續上一篇隨筆:https://www.cnblogs.com/kingstarer/p/12249028.html《工做碰上的技術問題及處理經驗》(四)html
我這人記憶力比較差,常常出現有些知識學了不久後就忘了,或者有些問題花了不少時間百度解決後,再過一段時間碰上時只有模糊印象,卻忘了具體解決方法。前端
最近幾年工做時我開始有意識地把登記天天工做碰上的技術問題作個簡單筆記。java
通常上班時間比較忙,只能草草記了一兩句話。等過一段時間,我會把這個筆記整理一下,把問題和處理經驗整理通順,以加深本身的印象。node
20190402: 今天碰上一個腳本文件編碼與系統編碼不符,致使sed運行報錯的問題。我腳本里面寫了一個命令sed -e 's/月份/月份 ${V_MONTH}/g' 執行時報錯"sed: -e expression #1, char 21: unterminated `s' command" 我在執行sed以前先執行set -x,打開腳本調試模式。看到輸出是sed -e "s/\324\302\267\335/\324\302\267\335 201904/g"。 這個輸出說明編碼是GBK,由於一箇中文佔了兩個字節。但我係統的LANG設置爲en_US.UTF-8。不相符,因此須要改一下。 20190407: 今天發現xargs命令作字符串處理仍是挺方便的,之前知道用它來跟管道組合處理參數太多超過命令行限制的狀況。這裏摘錄幾個用法: 替換字符串:echo "nameXnameXnameXname" | xargs -dX 多行輸入單行輸出:(echo a; echo b; echo c) | xargs 組裝shell命令:cat arg.txt | xargs -I {} ./sk.sh -p {} 20190408: 今天發現sourceinsight雙擊選中文字後會自動被修改,變成一個奇怪的問號圖標。開始覺得是我鍵盤有鍵被卡住了,挨個鍵檢查了一下,沒發現問題。 後來偶然發現原來我打開了金山詞霸,想起之前也看過網友吐槽,詞霸裏面的取詞和劃譯功能實現方法很粗暴,會不停往系統發快捷鍵消息。 因而嘗試把金山詞霸關了,果真好了。 20190409: 今天發現oracle的systimestamp類型是帶時區的timestamp,須要用cast(systimestamp as timestamp)轉換一下才變成不帶時區的。 今天用proc*c寫的程序導出數據庫表數據,發現有一些字段值是NULL,但我程序沒報錯。理論上proc若是不用指示變量,取出空的數據時會報錯的。 後來查查,發現原來我這個程序用proc*c預編譯時設置了UNSAFE_NULL=yes,因此沒報錯。 20190410: 今天發現oracle有一個語法insert all,能夠指定一條記錄同時插到兩個庫表: insert all into t1(c1) int t2(c2) select * from t; proc*c執行dml語句時支持預編譯一次,執行sql屢次。不過前提是要設置選項release_cursor=no(默認是no) 今天發現proc有一個參數:prefetch,指定sql語句句柄打開後預先從數據庫取出多少條記錄。這個參數默認是1,批量任務能夠考慮把它改大,有助於提升性能。 今天想用gcc的-Og選項編譯程序,發現竟然不支持。估計是我用的版本過低了。網上說-Og選項只會打開與-g不衝突的優化選項。 20190415: 今天發現cp有一個參數-p,複製時保留原文件的修改時間:cp -p old new shell清空文件的技巧 true命令: true > emptyfile 20190416: 用awk寫了一個輔助宏代碼對齊的腳本 # 輸入宏代碼,腳本會在每行後面補齊空格和\ awk -v v_tab_lenth=8 '{ # 首先讀取全部輸入行 計算全部輸入文本單行最大長度 v_arr_input[NR] = $0; v_str_len = length($0); v_arr_input_len[NR] = v_str_len; if (v_str_len > v_max_len) v_max_len = v_str_len; } END{ v_max_tab_cnt = int(v_max_len / v_tab_lenth) + 2; print "v_max_tab_cnt = "v_max_tab_cnt for (i = 1; i <= NR; ++i) { v_str_tab_cnt = int(v_arr_input_len[i] / v_tab_lenth); v_tab_cnt = v_max_tab_cnt - v_str_tab_cnt - 1; #if (v_str_tab_cnt * v_tab_lenth < v_arr_input_len[i]) v_tab_cnt = v_max_tab_cnt - v_str_tab_cnt - 1; #else v_tab_cnt = v_max_tab_cnt - v_str_tab_cnt; # print "v_tab_cnt = "v_tab_cnt, "v_str_tab_cnt = "v_str_tab_cnt, "v_arr_input_len[i] = " v_arr_input_len[i] printf("%s", v_arr_input[i]); for (j = 0; j < v_tab_cnt; ++j) printf("\t"); print("\\"); } }' tmp.txt 20190417: 今天發現一個函數fcloseall(_fcloseall),做用是把fopen打開的文件句柄全關了。 但我實際測試,發現fopen打開一個句柄fp,而後調用fcloseall,但這個fp句柄還能夠正常讀寫和關閉。 不過確實證實它有fflush的做用。 20190420: 今天發現proc查詢數據到char *類型縮主變量,竟然是經過strlen計算其空間大小。 這個設定好奇怪。在官方文檔裏面也提醒了調用者,須要用非'\0'字符填充空間。 proc執行rollback/commit會影響sqlca.sqlcode,因此若是須要這個值要先備份起來。 20190423: 今天建立一個分區表時發現oracle在建立表的速度比刪表的速度快不少。 建立語句雖然很長,但oracle通常在十幾毫秒內能完成,刪表語句很短,但執行要數秒鐘。 暫時不知道是什麼緣由致使的。 20190424: 今天覆習了oracle的savepoint語法: savepoint a; rollback to a; 今天我寫了一個函數,使用proc*c的數組批量操做技巧,一次插入N條記錄。 可是有一個問題沒解決,若是在插入過程當中數組裏面某些元素因爲數據異常插入失敗怎麼處理? 我暫時的解決方法是:插入前先使用savepoint創建一個保存點,若是插入失敗則回滾到該保存點。 不知道plsql裏面的forall命令是怎麼實現的使用forall批量插入數據時,若是某個數據插入出錯會忽略,繼續執行。 全部出錯記錄會存在sql%bulk_exceptions數組的。 20190428: 今天同事分享的一個問題:進行非功能測試,隨着時間增加,交易速度有明顯降低。 後來查了一下日誌,發現有一些sql執行耗時異常。經過分析sql執行計劃,發現sql沒走索引。 再進一步分析緣由,是由於庫表沒有及時作統計收集,oracle覺得是空表,原本應該走索引的,給走了全表掃描。 通常認爲,庫表記錄較小(小於100)或者查詢的數據量超過總數據的10%走全表掃描比走索引掃描快。(一次順序IO比屢次隨機IO快) 2190506: 今天花了點時間查了一個proc的問題: 執行update語句時沒找到記錄,sqlca.sqlcode返回1403,可是前面我用EXEC SQL WHENEVER SQLERROR DO指定的proc錯誤處理函數沒有被調用。 後來把.pc文件翻譯成.c文件看,才知道EXEC SQL WHENEVER SQLERROR DO指定的函數只有在sqlca.sqlcode < 0時纔會被調用。 今天還注意到一個oracle語法細節:select for update後面還能夠跟上of 字段,指定只鎖定記錄哪些字段。 select from hch for update of c1; 20190507: 查看正在運行程序環境變量的方法: strings /proc/${PID}/environ 20190508: 今天使用valgrind檢查程序內存使用狀況,發現有幾個出錯位置函數堆棧裏面沒有main,並且裏面都是一些oracle底層的函數。後來發現緣由是出錯位置函數調用層次太深,超過了默認值12。 我從新啓動valgrind,加上參數--num-callers=100,這樣就能顯示從main到出錯位置的全部函數。 20190509: 今天看到了這樣的代碼: if (bFlag) { EXEC SQL CONTEXT USE :ctx; } else { EXEC SQL CONTEXT USE DEFAULT; } EXEC SQL ...; 寫代碼人的本意根據bFlag的值決定使用不一樣數據庫鏈接執行sql,但這樣寫是有問題的,由於EXEC SQL CONTEXT並非一個語句。 它有點相似C語言的宏定義,在預編譯後根本不存在。(把.pc文件預編譯成.c後"EXEC SQL CONTEXT USE"這段代碼就是一段註釋) 他這樣寫代碼問題就跟用C語言這樣寫代碼同樣: #define SQL_CONTEXT_USE ctxDeault if (bFlag) { #undef SQL_CONTEXT_USE #define SQL_CONTEXT_USE ctx } else { #undef SQL_CONTEXT_USE #define SQL_CONTEXT_USE DEFAULT } EXEC_SQL(SQL_CONTEXT_USE); //不管bFlag的值是什麼,這裏都是用EXEC_SQL傳的值都是ctxDeault 正確寫法應該是這樣: if (bFlag) { EXEC SQL CONTEXT USE :ctx; EXEC SQL ...; } else { EXEC SQL CONTEXT USE DEFAULT; EXEC SQL ...; } 201900512: 今天一下網友分享一個案例:他用瀏覽器訪問某個網站時能正常獲取頁面信息,但用爬蟲訪問時卻獲取不到。 他已經修改了http請求頭,把agent改爲跟瀏覽器的同樣也不行。 後來他發現原來是訪問網站時服務器會返回一段js,瀏覽器執行那段js後才能正常生成頁面信息。他的爬蟲不支持js解析,因此出了錯。 201900513: oracle應用程序,有時會須要使用sysdate(或者序列號)修改庫表字段,但又想知道修改後的值是什麼。這時可使用returning into 子句,示例代碼以下: set lines 1000 pages 1000 set serveroutput on alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'; alter session set nls_timestamp_format='yyyy-mm-dd hh24:mi:ss.FF6'; alter session set nls_timestamp_tz_format='yyyy-mm-dd hh24:mi:ss.FF6 TZR'; drop table tab_hch; create table tab_hch(c1 date, c2 timestamp); declare v_dt date; v_dtmicro timestamp; BEGIN insert into tab_hch(c1, c2) values(sysdate, systimestamp) returning c1, c2 into v_dt, v_dtmicro; dbms_output.put_line('c1 = ' || v_dt); dbms_output.put_line('c2 = ' || v_dtmicro); -- 這裏輸出的時間就是新插入的記錄c2的值 END; / col c1 for a20 col c2 for a32 col c3 for a20 col c4 for a34 -- 比較c2與dbms_output.put_line的值,看是否一致 select c1, c2, sysdate c3, systimestamp c4 from tab_hch; 20190515: oracle 交換分區若是存在全局索引,會致使全局索引失效,能夠在交換分區時加上with update global index 20190529: sqlplus綁定變量用法: var v_hch number; exec :v_hch := 1; print :v_hch; select :v_hch from dual; 20190530: 今天碰上makefile裏面執行cd失效致使遞歸編譯的問題。事情是這樣的:有一個程序編譯時要求先到子目錄下面執行makefile編譯後,再回到當前目錄編譯。因而我寫了下面這個makefile。 prog: cd common make $@ cd .. make $@ 結果編譯時發現make被無限循環調用了,網上查了一下,要這樣寫cd common && make $@。原來每次執行一行命令後,makefile會從新回到當前工做目錄。因此我原來的makefile等於無限循環調用make編譯。 今天有網友問我他們系統有一個一個進程卡住,不知道是死循環了仍是在等待什麼條件,要怎麼辦。我建議他用pstack看一下堆棧,結合代碼分析程序的狀態。 20190531: 寫了一個awk腳本,用於把長行拆成多個短行,裏面考慮到了行尾單詞連續性問題: awk -v v_line_len=70 '{ v_str = $0; v_TotalLen = length(v_str); while(1) { v_str_sub = substr(v_str, 1, v_line_len); nLen = length(v_str_sub); if (nLen < v_line_len) { print v_str_sub; break; } nLen = v_line_len; v_ch = substr(v_str_sub, nLen, 1); # 若是結尾不是非字母或者數字,則一直往前找,直到找到第一個非字母或者數字的字符 # 若是找了20個還找不到,則放棄 這樣作是爲了不行尾的單詞被一分爲二 while ((v_ch == ":") || (v_ch >= "a" && v_ch <= "z") || (v_ch >= "A" && v_ch <= "Z") || (v_ch >= "0" && v_ch <= "9")) { --nLen; v_ch = substr(v_str_sub, nLen, 1); if (nLen <= v_line_len - 20) { nLen = v_line_len; break; } } v_str_sub = substr(v_str, 1, nLen); print v_str_sub; v_str = substr(v_str, nLen + 1); } }' 20190603: 今天學習了makefile一個特殊變量:MAKECMDGOALS 這個變量記錄了命令行參數指定的終極目標列表。 舉例:執行make debug命令,MAKECMDGOALS的值是debug。在遞歸腳本里面這個參數頗有用。 make還有其它幾個特殊變量,分別表明當前目錄,makefile名稱,make版本等 20190604: 今天碰到一個狀況:df顯示磁盤空間還剩不少,但用cp命令拷貝生成新文件時提示no space left on device。 上網查了一下,說多是磁盤inodes空間滿了,用df -i能夠查看。 我試了一下,果真如此。用df能夠看出inodes空間佔用 100%。cd到懷疑有大量文件的目錄下,ls時卡住了,沒法定位是什麼文件致使的。 沒辦法最後只能把目錄刪了重建。 20190605: oracle寫sql時若是須要指定轉義字符(k逃逸字符),可使用escape關鍵字。例如: select owner, table_name from all_tables where table_name like '%\_17_\_%' escape '\'; -- 找出全部以包含"_17?_"的表名,?表明一個任意字符 fuser能夠查看文件被哪些進程打開 ${0}:${LINENO} shell輸出日誌加上這個前綴,能夠更方便定位 bash裏面還可使用${FUNCNAME[0]}輸出當前函數名稱 一個日誌輸出函數示例: logerr() { echo "error at ${BASH_LINENO[1]}${FUNCNAME[1]} $*" } 20190613: 因爲oracle的索引是不記錄NUUL值記錄,因此惟一索引列是能夠存在多個爲NULL的記錄的 另外,oracle的NULL和空串''是等價的 20190614: 寫了一個方便查看文件數據的awk腳本(讀取行,拆成多列顯示) awk -F '\\|@\\|' '{ printf("%s:%d\n", FILENAME, FNR); for (i = 1; i <= NF; ++i) { printf("% 4d:%s\n", i, $i); } getline < "-"; }' 20190616: 一個web請求可能須要通過的cdn,dns負載均衡,f5負載均衡,nginx反向代理,消息隊列,redis,數據庫(讀寫分離,集羣),文件緩衝等這麼多種緩存機制 20190620: 使用static變量時,記得注意變量之間關連關係。我此次就踩了坑: 我在程序裏面使用了兩個static變量s_this_date緩存當前時間,s_next_date緩存s_this_date的下一天。 爲減小計算時間消耗,只有當s_this_date變化時,纔會計算s_next_date。 但代碼裏面有個問題,存在修改了s_this_date後,在s_next_date修改前函數就退出的狀況。 這樣就致使s_next_date有時跟s_this_date不是差一天的關係。 20190630: select for update是上鎖,不是檢查有沒有鎖 20190701: 今天使用了merge語句幫同事優化了一個語句: update tab_check_task t set Mcht_Name=(select Mcht_Name from tab_mcho_sre where mcht_no=t.mrch_id ); 13分鐘沒跑完 merge into tab_check_task t using tab_mcho_sre mcht on (mcht.mcht_no=t.mrch_id) when matched then update set t.Mcht_Name = mcht.Mcht_Name; 4分鐘跑完 今天一個同事說他在.bash_profile配置了兩個環境變量,但從新登陸後只有其中一個生效了,問我怎麼回事。 我建議他執行sh -x .bash_profile,看是哪裏出錯了。他執行後很快回復我,是.bash_profile後面加載了另外一個腳本,那個腳本里面有同名變量,相互覆蓋了。 sh -x 是調試shell的利器。‘ 20190704: 今天發現time命令和\time調用的是不一樣的程序,\time調用的是/usr/bin下面的time程序,而time則是調用shell內置的功能 今天看到一個調試一個release程序的方法: 先使用-g從新編譯一次程序,而後取出變量信息 objcopy --only-keep-debug projedtd projedtsymbol.dbg 再使用這些變量信息去調試release程序 gdb -q symbol=projedtsymbol.dbg --exec=projectr x /10x $sp # gdb查看當前程序棧的內容: 打印stack的前10個元素 20190705: 調試內存問題時,能夠設置環境變量 export MALLOC_CHECK_=3 這樣程序在發現內存異常時會打印出錯信息並退出 20190712: 今天來上班,發現昨天晚上掛的一個crontab任務沒啓動。一開始沒想明白是什麼緣由,覺得是任務腳本有問題,查半天沒查出來。 後來在同事建議下,我試了加了一個簡單的crontab任務,設置成1分鐘後跑,發現也沒啓動。這才肯定原來是crontab服務沒啓動,可使用如下命令確認: service crond status 20190715: proc調用存儲過程,出參,也要初始化,否則使用valgrind檢查時會提示未初始化的內存。 20190716: 今天使用vallgrind檢測程序時,出現不少內存泄漏提示。 但其實我確認代碼沒寫錯,後來查了一下,是由於使用了glib的一些數據結構,裏面使用了內存池。 而且查到了,若是設置環境變量G_SLICE=always-malloc這樣就不會啓動glib內存池。 20190717: 今天看代碼時發現一段邏輯,須要判斷一張數據庫表有沒有記錄,裏面直接用了select count(*) from tab檢查,其實可使用 select count(*) from tab where rownum < 2,由於要檢查有沒有記錄,只要有一條記錄就能夠判斷,不須要全表掃一次。 20190718: 從csdn上保存的博文,在沒有連公網時打開,老是過一會就自動重定向到csdn.net,很煩人。雖然知道確定是某段js搞鬼,但一直沒搞清楚是哪段。 今天發現用谷歌瀏覽器按f12能夠單步調試網頁,利用這功能終於定位到了「元兇」。 <img src="https://blog.csdn.net/chuxuan909/article/details/72465748?utm_source=blogxgwz0" onerror="setTimeout(function() {if(!/(csdn.net|iteye.com|baiducontent.com|googleusercontent.com|360webcache.com|sogoucdn.com|bingj.com|baidu.com)$/. test(window.location.hostname)) {window.location.href="\x68\x74\x74\x70\x73\x3a\x2f\x2f\x77\x77\x77\x2e\x63\x73\x64\x6e\x2e\x6e\x65\x74"}},3000); "> 把onerror批量替換成onerror1便可。這段代碼裏"\x68\x74\x74\x70\x73\x3a\x2f\x2f\x77\x77\x77\x2e\x63\x73\x64\x6e\x2e\x6e\x65\x74" 其實就是https://www.csdn.net 20190719: kafka閱讀心得: 觀察髒頁 cat /proc/vmstat | egrep 'dirty|writeback' 啓動g1垃圾回收器 export KAFKA_JVM_PERFORMANCE_OPTS='-server -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:+DisableExplicitGC -Djava.awt.headless=true" kafka-server-start.sh -daemon server.propertities 20190724: proc對匿名結構體支持不大好,建議儘可能使用typedef struct __StuName_t{}StuName_t;代替typedef struct {}StuName_t; 20190725: sqlldr加快裝載速度的參數設置建議: sqlldr errors=9999999 control=tab.ctl log=tmp.txt sreamsize=256000 bindsize=2560000 userid=stlm_o/stlm_o@RCC8TPD2 direct=TRUE rows=1000 20190726: 今天發現有一些商家使用退貨交易套利: 第一天先作了一大筆消費,次日一開門就作了退貨交易。因爲這時商戶資金不足,爲了避免影響用戶體驗,咱們系統會先墊錢給用戶,後面再從商戶的帳戶扣錢。 但有一些不法商戶跟消費者合做,退款後當即註銷商戶,致使系統出現短款。 爲了解決這個問題,咱們緊急作了一個白名單功能,不在白名單的商戶,當日營業額不足時不容許退貨。(這種狀況商家必定要退貨時,須要本身先作一筆大額消費) 20190731: 今天過來發現crontab任務沒啓動(檢查crontab任務重定向輸出的日誌,發現不存在)。檢查一下,發現由於是硬盤沒空間了。這才知道原來硬盤滿了會致使crontab調度異常。 20190801: 今天才發現df出來的size != used + free,查了一下,說緣由有兩個1 inode節點空間佔用了一些磁盤空間,2 系統會佔用一些預留空間,以便出現磁盤空間滿時止root用戶登陸處理(通常是0.05 * size)。不過個人系統加上這兩項空間,仍是差一些,不知道是否是還有其它隱藏的佔用空間狀況。 20190810: 這段時間都在研究kafka,kafka其實就是一個分佈式消息隊列中間件,主要用於吞吐量高(號稱每秒十萬寫,百萬讀),但業務邏輯簡單(如數據同步,通知)的場景。 kafka藉助zookeeper實現了集羣,高可用特性,自己又支持多副本功能,集羣少許機器出現故障時仍可正常使用。但kafka的消息一致性比較差,容易出現消息丟失或者重複消息的狀況。 kafka支持多個不一樣客戶端訂閱同一個消息主題,這樣能夠作到一份消息多個場景使用,這點對於數據分析特別有利。另外,kafak的消息都是落盤存儲的,因此生產者跟消費者耦合很是低,能夠分別獨立部署運行。 20190812: 這幾天用glib寫了一個多線程的程序,連接時報g_thread_init函數未定義(undefined reference to `g_thread_init'),但奇怪的是我明明有libglib-2.0.a,原來網上查了一下,原來是要額外連接libgthread-2.0.a cout從右到左計算,從左到右輸出 lsof -u username # 列出用戶全部打開的文件 20190814: 今天編譯libcjson.a,發現默認的編譯選項是沒有開啓-O2的,不知道爲何。我把它改了一下,增長-O2選項,發現只快了一點。 跑10萬次cJSON_test,耗時從1.15s降到0.97。又測試了5000000次的,發現分別耗時是55秒和45秒。仍是有點效果的,但效果不明顯,先使用默認的吧。 今天又出現某個bug增長打印日誌 就不出現,不加就出現的狀況。後來仔細看代碼,是由於我有兩個不一樣文件,同時聲明瞭一個全局變量(名字同樣),其中一個有初始化,一個未初始化,致使兩個變量連接時被合併成一個,從而互相影響。 20190815: 今天發生一個事情,因爲溝通問題,我跟同事改了同一個word文件,只能想辦法跟他的合併。網上找了一下,說word的審閱選項卡下面有比較功能。 試了一下,確實是能夠,但不是很直觀。後來經同事提醒,原來svn自帶啓動word比較功能。 20190820: 今天發現ue有一個好用的快捷鍵F5,做用是把大寫數據庫列名轉成駝峯式的大小寫混合的單詞。例如THIS_IS_A_TEST會被變成This_Is_A_Test 20190821: 小知識點:free命令輸出的內存使用信息裏面used並不表明真正可用內存,可用內存是free + buffer + cached之和 20190822: extern int g_lib_flag = 0; //連接時報錯 extern不能增長初始化 20190823: 今天生產系統發現有一些交易存在衝正交易比正交易先到,致使對帳不平的狀況。 出現bug的主要緣由是咱們接到衝正請求時發現數據庫沒有正交易,直接就返回前端衝正失敗(交易不存在),但沒有登記流水。後面正交易過來時咱們當普通交易正常處理了。但前端系統不知道,因此沒有重複發起衝正請求。 暫時要求前端嚴格控制順序發送交易,之後再出現須要考慮一些機制避免這種差別。 20190904: 這兩天使用Loadrunner對程序進行壓測,壓測過程當中常常提示壓力機cpu使用率超過80%的提示。開始時我沒怎麼在乎,想着不是目標機80%,壓力機沒到100%應該沒事。 後來偶然把測試腳本改一下,壓力機cpu消耗下來,發現目標機tps竟然有明顯升高。 看來之後要注意一下。 oracle默認刪除表後不會清除空間,而是放到回收站。若是要強制收回這些空間,可使用select * from user_recyclebin;查出表名,而後使用 purge table "表名"; 20190914: 今天發現一個bug: 咱們一個程序在執行數據庫查詢過程當中,收到信號,轉去執行中斷處理函數。 結果函數裏面也有數據庫查詢操做,致使死鎖了。(proc的api對於這種狀況沒處理好) 臨時解決方法是在數據庫操做期間先屏蔽了信號,不過這樣可能致使信號漏處理,之後須要優化。 20191030: 以前對日誌組件作了優化,使用本身寫的帶緩存的localTimeCache代替localTime,減小鎖競爭。 今天寫了一個測試,發如今高頻調用下時,有時會出現跟localTime的秒數有差別的狀況,代碼以下: while (1) { int *pSecCache = &localTimeCache(&time)->tm_sec; int *pSec = &localTime(&time)->tm_sec; LogInfo("cache %d", *pSecCache); LogInfo(" nocache %d\n", *pSec); } 後來仔細分析,原來LogInfo裏面也會調用localTimeCache,致使pSecCache的值發生了變化。對於這種靜態變量使用,須要多注意。 今天又碰上一個進程由於信號處理函數出bug的狀況:在調用system函數時接到信號,轉到信號處理函數時又調用了system,致使死鎖。 20191030: proc查詢數據庫數據到char數組時,若是目標數組空間不足,則會截斷(但仍是會以\0會結尾)。 若是數組空間比數據庫字段長度長,則剩下的空間會以空格填充。 20191114: void func(char * const arr[]) 只讀字符串數組 strcpy(arr[0], "123"); //ok arr[0] = "123"; // not ok 20191125: oracle 在線壓縮分區的方法: 1 完美方法 使用12 c的move online功能 2 變通方法a 先將要壓縮的分區數據導出來到臨時表並壓縮 把臨時表的數據跟待壓縮分區作在線交換(要加上with update indexes) 從臨時表裏面找操做期間變動的記錄,更新回壓縮分區 3 變通方法b(壓縮分區不須要查詢的狀況) 建一個空表 把分區的數據跟空表交換 對錶作壓縮 20191126: oracle作分區交換時,可使用including indexes,在作交換分區時順便維護local索引 float類型的變量在計算時很容易損失精度:0.1循環加8次 > 0.8 double也會,但比float損失精度的機率會低一些。 20191127: 今天出現一個問題:我在程序裏面一個sql使用了hint:result_cache想提升查詢速度,單進程測試時發現確實有明顯改善。 但到生產機器時,多進程環境跑的時候卻致使了大量lanth free事件,反而拖慢了速度。後來dba臨時關閉了result_cache功能才恢復。 20191204: 進程數估計 機器cpu跑滿 看是否有堵塞 交易太頻繁,沒有發心跳 mq recv 20191205: oracle使用merge into有時也會由於主鍵衝突失敗,主要是出如今高併發插入的場景。 20191206: watch命令特別方便監測進程運行狀況:執行 watch 'ps aux www|grep -w -E "ProgName|TTY"' 系統會顯示進程資源佔用狀況,而且自動每2秒刷新 20191207: 今天使用valgrind檢測程序時,發現好多invalid write。仔細檢查,發現是由於 strptime函數沒有填充目標變量的夏令時字段,致使這個字段是未知字節。而後我又拷貝了這個變量的值,就出現這個問題。 解決方法是strptime函數執行後再設置tm_isdst爲0 20191208: 今天發現c++的throw比較消耗資源,即便沒觸發throw部分代碼。 我寫了兩個程序,代碼是同樣的,只是一個加了try catch,另外一個沒有加。 編譯後運行,發現效率相差20% 20191210: 今天使用callgrind檢測程序性能時,發現我有一個函數雖然有調用,可是在callgrind輸出結果卻看不到實際調用狀況。 後來通過屢次測試,發現原來是這個程序被編譯器自動內聯了。雖然我沒有指定inline,也沒有加-O,但編譯器仍是將它內聯了。 兩個靜態庫的函數互相調用,會致使連接時不管怎麼調整順序,都有可能報「找不到對象」,這時能夠多連接幾回: 例如我有libA.a libB.a相互調用了,寫makefile時可這樣:-lA -lB -lA -lB。不過這只是臨時處理方案,實際上不該該出現這樣的相互調用的狀況。 linux消息隊列好像沒有支持io多路複用的api,我設想了一個解決方案: 啓動一個專門的讀線程,使用阻塞讀消息隊列,若是讀到了消息,則發送一個信號給主進程監聽的句柄(例如匿名管道) 20191211: 最後生產數據庫空間告警,只能把一些不經常使用的流水錶作壓縮,以節省空間。幸虧oracle提供了壓縮表的功能。 20191212: 最近半年作了一個查詢庫同步的功能,過程仍是很折騰的: 最開始打算直接使用goldengate同上交易庫的表和查詢庫的表,這是最方便的。 可是運維團隊說沒有購買這個工具,並且有安全問題。因而只能做罷。 後來又想着在業務庫表加上觸發器,把修改內容登記到一個日誌表,再寫一個程序根據日誌表同步數據到查詢庫。 但運維團隊又說不能加觸發器,由於觸發器影響性能。 以後有同事提出使用物化視圖,但我查了一下網上,oracle的物化視圖功能bug不少,沒建議。 最後偶然間,我查proc開發文件時發現oracle提供了一種returning into的語法,能夠返回update/insert修改後記錄的內容。 因而最後決定: 1 而且給業務表增長修改時間字段,insert或update時順便更新這個字段。 2 在全部修改數據庫流水錶的代碼增長returning into子句,把修改結果查詢回來。 3 把返回的記錄發給同步進程,同步進程把記錄merge到查詢庫的表 4 爲防止順序錯亂,同步查詢庫時須要加上判斷,若是修改時間比數據庫記錄的時間早,則不處理 20191216: 文件編碼不是文件的屬性之一,這是不少人沒搞清楚的。他們每每會說「我文件已經保存成gbk編碼,爲何傳到linux上打開仍是亂碼」 其實問題就是文件編碼不是文件的屬性,linux上的文件工具打開文件時只能「猜想」文件的編碼,若是它猜錯了,顯示就是亂碼。 20191217: 邏輯尺:一個字段,其中的各個位,由咱們本身規定爲0、1。 而後,用這一串0、1,依次去選擇兩種操做。 這個字節,每每有人稱之爲邏輯尺。 20191218: 今天用proc編譯.pc文件時出現core,看緣由是段錯誤。 後來檢查一下,是因爲文件路徑太長,超過100個字符,觸發proc的bug 20191219: vim顯示不了回車符解決方法:vi -b vim輸入回車符方法:按住ctrl,再按v,再鬆開v按m 20191220: 今天使用loadrunner壓測的過程當中,報了很多"server has shut down the connection"的錯誤 觀察被壓測機器的接入程序,卻沒有發現異常。 猜想是因爲客戶端機TIME_WAIT太多形成的,不過修改後也沒多大改善。具體緣由暫時還不知道 20191223: Disql是DM數據庫自帶的數據庫命令行客戶端工具。相似於sqlplus,不過作得不太好。 今天隨便試用了一下,就發現一個bug:進入disql後,若是不執行sql,直接按ctrl + c,會致使程序退出 20191225: %08s,不是用0左補齊,而是用空格 20191226: oracle在多個會話查詢同一條記錄,容易出現LanchFree競爭事件 20191227: 今天作非功能測試,發現有一個交易跑一會tps就急劇降低。一開始我覺得受清理日誌影響,但後來把日誌清理停了也同樣。 觀察vmstat輸出,tps降低時cpu使用wait的數據急劇上升,而且so也上升。猜想是因爲內存換頁影響。使用ps aux www觀察,發現進程佔用的內存大漲。 iostat -x 2 5 # 每隔2秒打印io信息 共5次 20191228: gdb打開core文件,使用where發現堆棧異常,有一些函數根本不可能調用到,但卻顯示在輸出裏面。 後來發現core文件生成時間比程序的修改時間還早,說明程序被修改過。後來我找了修改前的程序,從新用gdb調試,這裏where輸出就正常了。 20191230: 今天啓動業務系統時出現有一些進程打開監聽端口時失敗,重啓時就行了。 仔細分析日誌,發現問題是某些進程使用的隨機端口正好與監聽端口衝突了。 20191231: 今天壓測時,發現tps忽然降低。看vmstat,bi忽然增長,wa增長。查看free,發現buffer忽然減小,原來是有進程佔用了太多內存致使的。 20200106: 今天作非功能測試時,發現數據庫不少"cursor: pin S wait on X"的等待事件。 百度查了一下,出現這個等待事件的緣由不少,其中一個比較常見的狀況是數據庫硬解析sql太多。 但咱們系統高併發的sql都是使用綁定變量的,理論上不該該出現不少硬解析。因此當時認爲不是這個問題。(其實當時應該檢查一下硬解析次數再下結論) 後來偶然間發現有一些20年的流水錶沒建,致使sql執行時出現"table or veiw not exist"的錯誤,這才明白過來爲何會有不少硬解析。 後來把表建好後再跑就沒這個等待事件了。 20200107: 看網上的實驗說是rac切換時,該節點沒提交事務會自動回滾 若是應用此時不進行rollback操做,再執行其餘語句(包括commit)都會報ora-25402 20200108: loadrunner參數取隨機值設置方法: Select next row: Random Update Value On: Each iteration 20200109: 查看系統在監聽的端口和對應程序名:netstat -anp|grep LIS 20200110: 數據庫緩慢,執行 set linesize 240 col sid format 9999 col s# format 99999 col username format a15 col event format a30 col machine format a20 col p123 format a18 col wt format 999 col SQL_ID for a18 alter session set cursor_sharing=force; SELECT S.SID, S.SERIAL# S#, P.SPID, NVL(S.USERNAME, SUBSTR(P.PROGRAM, LENGTH(P.PROGRAM) - 6)) USERNAME, S.MACHINE, S.EVENT, S.P1 || '/' || S.P2 || '/' || S.P3 P123, S.WAIT_TIME WT, NVL(SQL_ID, S.PREV_SQL_ID) SQL_ID FROM V$PROCESS P, V$SESSION S WHERE P.ADDR = S.PADDR AND S.STATUS = 'ACTIVE' AND P.BACKGROUND IS NULL; 等待事件sga:allocation forcing component growth 20200217: 今天安裝redis時發現一些語法比較奇怪的腳本,上網查了一下,原來是tcl腳本 百度了一下,介紹這樣的:「Tcl 是一種 腳本語言。 由John Ousterhout建立。 TCL很好學,功能很強大。TCL常常被用於 快速原型開發,腳本編程, GUI和測試等方面。」,TCL念做「踢叩」 "tickle" 之後有機會要了解一下 20200220: make install時能夠臨時指定安裝目錄,make PREFIX=/home/huangcihui/local install 20200225: 今天測試redis性能時偶然發現redis服務設置了密碼,但運行redis-benchmark時沒輸入密碼參數結果也能跑成功。 後來研究了一下代碼才發現,redis-benchmark工具默認對返回結果不作檢查,須要加上-e參數,纔會檢查redis命令執行結果是否成功。 20200228: 今天發如今高併發狀況下,oracle的merge語句也可能會出現主鍵衝突。以前在低併發狀況時一直用merge一次完成INSERT+UPDATE,避免主鍵衝突。 20200229: 今天同事反映,生產上有一些交易被拒絕,報20200229日期非法。但今年是閏年,理論上不該該出現這個問題,並且奇怪的是否是全部交易都被拒絕。後來查了一下代碼,裏面有這樣的代碼: char year[5]; strcpy(year, dateTime, 4); if (IsLeap(atoi(year)) { ... } 因而明白了,程序裏面對於year沒有作初始化,致使有時atoi結果出現異常,致使程序判斷閏年錯誤。 20200302: ps aux www|grep -E 'TTY|redis',這樣能夠保留ps輸出的標題 201200303: 當你使用sudo去執行一個程序時,處於安全的考慮,這個程序將在一個新的、最小化的環境中執行,也就是說,諸如PATH這樣的環境變量,在sudo命令下已經被重置成默認狀態了。 要想改變PATH在sudo會話中的初始值,用文本編輯器打開/etc/sudoers文件,找到」secure_path」一行,當你執行sudo 命令時,」secure_path」中包含的路徑將被當作默認PATH變量使用。 sudo -v 延長密碼有效期限5分鐘,這樣就能夠臨時省去sudo輸入密碼的麻煩 20200304: redhat的屏保竟然是向上拖動的,不是像windows同樣點擊自動消失的。 開機後等很久一直停留在時間界面,點了沒反應,我一直覺得開機沒完成。。。 20200305: 新安裝的redhat默認啓動是進入圖形界面,能夠執行命令 systemctl set-default multi-user.target,這樣重啓後優先進入命令行界面 若是之後須要恢復回來,則執行systemctl set-default graphical.target便可 臨時命令行切換至桌面命令: init 5 臨時桌面切換至命令行命令: init 3 20200308: redhat配置網卡自動鏈接,並使用dhcp配置網絡地址方法: 須要修改配置/etc/sysconfig/network-scripts/ifcfg-<網卡名稱> 假設網卡名字叫eth0,則修改/etc/sysconfig/network-scripts/ifcfg-eth0 將BOOTPROTO改成dhcp,ONBOOT改成yes 修改後使用ifup eth0啓動鏈接