极验高并发验证服务背后的技术实现

极验目前的用户超过7万家网站,日均验证量1亿次,做为一家专一于验证安全服务的公司,极验所要面临的并发压力主要表如今如下几点:数据库

  1. 日益增长的用户并发量。编程

  2. 验证请求是全动态过程,不可以进行缓存。后端

  3. 每一次请求都会形成数据库的读写。缓存

  4. 处理请求须要耗费CPU大量的时间进行模型的计算。安全

  5. 做为抗击黑产的第一线,可能遭到黑产的攻击。服务器

那么极验是如何作到,既保证用户的验证需求量,又尽可能快速响应用户的验证请求,还可以扛得住黑产的攻击呢?极验主要从三个方面来解决高并发问题。网络

下降并发的开销

利用协程处理并发,咱们熟知的协程相较于线程来讲具备的优势是,可以跨平台跨体系架构,不须要线程上下文切换和原子操做锁定及同步的开销。这样就避免了操做系统调度线程形成的资源浪费。同时协程方便切换控制流,可以简化编程模型,避免异步回调代码的逻辑分割,使得程序的可读性好,有利于后台的维护。像极验这样高并发量同时须要高扩展性的验证服务企业来讲,使用协程处理是下降并发开销最合适的方法。架构

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概念支持灵活,还具备对用户透明的扩容和缩容操做,简单便捷,集群管理工具丰富等优点。

图片描述

可是对于极验来讲这样的方式并非那么合适,存在着如下几点极验必需要考虑的问题。

  1. 使用代理使得整个结构多了一层不安全因素,一旦代理层出现问题,那么后面的都没法正常运转。

  2. 代理自己并不具有良好的扩展性,没法自动的进行分配,在运维上有必定的难度。

  3. 加入代理层也会使得整个结构的响应速度相应减慢。

考虑到这些问题,咱们选择采用本身的基于客户端的分布式解决方案,结构以下。

图片描述

客户端经过一致性hash,写入当前机器与hash环上的下一台机器,实现数据冗余。读取时从当前机器读取,失败则从hash环上下一台机器读取。得益于相对简单的结构,扩容、故障恢复速度会快得多,同时运维成本更低。

在高并发量的状况下,数据库每每成为瓶颈,加上大量挂起等待的协程也会使得数据库的性能大大下降。像极验这样天天有大量的验证数据须要读取,提高数据库性能就显得十分重要。咱们的解决方案是进行嵌入式缓存,全部查询彻底遵循缓存中的数据,缓存按期与数据库同步。同时缓存直接嵌入服务进程内,实现几乎零开销查询。因为Python的GIL存在,咱们利用mmap实现进程间共享内存。

咱们在实现这个嵌入式缓存的过程当中,彻底按照咱们业务中遇到的实际问题进行设计,因此可能对于其余业务不是很适用。具体来讲,极验的数据库查询主要有三种特性:

  1. 数据几乎只读不写,而且对于数据一致性要求不高。

  2. 数据库查询开销相对计算逻辑比重较大。

  3. 接口并发数长期保持在较高水平,用传统缓存方式的话一旦缓存被穿透(例如恶意伪造不存在的数据)系统将崩溃。

基于上面三点特性,咱们专门定制了最适合咱们本身的缓存,并使得数据库彻底再也不是系统的瓶颈。

提升计算性能

提升计算性能极验主要采用如下两种方式:

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的并发,而且整个架构能够彻底快速横向扩展。

相关文章
相关标签/搜索