Varnish 3進程結構,存儲方式及性能調優

Varnish進程及存儲

  • Varnish進程結構
    varnish_process_architecture
  • Varnish管理進程

    varnishd啓動之後有兩個進程:管理進程(父進程ID爲1)和子進程(父進程ID爲管理進程ID).

    # ps -ef | grep varnishd | grep -v grep

    管理進程每隔幾秒探測一下子進程的活動.如果在一定的時間之內,沒有獲得回覆,管理進程就會殺死子進程並重啓它.管理進程的日誌將會記錄到syslog.由於管理進程啓動子進程的速度很快,因此很難察覺到.通過監控syslog和varnish的啓動時間有助於解決問題.

    # tail -f /var/log/messages
    # varnishstat -f uptime
  • Varnish子進程及線程模型

    子進程包含幾種類型的線程,包括但不限於:

    線程名稱線程數目任務
    acceptor線程1個接收新連接並委派他們
    cache-worker線程每個會話(活動連接)一個處理請求
    cache-main線程1個用於Varnish啓動
    expiry線程1個將舊內容從緩存中移除
    ban lurker線程1個清除bans
    epoll/kqueue線程可配置,默認爲2個管理線程池
    backend線程每個後端探測有一個探測健康檢查

    當線程需要獲得或修改內存的時候,Varnish使用工作空間(workspaces)來減少線程之間的競爭.Varnish有多個工作空間,但用來操作會話數據的會話工作空間(session workspace)是最重要的.比如,session workspace爲5M,有1000個線程,那麼虛擬內存使用是5GB,但實際的內存使用不一定是5GB.內存控制器和操作系統會跟蹤記錄實際使用的內存.

    爲了跟系統的其它部分通訊,子進程使用了文件系統可訪問的共享內存日誌(shared memory log).這意味着如果一個線程需要記錄日誌,它所需要做的就是獲得一個”鎖”,寫進內存區域,然後釋放”鎖”.此外,每個worker線程都有一個日誌數據的緩存,以減少”鎖”的競爭.

    共享內存日誌文件通常大約爲90MB,並且分成兩個部分.第一部分是計數器(counters),第二部分是請求數據(request data).可以使用Varnish的輔助工具(如:varnishlog,varnishstat,varnishtop)來查看實際數據.

    Varnish的每個會話都使用一個線程.Varnish可以使用的線程數決定了Varnish可以同時併發處理多少個請求.
    Varnish運行時使用多個線程池.當一個連接被接受的時候,該連接會被委派給其中一個線程池.這個線程池會進一步委派這個被接受的連接給可用的worker線程.如果沒有可用的worker線程,則將該連接放到queue.如果Queue已經滿了,則該連接被丟棄.Varnish默認使用2個線程池,這已經被證明足夠用,即使對很忙的Varnish服務器也適用.

  • VCL編譯

    Varnsih緩存策略的配置是通過VLC(Varnish配置語言)來實現的.管理進程會解析VCL並轉化爲C,然後由C編譯器來編譯.最終,編譯後的VCL會被關聯到正在運行的Varnish實例.編譯後的VCL文件一直被保留直到重啓Varnish或通過管理客戶端的vcl.discard命令丟棄它.

    在Varnish不停止運行的情況下,可通過管理客戶端重新加載VCL配置,新VLC的緩存策略會立即生效.

    查看當前Varnish實例的可用vcl列表:

    # varnishadm vcl.list
    available       0 boot
    available       0 reload_2013-04-06T23:00:44
    available       0 reload_2013-04-06T23:00:47
    available       0 reload_2013-04-06T23:00:48
    active          0 reload_2013-04-06T23:00:49

    編譯一個新的vcl,並加載使用:

    # varnishadm vcl.load full_vcl /usr/local/varnish/etc/varnish/full_fdfs.vcl
    # varnishadm vcl.list  
    available       0 boot
    available       0 reload_2013-04-06T23:00:44
    available       0 reload_2013-04-06T23:00:47
    available       0 reload_2013-04-06T23:00:48
    active          0 reload_2013-04-06T23:00:49
    available       0 full_vcl
    # varnishadm vcl.use full_vcl

    丟棄一個名爲”reload_2013-04-06T23:00:44″的vcl配置:

    # varnishadm vcl.discard reload_2013-04-06T23:00:44
  • Varnish存儲方式

    Varnish支持幾種方式來給緩存分配空間,包括:file,malloc和persistent (experimental).

    • malloc存儲方式:
      Varnish會使用malloc(內存分配)請求分配整個預設緩存大小的內存.操作系統通過使用swap將不能裝載到內存的數據存儲到磁盤.

    • file存儲方式:
      Varnish會在文件系統上創建一個文件去包含整個緩存,並且告訴操作系統通過mmap(內存映射)將整個文件映射到內存中(如果可能的話),即file方式實際上也是使用內存去緩存數據.
      需要注意的是,在停止或重啓Varnish的時候,file存儲的方式不會保留數據.使用file存儲方式,Varnish不會記錄哪些數據寫入到磁盤,哪些沒有寫入.因此不可能知道磁盤上的緩存是否可用,它僅僅是隨機數據.如果使用file存儲方式的話,Varnish不會(也不可以)重新使用舊的緩存.

    • persistent:
      類似file存儲方式,是一種試驗性的持久存儲方式.它還沒有很好解決空間全部消耗完的情況.

    • 存儲方式選擇
      選擇存儲方式的時候,如果內存足夠大的話,最好選擇malloc,這樣可以讓緩存全部或是大部分保存在內存中.
      如果需要緩存的數據超過可用物理內存,可以選擇file存儲方式.

    • Varnish額外開銷
      通過-s參數設置的是預設的實際緩存大小.Varnish還需要額外的開銷來跟蹤記錄緩存,大概每個儲存對象需要約1K的額外開銷.(100萬的對象就需要額外使用1GB內存).此外,啓動Varnish(無任何存儲對象時)也需要大概100MB左右的開銷.

Varnish性能調優

  • Varnish參數

    查看Varnish當前的所有參數設置:

    # varnishadm 'param.show -l'

    優化參數的設置可以通過管理客戶端varnishadm設置,也可以在通過varnishd的啓動參數-p來設置.
    通過varnishadm設置的參數不會被保存,Varnish重啓的時候將會丟失.最好的設置方式將參數放到啓動腳本.

  • 系統內核調優
    # echo 'fs.file-max=1000000' >> /etc/sysctl.conf
    # echo 'net.ipv4.ip_local_port_range = 1024 65535' >> /etc/sysctl.conf
    # sysctl -p
    # echo '* soft nofile 1000000' >> /etc/security/limits.conf
    # echo '* hard nofile 1000000' >> /etc/security/limits.conf
    # echo 'session required pam_limits.so' >> /etc/pam.d/login
    # ulimit -n 1000000
    # ulimit -n -H

    注:不要設置tw_reuse爲1 (sysctl).那樣會對NAT的客戶端造成問題.

  • Varnish啓動參數調優

    Varnish的默認參數大多已經是優化的了.需要調優的可能是線程數(number of threads)和工作空間(workspace).

    • thread_pools:worker線程池的數量,默認值爲2.
      增加worker線程池數量可以減少”鎖”的競爭.但是過多的線程池會消耗CPU和RAM的資源,線程池數目多於CPU的核數目對性能是有損害的.
      儘管可使用多個線程池,但生產環境和經驗已經證明有2個線程池之後,增加更多的線程池並不會提高性能.

    • thread_pool_min:每個線程池的最小的線程數,默認值爲5.

    • thread_pool_max:每個線程池的最大的線程數,默認值是500.
      不要將該值設置得太高,因爲過量的worker線程會消耗RAM和CPU,從而適得其反.
      worker線程數受文件描述符數限制,總的worker線程數不應該超過5000,否則可能出現文件描述符相關的問題.

    • thread_pool_add_delay:創建線程之間最少需要等待的時間,默認值爲2ms.
      設置時間過長會導致worker線程不足,設置過短會增加worker線程堆積的風險.
      使用2ms就好,可以快速創建線程,避免發生隊列填滿和丟棄請求,減少Varnish的啓動時間.

    • thread_pool_timeout:線程空閒的閾值(在被移除之前),默認值300s.該值很少需要改變.
      當線程數目超過thread_pool_min,並且處於空閒狀態至少這麼久的時間,就很可能被清除.

    • thread_pool_fail_delay:在線程創建失敗之後,創建另一個線程需要至少等待多少時間.
      創建worker線程失敗通常是系統出問題的徵兆.因爲進程已經消耗完留給線程堆棧(thread stacks)的RAM資源.
      這樣的延遲可以減少不必要的擁擠狀況.
      如果線程創建失敗成爲了問題,那麼請檢查thread_pool_max是否設置太高.增加thread_pool_timeout和thread_pool_min也可能有助於降低線程銷燬和重新創建的速率.

    • lru_interval:儲存對象在LRU列表上移動之前的寬限時間.
      存儲對象只能被移動到LRU列表的前面,如果他們在這個時間之內還沒有被移動到那裏的話.
      這樣可以減少給LRU列表訪問的“鎖”操作的數量.不要修改該值,否則可能會很危險(如果你突然需要LRU列表的話).

    • sess_workspace: 分配給會話的進入的HTTP頭的工作空間(來自客戶端).默認是64K,最小需要1K.
      這個空間必須足夠大,分配給整個HTTP協議頭部和任何在VCL中對HTTP頭的修改.調優的話,可以取值16k~10M.

    • session_linger:爲了看是否有新的請求馬上出現,worker線程在一個會話上逗留多長時間.默認值爲50ms.
      如果會話被重複使用,在之前一次的請求完成之後的頭100ms內,最多隻有一半的重用發生.
      設置該值過高會導致worker線程不會爲這樣的逗留時間做任何事情,設置過低意味着更多的會話繞過了等待.
      在CPU吃緊的時候,讓每個worker線程等待幾個新的請求很重要,這樣可以避免過多的上下文切換.
      該值的設置取決於分發存儲對象的通常需要多少時間.此外,這也會減少線程堆積的數量.

    • sess_timeout:留給持久會話的空閒超時(即keep-alive timeout).默認是5s.(來自客戶端)
      如果一個HTTP請求在這麼多時間之內還沒有被接受,那麼這個會話就會被關閉.
      調高sess_timeout的值,會增加文件描述符的消耗.這樣做沒有什麼好處,還可能會造成文件描述符耗盡的危險.

    • send_timeout:客戶端連接的發送超時.默認值爲60s.
      如果HTTP響應數據在這麼多的時間內沒有被傳輸,那麼會話就被關閉.

    • cli_timeout:子進程迴應來自管理進程CLI請求的超時時間.默認是10s.
      cli_timeout是管理進程在認定子線程死掉之前,等待子線程進行迴應的超時時間.如果超過這個時間,管理進程就會殺掉子進程,並將它重啓.Varnish負載比較大的話,管理進程可能會出現無法及時管理子線程而造成誤殺.適當調高該值可以避免這種情況發生.

    優化varnishd的啓動參數設置例子:

                      
    -p thread_pools = 2                          
    -p thread_pool_min = 200                      
    -p thread_pool_max = 2000   
    -p thread_pool_add_delay=2                  
    -p session_linger = 100                       
    -p sess_workspace=262144
    -p cli_timeout=25
    

    通常使用500~1000個總的最小線程來運行Varnish.通過監控n_wrk_queued可以知道這樣的線程設置是否合適.
    n_wrk_queued(queued work requests)在Varnish啓動之後應該是幾乎靜止不變的.

    # varnishstat -f n_wrk_queued
    
  • VCL參數優化
    • connect_timeout:後端的默認連接超時(OS/network延遲).默認是0.7s
      Varnish在放棄連接之前只會嘗試連接後端這麼多時間.VCL中可以針對每個後端和後端請求覆蓋該值.

    • first_byte_timeout:接收後端的第一個字節數據的默認超時(頁面生成?).默認是60s.
      Varnish在放棄之前只等待這麼長時間去接收第一個字節數據.如果設置該值爲0,意味着永遠不超時.
      VCL中可以針對每個後端和後端請求覆蓋該值.該參數不適用於pipe.

    • between_bytes_timeout:接收後端數據時字節之間的默認超時.默認是60s.
      Varnish在放棄之前在字節之間只等待這麼多時間.如果該值爲0,意味着永遠不超時.
      CL中可以針對每個後端和後端請求覆蓋該值.該參數不適用於pipe.

    VCL後端邏輯例子:

    ...
    backend default {
        .host = "192.168.1.191";
        .port = "80";
        .connect_timeout = 1s;
        .first_byte_timeout = 100s;
        .between_bytes_timeout = 100s;
        .probe = {
            .url = "/status.php";
            .interval = 20s;
            .timeout = 10s;
            .window = 2;
            .threshold = 2;
        }
    }
    ...

轉載:http://www.zrwm.com/?cat=138 作者:Jose


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章