您好,登錄后才能下訂單哦!
1.問題背景
對于分布式數據庫和分布式環境,高并發和高性能壓力的情況下,出現線程創建失敗等等問題也是十分常見的,這時候就十分考慮數據庫管理員的經驗,需要能快速的定位到問題和瓶頸所在,快速解決。本文也是作為一個最佳實踐,告訴大家如何在高并發情況下定位問題,排除問題,解決瓶頸。
2.問題定位
SequoiaDB在集群環境中的 -10 錯誤碼,在認真查閱節點的 diaglog 日志后,發現是操作系統 create thread 失敗的問題。
如我們的測試環境下,SequoiaDB節點的 diaglog 的錯誤日志信息
閱讀這個錯誤日志的內容,通過看到類似如下的關鍵信息
Failed to create new agent: boost::thread_resource_error: Resource temporaily unavailable
Failed to create new agent, probe = 30
Failed to create subagent thread, rc = -10
Failed to start session EDU, rc = -10
那么一般操作系統在創建線程時,會受限于哪些參數呢,主要有幾個:文件句柄數限制、操作系統句柄數限制和內存資源。
1)文件句柄數
在linux 操作系統中,號稱一切皆為文件,無論是進程、線程、socker 還是其他,最終都會被操作系統歸為文件操作。操作系統或者進程,每申請一個資源,例如線程、socker,都會打開一個文件,那么這個文件打開狀態,就可以簡單理解為文件句柄。其中,“句柄數限制“代表操作系統或者某個進程所能夠打開的最多文件的數量的限制。
大家有了這個概念后,我們再來看操作系統是如何對文件句柄數進行限制的。在操作系統中,有一個神奇的命令 - ulimit 這一個命令可以設置許多限制值,進程文件句柄數就是其中之一。
例如我們可以查看 root 用戶的 ulimit 輸出, -n open file = 1024 就是root 用戶允許進程打開的最大文件句柄數。
此處我們需要注意,由于root 用戶是Linux 中的管理員用戶,所以如果root 用戶的 ulimit open file 設置成 1024, 那么其他的用戶,例如test、mysql 用戶等,想將 ulimit opon file 設置成 大于 1024,是不行的。
因此,普通用戶的 ulimit 值修改前,必須要注意root用戶的ulimit值,保證普通用戶的ulimit值比root用戶的設置值小。
2)操作系統句柄數
除了進程中的句柄數限制,整個操作系統的句柄數限制同樣會對數據庫運行產生影響。在句柄數限制下,因為一個操作系統,總不能無限地打開句柄的。所以又引入另外一個設置,操作系統最大打開的句柄數限制。
這個值在 centos 7 中,是被保存在 /proc/sys/fs/file-max 文件中。
如果操作系統總的句柄數已經達到上限,那么即使進程還沒有啟動幾個線程,也會出現句柄不夠的情況。
如果希望臨時修改操作系統最大句柄數的設置,可以直接執行,即可: echo 2000000 > /proc/sys/fs/file-max
如果希望永久修改操作系統最大句柄數的設置,可以編輯 /etc/sysctl.conf 文件,增加 fs.file-max = 2000000 內容,然后在root 用戶中執行 sysctl -p 即可。
3)內存資源
針對內存資源的優化,在創建線程時,在Linux 中,是需要給它預先分配內存的 – 也叫 棧大小,用來存儲線程中數據的值。
我們程序員都知道,內存主要分為兩個大的部分,一個稱為 “堆”,一個稱為“棧”。在程序中,“堆”通常是程序用來保存常量和變量名字的,“棧”則通常是程序來用保存具體的變量數字的。
此前我們說到,如果系統內存不足,也是無法創建線程的。這個原因就是在于創建線程時,操作系統需要分配一塊內存給線程,這個內存是多大呢,就是 ulimit 中 -s stack size 的大小。如果操作系統連 stack size 大小的內容都無法拿出來了,創建線程就會失敗。
整個服務器資源,為什么這么一點內存都沒有了?
其實如果仔細查看操作系統,你就會發現,那么多進程,每個進程又是那么多線程在運行,每個線程都在申請內存(注意,這塊的內存是物理內存),內存不足正常的很。這個也容易讓人聯想到JVM 的OOM ,但是他們真的不是一回事,大家千萬不要誤會。
要解決這個問題也比較簡單 – 直接粗暴?就是將 ulimit 中 -s stack size 調小一點,每個線程不要申請那么多內存了,操作系統的內存資源就會更加的充裕。畢竟程序、線程這些,都是用完就完了,不可能都永久占用內存的。
3.其他需要注意的點
除了上述解決方案,仍無法解決創建線程失敗的額問題
執行 ulimit -a 命令,參數看起來也正常,但是系統是否是完成了設置?我們需要真正確認SequoiaDB進程的ulimit 參數是啥。
確認的方式有兩種:
? 在sdb的較新版本中,節點啟動時的diaglog 日志,會打印它自己的 ulimit 參數,讀者可以去翻翻日志
? 另外一種就更加直接,直接查看 linux 的系統記錄。例如知道 11910 進程的 PID 是 123456,就直接打開 /proc/123456/limits 文件,查看里面的內容,這樣想不知道,都難
4.備注:關于句柄數和線程的命令
查看 某個進程總共開啟了多少個 線程,可以
cat /proc/$PID/status | grep Threads
pstree -p $PID ,然后+1,因為還有主進程
top -Hp $PID,然后查看頭部 “Threads”參數
ps hH p $PID | wc -l
查看linux 目前總打開的句柄數
lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|awk '{print $1}' | awk '{sum += $1};END {print sum}'
查看某個進程打開的總句柄數
lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr | grep $PID
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。