極驗高併發驗證服務背後的技術實現

IT風發表於2016-04-01

極驗目前的使用者超過7萬家網站,日均驗證量1億次,作為一家專注於驗證安全服務的公司,極驗所要面臨的併發壓力主要表現在以下幾點: 日益增加的使用者併發量。 驗證請求是全動態過程,不能夠進行快取。 每一次請求都會造成資料庫的讀寫。 處理請求需要耗費CPU大量的時間進行模型的計算。 作為抗擊黑產的第一線,可能遭到黑產的攻擊。 那麼極驗是如何做到,既保證使用者的驗證需求量,又儘量快速響應使用者的驗證請求,還能夠扛得住黑產的攻擊呢?極驗主要從三個方面來解決高併發問題。 降低併發的開銷 利用協程處理併發,我們熟知的協程相較於執行緒來說具有的優點是,能夠跨平臺跨體系架構,不需要執行緒上下文切換和原子操作鎖定及同步的開銷。這樣就避免了作業系統排程執行緒造成的資源浪費。同時協程方便切換控制流,能夠簡化程式設計模型,避免非同步回撥程式碼的邏輯分割,使得程式的可讀性好,有利於後臺的維護。像極驗這樣高併發量同時需要高擴充套件性的驗證服務企業來說,使用協程處理是降低併發開銷最合適的方法。 enter image description here 程式碼示例 其次極驗利用OpenResty過濾非法請求,以及限制不同賬戶併發。OpenResty 是一個基於 Nginx 與 Lua 的高效能 Web 平臺,其內部整合了比較精良的 Lua 庫、第三方模組以及大多數的依賴項。能夠比較便捷地搭建處理超高併發、高擴充套件性的動態 Web 服務。 提升資料庫效能 極驗主要通過兩個手段來提升資料庫的效能:驗證的臨時資料採用基於分散式Redis和構建嵌入式資料庫快取,實現資料庫零查詢。 Proxy的Redis儲存可能是目前比較常規的儲存方法,通過代理將讀寫壓力進行合理分配。codis-proxy基於GO和C語言,併發處理能力比較強。後端基於slot概念支援靈活,還具有對使用者透明的擴容和縮容操作,簡單便捷,叢集管理工具豐富等優勢。 enter image description here 但是對於極驗來說這樣的方式並不是那麼合適,存在著以下幾點極驗必須要考慮的問題。 使用代理使得整個結構多了一層不安全因素,一旦代理層出現問題,那麼後面的都無法正常運轉。 代理本身並不具備良好的擴充套件性,無法自動的進行分配,在運維上有一定的難度。 加入代理層也會使得整個結構的響應速度相應減慢。 考慮到這些問題,我們選擇採用自己的基於客戶端的分散式解決方案,結構如下。 enter image description here 客戶端通過一致性hash,寫入當前機器與hash環上的下一臺機器,實現資料冗餘。讀取時從當前機器讀取,失敗則從hash環上下一臺機器讀取。得益於相對簡單的結構,擴容、故障恢復速度會快得多,同時運維成本更低。 在高併發量的情況下,資料庫往往成為瓶頸,加上大量掛起等待的協程也會使得資料庫的效能大大降低。像極驗這樣每天有大量的驗證資料需要讀取,提升資料庫效能就顯得十分重要。我們的解決方案是進行嵌入式快取,所有查詢完全遵循快取中的資料,快取定期與資料庫同步。同時快取直接嵌入服務程式內,實現幾乎零開銷查詢。由於Python的GIL存在,我們利用mmap實現程式間共享記憶體。 我們在實現這個嵌入式快取的過程中,完全按照我們業務中遇到的實際問題進行設計,所以可能對於其他業務不是很適用。具體來說,極驗的資料庫查詢主要有三種特性:1.資料幾乎只讀不寫,並且對於資料一致性要求不高。2.資料庫查詢開銷相對計算邏輯比重較大。3.介面併發數長期保持在較高水平,用傳統快取方式的話一旦快取被穿透(例如惡意偽造不存在的資料)系統將崩潰。基於上面三點特性,我們專門定製了最適合我們自己的快取,並使得資料庫完全不再是系統的瓶頸。 提高計算效能 提高計算效能極驗主要採用以下兩種方式: 主要效能消耗在資料處理邏輯以及神經網路引數計算 利用Cython將計算密集程式碼編譯成擴充套件模組供Python呼叫 enter image description here

控制神經網路規模,同時優化計算效率 通過不斷調整神經網路的引數和加大訓練的迭代次數來保證足夠精度下網路規模最小。 在預測時加入DropOut,讓部分神經元不參與計算,減少計算量的同時一定程度避免過擬合。 利用小網路學習大網路所提取到的特徵加上現代Cpu的SIMD指令集加速計算——使用優化過的Blas庫例如OpenBlas等。這樣一來,能夠很好的控制神經網路的規模。 極驗通過以上三個技術手段,來解決高併發問題。目前我們使用不到二十臺阿里雲伺服器的情況下可以做到5w的併發,並且整個架構可以完全快速橫向擴充套件。

相關文章