1.問題背景mysql
對於分佈式數據庫和分佈式環境,高併發和高性能壓力的狀況下,出現線程建立失敗等等問題也是十分常見的,這時候就十分考慮數據庫管理員的經驗,須要能快速的定位到問題和瓶頸所在,快速解決。本文也是做爲一個最佳實踐,告訴你們如何在高併發狀況下定位問題,排除問題,解決瓶頸。linux
2.問題定位程序員
SequoiaDB在集羣環境中的 -10 錯誤碼,在認真查閱節點的 diaglog 日誌後,發現是操做系統 create thread 失敗的問題。sql
如咱們的測試環境下,SequoiaDB節點的 diaglog 的錯誤日誌信息數據庫
閱讀這個錯誤日誌的內容,經過看到相似以下的關鍵信息centos
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服務器
那麼通常操做系統在建立線程時,會受限於哪些參數呢,主要有幾個:文件句柄數限制、操做系統句柄數限制和內存資源。session
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 參數是啥。
確認的方式有兩種:
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