極驗目前的用戶超過7萬家網站,日均驗證量1億次,做爲一家專一於驗證安全服務的公司,極驗所要面臨的併發壓力主要表如今如下幾點:數據庫
日益增長的用戶併發量。編程
驗證請求是全動態過程,不可以進行緩存。後端
每一次請求都會形成數據庫的讀寫。緩存
處理請求須要耗費CPU大量的時間進行模型的計算。安全
做爲抗擊黑產的第一線,可能遭到黑產的攻擊。服務器
那麼極驗是如何作到,既保證用戶的驗證需求量,又儘可能快速響應用戶的驗證請求,還可以扛得住黑產的攻擊呢?極驗主要從三個方面來解決高併發問題。網絡
利用協程處理併發,咱們熟知的協程相較於線程來講具備的優勢是,可以跨平臺跨體系架構,不須要線程上下文切換和原子操做鎖定及同步的開銷。這樣就避免了操做系統調度線程形成的資源浪費。同時協程方便切換控制流,可以簡化編程模型,避免異步回調代碼的邏輯分割,使得程序的可讀性好,有利於後臺的維護。像極驗這樣高併發量同時須要高擴展性的驗證服務企業來講,使用協程處理是下降併發開銷最合適的方法。架構
from tornado import gen @gen.coroutine def fetch_coroutine(ur1): http_client=AsyncHTTPCient() response=yield http_client.fetch(url) # In Python versions prior to 3.3, returning a value from # a generator is not allowed and you must use # raise gen.return(response.body) # instead return response.body
其次極驗利用OpenResty過濾非法請求,以及限制不一樣帳戶併發。OpenResty 是一個基於 Nginx 與 Lua 的高性能 Web 平臺,其內部集成了比較精良的 Lua 庫、第三方模塊以及大多數的依賴項。可以比較便捷地搭建處理超高併發、高擴展性的動態 Web 服務。併發
極驗主要經過兩個手段來提高數據庫的性能:驗證的臨時數據採用基於分佈式Redis和構建嵌入式數據庫緩存,實現數據庫零查詢。app
Proxy的Redis存儲多是目前比較常規的存儲方法,經過代理將讀寫壓力進行合理分配。codis-proxy基於GO和C語言,併發處理能力比較強。後端基於slot概念支持靈活,還具備對用戶透明的擴容和縮容操做,簡單便捷,集羣管理工具豐富等優點。
可是對於極驗來講這樣的方式並非那麼合適,存在着如下幾點極驗必需要考慮的問題。
使用代理使得整個結構多了一層不安全因素,一旦代理層出現問題,那麼後面的都沒法正常運轉。
代理自己並不具有良好的擴展性,沒法自動的進行分配,在運維上有必定的難度。
加入代理層也會使得整個結構的響應速度相應減慢。
考慮到這些問題,咱們選擇採用本身的基於客戶端的分佈式解決方案,結構以下。
客戶端經過一致性hash,寫入當前機器與hash環上的下一臺機器,實現數據冗餘。讀取時從當前機器讀取,失敗則從hash環上下一臺機器讀取。得益於相對簡單的結構,擴容、故障恢復速度會快得多,同時運維成本更低。
在高併發量的狀況下,數據庫每每成爲瓶頸,加上大量掛起等待的協程也會使得數據庫的性能大大下降。像極驗這樣天天有大量的驗證數據須要讀取,提高數據庫性能就顯得十分重要。咱們的解決方案是進行嵌入式緩存,全部查詢徹底遵循緩存中的數據,緩存按期與數據庫同步。同時緩存直接嵌入服務進程內,實現幾乎零開銷查詢。因爲Python的GIL存在,咱們利用mmap實現進程間共享內存。
咱們在實現這個嵌入式緩存的過程當中,徹底按照咱們業務中遇到的實際問題進行設計,因此可能對於其餘業務不是很適用。具體來講,極驗的數據庫查詢主要有三種特性:
數據幾乎只讀不寫,而且對於數據一致性要求不高。
數據庫查詢開銷相對計算邏輯比重較大。
接口併發數長期保持在較高水平,用傳統緩存方式的話一旦緩存被穿透(例如惡意僞造不存在的數據)系統將崩潰。
基於上面三點特性,咱們專門定製了最適合咱們本身的緩存,並使得數據庫徹底再也不是系統的瓶頸。
提升計算性能極驗主要採用如下兩種方式:
1. 主要性能消耗在數據處理邏輯以及神經網絡參數計算
利用Cython將計算密集代碼編譯成擴展模塊供Python調用
def primes(int kmax): cdef int n,k,i cdef int p[1000] result=[] if kmax>1000: kmax=1000 k=0 n=2 while k<kmax: i=0 while i<k and n % p[i]!=0: i=i+1 if i=k: p[k]=n k=k+1 result.append(n) n=n+1 return result
2. 控制神經網絡規模,同時優化計算效率
經過不斷調整神經網絡的參數和加大訓練的迭代次數來保證足夠精度下網絡規模最小。在預測時加入DropOut,讓部分神經元不參與計算,減小計算量的同時必定程度避免過擬合。
利用小網絡學習大網絡所提取到的特徵加上現代Cpu的SIMD指令集加速計算——使用優化過的Blas庫例如OpenBlas等。這樣一來,可以很好的控制神經網絡的規模。
極驗經過以上三個技術手段,來解決高併發問題。目前咱們使用不到二十臺阿里雲服務器的狀況下能夠作到5w的併發,而且整個架構能夠徹底快速橫向擴展。