1. 程式人生 > >Linux隨機數發生器導致Apache程序全部Block的問題

Linux隨機數發生器導致Apache程序全部Block的問題

今天上午,運營同事報告一個嚴重故障,現象是網站頁面速度非常慢,基本不可用。工程師開始追查問題。

首先介紹一下系統架構:前端 Apache,中間PHP,後端MySQL,經典的LAMP架構。

猜測資料庫出現效能問題

第一反應,懷疑資料庫資料量太大。我們一直定期清理資料庫,保證單表資料量在一定範圍內。而這段時間一直沒有清理,資料量可能過大。立刻執行delete語句,單表減少100W條記錄。但是,問題依舊。

後來,DBA同學發現慢查詢,存在filesort。果斷增加索引,慢查詢消失。但是,問題依舊。

無奈之下,懷疑機房網路問題。但是其他產品線都沒有問題,網路組也沒有故障通報。因此,否決這種可能。

線下環境復現故障

時間已經到了下午5點,決定重新梳理思路,反覆觀察故障現象。總結幾點:

  • 頁面響應速度不穩定,或慢或快,或稍慢,或奇慢,缺少一種規律性
  • 甚至,在一位同事的電腦上,重新整理幾次都很快。

由於沒有許可權看線上日誌(其實程式碼中也沒有打任何日誌),無法從日誌中獲取有效資訊。為了方便除錯,我們決定線上下環境部署程式碼並嘗試復現故障。

結果,線下環境中,故障基本必現。可以肯定,與網路環境沒有關係,與線上的memcahced/mysql的執行狀況也沒有關係。

我們在PHP程式碼的不同位置插入除錯程式碼 echo ‘xxx’;exit;  , 試圖確定何處程式碼在堵塞。

我們驚奇的發現,當一個頁面處於等待響應的狀態時,後續頁面必然也在等待。而且,後續頁面沒有執行任何PHP程式碼。我們推斷,Aapache程序block住了!

Strace Apache程序

為了搞清楚Apache程序block在什麼地方,我們使用strace工具觀察Apache程序的系統呼叫。

先找出Apache的程序號。

Shell程式碼  收藏程式碼
  1. [[email protected] ~]# ps aux|grep httpd  
  2. root      3553  0.0  2.6 312672 13476 ?        Ss   Aug03   0:03 /usr/local/apache2/sbin/httpd -k restart  
  3. www       4759  0.0  4.4 320664 22584 ?        S    20
    :31   0:00 /usr/local/apache2/sbin/httpd -k restart  
  4. www       4760  0.0  3.2 316548 16672 ?        S    20:31   0:00 /usr/local/apache2/sbin/httpd -k restart  
  5. www       4761  0.0  3.2 316548 16672 ?        S    20:31   0:00 /usr/local/apache2/sbin/httpd -k restart  
  6. www       4762  0.0  3.2 316548 16672 ?        S    20:31   0:00 /usr/local/apache2/sbin/httpd -k restart  
  7. www       4763  0.1  4.9 319552 25036 ?        S    20:31   0:00 /usr/local/apache2/sbin/httpd -k restart  
  8. www       4766  0.0  3.2 316548 16672 ?        S    20:32   0:00 /usr/local/apache2/sbin/httpd -k restart  
  9. root      4890  0.0  0.1  61188   732 pts/3    R+   20:35   0:00 grep httpd  
  10. www      30809  0.0  6.0 327304 30772 ?        T    16:43   0:01 /usr/local/apache2/sbin/httpd -k restart  

然後,隨便挑一個程序號,strace上去:strace -p 4759

接著,反覆重新整理頁面,總有一個請求會落到PID為4759的程序上。

終於,一個請求過來,快速刷屏,戛然而止,輸出內容定格在:

Shell程式碼  收藏程式碼
  1. connect(107, {sa_family=AF_INET, sin_port=htons(7634), sin_addr=inet_addr("10.73.19.246")}, 16) = -1 EINPROGRESS (Operation now in progress)  
  2. poll([{fd=107, events=POLLOUT}], 11000) = 1 ([{fd=107, revents=POLLOUT}])  
  3. connect(107, {sa_family=AF_INET, sin_port=htons(7634), sin_addr=inet_addr("10.73.19.246")}, 16) = 0  
  4. write(107"get APPS_SCREEN_API_CURR_TOKEN \r"..., 33) = 33  
  5. read(1070x14130e488196)             = -1 EAGAIN (Resource temporarily unavailable)  
  6. poll([{fd=107, events=POLLIN}], 1200) = 1 ([{fd=107, revents=POLLIN}])  
  7. read(107"VALUE APPS_SCREEN_API_CURR_TOKEN"..., 8196) = 107  
  8. write(107"quit\r\n"6)               = 6  
  9. read(1070x14130e488196)             = -1 EAGAIN (Resource temporarily unavailable)  
  10. poll([{fd=107, events=POLLIN}], 1200) = 1 ([{fd=107, revents=POLLIN}])  
  11. read(107""8196)                     = 0  
  12. shutdown(1072 /* send and receive */) = 0  
  13. close(107)                              = 0  
  14. open("/dev/random", O_RDONLY)           = 107  
  15. read(107,  

注意,最後一行輸出並不完整,說明Apache程序堵塞在read系統呼叫上。read的物件是 /dev/random,看起來與隨機數有關。但是,哪裡的程式碼會用到隨機數呢?

找到關鍵程式碼

根據前面輸出的IP和PORT,包括呼叫引數,我們確定這是在訪問memcached。於是,順藤摸瓜,找到訪問memcached之後的一段程式碼:

Php程式碼  收藏程式碼
  1. $size = mcrypt_get_iv_size (MCRYPT_BLOWFISH,MCRYPT_MODE_ECB);  
  2. $iv = mcrypt_create_iv($size, MCRYPT_DEV_RANDOM);  
  3. $m = mcrypt_ecb (MCRYPT_BLOWFISH,$key,$dmcryptText,MCRYPT_DECRYPT,$iv);  

其中,第二行程式碼,出現了RANDOM,查了一下php手冊,當第二個引數為MCRYPT_DEV_RANDOM時,mcrypt_create_iv存在堵塞的可能性。MCRYPT_DEV_URANDOM則不會阻塞。

線上故障得以解決

雖然還不知道具體原因,但是本著快速解決問題的原則,決定替換引數立刻上線。

果然,問題得以解決,重新整理頁面時,從未如此酣暢淋漓!

分析故障現象

線上的Apache程序很大的概率會走到上述程式碼,因此很可能被block一段時間。於是,當前頁面就會很慢。

當所有Apache程序都被block時,後續請求必須等待空閒的Apache程序,因此後續頁面都將變得很慢。

由於Apache程序unblock的時間不可確定,因此後續頁面的等待時間也時長時短。

深挖原因

雖然問題解決,但是本質原因還沒搞清楚:為什麼MCRYPT_DEV_RANDOM會堵塞,而MCRYPT_DEV_URANDOM從不會堵塞。

google了一下/dev/random,維基百科一如既往的靠譜:

 寫道 在這個實現中,發生器儲存了來自熵池中噪聲的資料位數的估計值,而隨機數是從該熵池中建立的。
在讀取時,/dev/random裝置只會返回熵池中噪聲資料中的隨機位元組。
/dev/random應當可以適用於要求非常高質量隨機性的應用,例如產生公鑰或一次性密碼本。
若熵池空了,對/dev/random的讀操作將會被阻塞,直到收集到了足夠的環境噪聲為止[3]。

這樣的設計使得/dev/random是真正的隨機數發生器,提供了最大可能的隨機資料熵,建議用於產生保護高價值或長保護週期的金鑰。

/dev/random的一個副本是/dev/urandom ("unlocked",非阻塞的隨機數發生器[4]),它會重用內部池中的資料以產生偽隨機資料。
這表示對/dev/urandom的讀取操作不會產生阻塞,但其輸出的熵可能小於/dev/random的。
該裝置檔案是設計用於密碼學安全的偽隨機數發生器的,可以用於安全性較低的應用。

大概的意思就是,/dev/random生成隨機數時,依賴熵池。如果熵池空了或不夠用,對/dev/random的讀取就會堵塞,直到熵池夠用為止。/dev/urandom則不會堵塞。有得必有失,urandom的隨機性弱於random。

詳解熵池

熵池本質上是若干位元組。/proc/sys/kernel/random/entropy_avail中儲存了熵池現在的大小,/proc/sys/kernel/random/poolsize是熵池的最大容量,單位都是bit。如果entropy_avail的值小於要產生的隨機數bit數,那麼/dev/random就會堵塞。

那麼,為什麼熵池不夠用呢?

google了一下資料,熵池實際上是從各種noice source中獲取資料,noice source可能是 鍵盤事件、滑鼠事件、裝置時鐘中等。linux核心從2.4升級到2.6時,處於安全性的考慮,廢棄了一些source。source減少了,熵池補給的速度當然也變慢,進而不夠用。

其實,通過消耗熵池,可以構造DOS攻擊。原理很簡單,熵池空了,依賴隨機數的業務(SSL,加密等)就不能正常進行。

補充熵池

Linux伺服器在執行時,既沒有鍵盤事件,也沒有滑鼠事件,如何快速積累熵池呢?

google了一下資料,發現有一些程式可以自動補充熵池,例如rngdrng-tools

我在Linode VPS上嘗試了一下rngd,效果非常明顯。

先觀察rngd啟動前的熵池大小: watch cat /proc/sys/kernel/random/entropy_avail ,在100~200之間。

然後啟動rngd:sudo rngd -r /dev/urandom -o /dev/random -f -t 1

熵池立刻飆升到3712,接近4096的上限。

總結

先吐槽:沒有日誌的系統太扯淡了,追查問題只能靠推測或猜測,耽誤大量時間。

後總結:如果業務依賴隨機數,那麼最好使用工具主動補充熵池。

再吐槽:熵池一直夠用,今天才出現不夠用的情況。究竟是神馬原因,還搞不清楚。碼農真苦!

相關推薦

Linux隨機數發生器導致Apache程序全部Block的問題

今天上午,運營同事報告一個嚴重故障,現象是網站頁面速度非常慢,基本不可用。工程師開始追查問題。 首先介紹一下系統架構:前端 Apache,中間PHP,後端MySQL,經典的LAMP架構。 猜測資料庫出現效能問題 第一反應,懷疑資料庫資料量太大。我們一直定期清理資

Linux下獲取可執行程序的絕對路徑

出錯 處理 其他 但是 源文件位置 應該 out 絕對路徑 class 編寫的程序中如果需要讀取配置文件,或者需要輸出log文件打印日誌,或者讀取其他文件的時候會出現一個問題: 可執行程序在讀取文件路徑的時候使用什麽路徑? 我們一般項目的結構就是: project/

linux中編譯C語言程序

編輯器 ins spa include all 運行程序 gcc linux中 style 1.首先安裝gcc編輯器 yum install gcc* -y 2.編寫C語言程序 [[email protected]/* */ ~]# vim aa.c #i

linux 編譯式安裝apache

系統 -1 技術 安裝apache ket linu 升級 clas 重新 apache的安裝需要兩個組件,APR對於Tomcat最大的作用就是socket調度 組件下載解壓完成 ,講兩個組件解壓包移動到apache的類庫文件夾內 註:如果系統自帶了ap

Linux學習筆記:rpm程序包管理

源代碼 rpm 程序包 以CentOS為例,rpm程序包管理器的相關內容如下:CentOS的程序包管理器: 程序包的命名規則: 源代碼包: software_name-VERSION.tar.gz VERSION:major.mino

linux下設置mysql apache 開機後自動啟動

etc init 改變 表示 mysql support 一行 pre server 1 #將mysql啟動腳本放入所有腳本運行目錄/etc/rc.d/init.d中 2 cp /lamp/mysql-5.0.41/support-files/mysql.server

輕松學習之Linux教程四 神器vi程序編輯器攻略

分享 內置 snippet 2014年 答案 程序 ice 界面 fff 本系列文章由@超人愛因斯坦出品,轉載請註明出處。 文章鏈接: http://hpw123.net/a/Linux/Linuxjichu/2014

Linux服務器配置apache服務

指向 eps node 安裝 pac rep ice 系統 .com 1、查看服務器是否安裝apache服務:rpm -qa|grep (apr/apr-util/pcre/httpd)   如果不需要系統已有的服務的話,可以刪除掉重新配置(rpm -e servicena

鳥哥的Linux私房菜-----16、程序與資源管理

blog dsm alt 技術 article ack src mar data 鳥哥的Linux私房菜-----16、程序與資源管理

Linux虛擬機安裝應用程序提示Graphical installers are not supported by the vm

system linux安裝 library 虛擬 when for mis clas bstr Linux安裝應用程序提示Graphical installers are not supported by the vm Technote (troubleshooting

linux服務器中Apache隱藏index.php失敗

document mod write inux override director tee family height 可以通過URL重寫隱藏應用的入口文件index.php,下面是相關服務器的配置參考: 【Apache】 httpd.conf配置文件中加載了mod_re

linux後臺運行jar程序

jar包 鎖定 輸出重定向 而是 color netstat 編號 打印 mman Linux 運行jar包命令如下: 方式一:java -jar XXX.jar特點:當前ssh窗口被鎖定,可按CTRL + C打斷程序運行,或直接關閉窗口,程序退出那如何讓窗口不鎖定?

linux基礎】rpm安裝程序和管理

rpm使用1.了解應用程序應用程序(app):安裝在os上完成特定功能的軟件。應用程序的類型:*.rpm(redhat分支默認軟件格式),*.deb(debian分支默認軟件格式),源代碼(通用的軟件格式,也是生成rpm和deb的基礎),其他自帶安裝程序及免安裝的軟件。用戶程序常用的目錄:/etc,/var/

存儲過程不返回記錄集導致ADO程序出錯

sad () cad csdn博客 dset cts ref seo open HRESULT _hr = get_adoEOF(&_result); IsEOF()函數如下:其中ADOCG::_RecordsetPtr m_pRecordset; BOOL I

Linux下GoAccess的安裝與全部用法

3.4 百分號 最終 單獨 一個 用戶id 概述 src 月份 GoAccess用戶文檔 一、 GoAccess概述 1.1 GoAccess概述 goaccess是一個實時的web日誌分析器,以及交互式查看器,在類Unix系統的終端(terminal)上

Linux如何實現開機啟動程序詳解(轉)

window 自己的 進行 執行時間 dns服務 全部 星期 ext 例如 Linux開機啟動程序詳解我們假設大家已經熟悉其它操作系統的引導過程,了解硬件的自檢引導步驟,就只從Linux操作系統的引導加載程序(對個人電腦而言通常是LILO)開始,介紹Linux開機引導的步驟

我在linux的第一個C程序

自帶 nbsp str logs c++ world 命令 直接 生活 今天在虛擬機裝起了linux,根據大家學習所需要,可以安裝自己喜歡的版本,我這裏裝的是centos 7.0版本,也正是學習的開始,現在來看看簡潔大氣的centos界面吧; 在centos編譯C程

linux利用CMakeLists編譯cuda程序

pro sum rar source tar sta cut urn ner 文件目錄: cudaTest |--utils.cu |--utils.h |--squaresum.cu |--squaresum.h |--test.c

[科技]NOI Linux下的對拍程序

ima 而是 cst 裏的 aps 環境 輸入 函數 mage 我們知道,在$Windows$環境下用$cmd$裏的$FC$函數實現對拍(放到一個目錄下): #include <cstdlib> int main(){ while(true){

linux服務器)apache開啟gzip的配置以及效果對比

evel 左右 bsp image XML php 以及 .com erb 配置: 1 進入配置目錄: cd /opt/lampp/etc 2 編輯配置文件: vi httpd.conf 3 配置:增加以下代碼片段 # gzip壓縮 <IfModule mo