openswan性能初步分析

openswan性能初步分析

在這裏插入圖片描述
這裏對openswan的性能做個簡單的說明。爲什麼要介紹這個話題呢?

其實最主要的原因還是想openswan的性能到底如何、極限是多少隧道、會有哪些瓶頸等等? 比如一個項目要openswan支持很多隧道(比如說上萬條),那麼首先要考慮自己的產品能否支持到這麼多?也就是說需要知道自己產品的真實性能。如果不考慮這些實際的問題,只一味的接項目,那麼最可能的結果就是白白投入這麼多的人力物力時間,最終項目也拿不下,日子久了自己的飯碗也會被砸

在這裏插入圖片描述

另一個原因:openswan的官方也沒有給出明確的性能參數,比如說最大能支持多少條隧道? 所以根據現有的硬件資源來測試其性能是必不可少的。具體問題具體分析嘛。

1. pluto能支持多少條隧道

這個問題,我是衆裏尋他千百度呀,可惜的是驀然回首,產品經理他不走。後來我在openswan的源碼中找到這麼一條郵件信息,原文如下:

FreeS/WAN allows a single gateway machine to build tunnels to many others. There may, however, be some problems for large numbers as indicated in this message from the mailing list:

Subject: Re: Maximum number of ipsec tunnels?
   Date: Tue, 18 Apr 2000
   From: "John S. Denker" <[email protected]>

Christopher Ferris wrote:

>> What are the maximum number ipsec tunnels FreeS/WAN can handle??

Henry Spencer wrote:

>There is no particular limit.  Some of the setup procedures currently
>scale poorly to large numbers of connections, but there are (clumsy)
>workarounds for that now, and proper fixes are coming.

1) "Large" numbers means anything over 50 or so.  I routinely run boxes
with about 200 tunnels.  Once you get more than 50 or so, you need to worry
about several scalability issues:

a) You need to put a "-" sign in syslogd.conf, and rotate the logs daily
not weekly.

b) Processor load per tunnel is small unless the tunnel is not up, in which
case a new half-key gets generated every 90 seconds, which can add up if
you've got a lot of down tunnels.

c) There's other bits of lore you need when running a large number of
tunnels.  For instance, systematically keeping the .conf file free of
conflicts requires tools that aren't shipped with the standard freeswan
package.

d) The pluto startup behavior is quadratic.  With 200 tunnels, this eats up
several minutes at every restart.   I'm told fixes are coming soon.

2) Other than item (1b), the CPU load depends mainly on the size of the
pipe attached, not on the number of tunnels.

It is worth noting that item (1b) applies only to repeated attempts to re-key a data connection (IPsec SA, Phase 2) over an established keying connection (ISAKMP SA, Phase 1). There are two ways to reduce this overhead using settings in ipsec.conf(5):

  • set keyingtries to some small value to limit repetitions
  • set keylife to a short time so that a failing data connection will be cleaned up when the keying connection is reset.

The overheads for establishing keying connections (ISAKMP SAs, Phase 1) are lower because for these Pluto does not perform expensive operations before receiving a reply from the peer.

A gateway that does a lot of rekeying – many tunnels and/or low settings for tunnel lifetimes – will also need a lot of random numbers from the random(4) driver.

※: 【摘自源碼中的文檔:performance.html】

上面的信息是2000年的一個郵件,回覆的是freeswan的問題,但是這是我目前找到的最接近的回答,即使它也沒有給出明確的答案。

我在測試pluto性能時(公司移植適配後的),隧道最多的時候建了4800條左右(峯值),此時左右兩端隧道的狀態已經嚴重不一致了(left已經建立成功,但right卻沒有),這個原因我還沒有細究,不過可以肯定的是:和pluto的低性能有關。如果不考慮因移植引入的瓶頸問題,支持5000條應該不是問題。但此時的pluto的效率已經很低很低。下面我把自己遇到的問題做一個簡單的記錄、分析。

2. pluto的瓶頸在哪裏

既然說pluto的性能比較低,那麼它的瓶頸在哪裏呢?

這個原因會有很多,因此pluto的可用配置參數很多,不同的配置時,瓶頸略有不同,但是有幾個函數,無論策略如何配置,它的CPU佔有率都是穩坐前幾把交椅的存在。(在很多隧道時,特明顯,比如多餘1000條)。下面我來一一說明:

2.1 openswan_log()

openswan_log()這個函數支持爲了增加調試信息以及記錄日誌信息。由於需要頻繁的進行系統調用(或讀寫文件),導致pluto的處理性能極大的降低。當然對於va_start(),va_end()等函數並未細緻研究,因此它的效率根源暫時無法回答,可以肯定的是它的效率真的很低很低,因此爲了優化這個問題,只需要在openswan_log()的實現中實現一個開關即可,如果不做任何日誌操作,直接返回即可。解決這個開關常見的有兩種方式:

  • 添加一條whack命令

這是因爲whack命令已經實現了進程間的通訊(whack—pluto),完全可以滿足要求。此種做法處理效率快,也更加正規。

  • 訪問文件系統中的一個文件

我們也可以藉助文件系統實現進程間通訊。例如判斷文件系統中是否存在某一個文件。這裏便可以通過檢測文件系統中是否存在特定文件來控制openswan_log()是否記錄日誌信息。

此方法的優點是實現很簡單,實時性很好;但問題是每次需要訪問文件系統,效率比直接訪問全局變量來的慢。

2.2 find_phase1_state()

在隧道協商過程開始之前,需要確定是否之前是否已經協商過且存在狀態,如果存在,可能第一階段已經協商成功,直接進行第二階段協商即可。這個過程是必須的,通過它可以確定發起第一階段協商還是第二階段協商。那麼這個函數都做了哪些操作呢?

在這裏插入圖片描述

從當前的狀態哈希表(statetable), 找到最適合當前連接的狀態。也就是說需要將整個哈希表遍歷完才能找到“最合適”的。

除此之外,什麼是"合適呢"?

那就是一系列的判斷條件,其中一個是same_peer_ids, 最終比較雙方的ID標識,這個標識如果是默認的IP類型,那麼速度會相對快些;但如果爲FQDN、USE_FQDN,那麼函數的執行效率會更低。

因此如果我們提前添加1萬條隧道,每協商一條隧道,find_phase1_state便至少執行一次,遍歷所有的狀態,檢測所有的條件,那麼隨着隧道協商的增加,效率越來越低。

目前對於這個的優化還沒有特別好的想法。一個初步的想法是“以空間換時間”:即同時維持兩個哈希表,除了上述的哈希表外,再維持一個基於連接的哈希表,兩個哈希表共享所有的節點,只需增加一個指針域,將其鏈起來,構成一個網狀的結構。使用時根據不同的需求訪問不同的哈希表,速率上應該能得到提升。(增刪節點時得同時操作兩個哈希表)

2.3 event_schedule()

pluto中對於定時事件的處理是通過排序鏈表實現的,使用排序鏈表有一個缺點:當定時事件很多時,添加新定時器的效率會很低。因此在插入操作時,我們需要將當前的時間在鏈表中進行排序,雖然時間複雜度是O(n),但當定時事件很多時,卻不得不考慮效率低下的問題。這在pluto中添加成百上千條隧道時,體現的尤其明顯。那麼有沒有辦法進行優化呢?

在這裏插入圖片描述

答案肯定是有的。

常見的定時器有三類(《Linux高性能服務器編程》):排序鏈表,時間輪,時間堆。

既然排序鏈表低,很多人可能想到哈希表:根據定時的時間長度來取哈希,然後在進行排序豈不是可以提高效率。不錯,的確這樣,這就是時間輪的基本思想。如果需要優化的話pluto中的升序鏈表可以改爲時間輪。那麼改爲時間輪效率能提高嗎?由於pluto中的定時器都是以秒爲單位,這個時間跨度感覺有點太短,導致多個定時器堆積的問題,但是比升序鏈表效率高是確定的,因爲在添加定時器時的效率提高了很多。

在這裏插入圖片描述

2.4 con_by_name()

這個函數是在根據連接的名字查詢連接時使用的,pluto是使用鏈表來維護的。如果數量很大時,遍歷鏈表的時間複雜度O(n)。當然這個可以進行優化,同樣採用哈希表,儘可能的將連接均勻的分佈在不同的表中,這樣便可以提升查詢時的效率。

2.5 generate_msgid()

msgid是第二階段時的一個重要參數,它用來唯一標識一個IPSEC SA。

在生成msgid時,要確保msgid的唯一性,因此需要遍歷當前ISAKMP中所有的msgid。這個效率低下,跟我配置隧道參數時相關:我配置的隧道的端點IP相同,也就是說所有的隧道共用一個ISAKMP SA, 因此第二階段的隧道生成msgID時,需要同所有的msgid進行匹配,如果重複需要重新生成。

3. pluto中核心架構分析

pluto的核心處理架構是在call_server()中實現的。它使用IO多路複用的方式將IO事件信號定時器進行的集中的處理。該處理方式的優點在於統一處理,編程實現上容易些(雖然對源碼的作者來講:so easy!!!)

在這裏插入圖片描述

如果這裏將這三個事件分別放到三個線程中進行處理,當添加的隧道數量沒有那麼多時,效率上有一定的改善。可能問題來了? 如何判斷多線程(多進程)和IO多路複用孰優孰劣呢?

3.1 IO密集型和計算密集型

​ 首先得考慮業務的類型,屬於IO密集型還是計算密集型。

  • IO密集型

監工

I磁盤的讀取數據和輸出數據非常大的時候就是屬於IO密集型。由於IO操作的運行時間遠遠大於cpu、內存運行時間,所以任務的大部分時間都是在等待IO操作完成。

特點:cpu消耗小。(因爲CPU在休息等待)

IO密集型,由於CPU很多時間處於休眠等待期,因此通過多線程(多進程)來同時執行多個IO操作,只要其中一個沒有阻塞等待,那麼效率就可以得到相應的改善(不考慮資源切換和非常多的線進程情況下)。

  • 計算密集型
    在這裏插入圖片描述

計算密集型就是計算、邏輯判斷量非常大而且集中的類型,因爲主要佔用cpu資源所以又叫cpu密集型,而且當計算任務數等於cpu核心數的時候,是cpu運行效率最高的時候。

特點:消耗cpu。

很明顯,雖然IPsec也有比較多的IO操作,典型的就是使用數字證書進行協商時,但它絕對稱得上是計算密集型(加解密就是啪啪啪一頓計算,CPU直接滿負荷工作)。這時即使才用了多進程多線程技術,效率上也有可以沒有辦法得到提升。此時最好的辦法就是提升硬件的性能呢。

3.2 pluto適合多線程多進程嘛?

pluto雖然屬於計算密集型,喫CPU的大戶,但是如果將上述的三個事件(IO事件信號定時器)分開處理,自測情況下情況有所改觀,協商的隧道數量提升了幾百個左右。但是如果想把IO事件(IPSEC協商流程)進行多線程多進程處理,效率上應該得不到明顯的提升,畢竟CPU已經滿負荷的在計算,又讓他去計算另一條隧道,理論上改善的可能性有限。

解決辦法就是增加相應的硬件輔助資源:如增加CPU核心數、增加硬件加密卡等。

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