美文网首页
从0开始学架构: 3. 微服务网关源码剖析

从0开始学架构: 3. 微服务网关源码剖析

作者: 牧码人爱跑马 | 来源:发表于2020-04-11 21:15 被阅读0次

    一、微服务网关层的整体架构思考

    先回顾下网关层的功能:

    1.请求鉴权

    发布商品,登录鉴权。

    2. 数据完整性检查

    数据定长Header,变长body

    3. 协议转换

    JSON-> HashMap(string,obj)
    如果value不支持json嵌套的话,就string就可以。hashmap(string,string)

    4. 路由转发

    根据CMD转发到不同业务逻辑层

    5. 服务治理

    限流,降级,熔断等。

    其中最核心的是1和4.
    1涉及到session存到哪,
    4涉及到如何把众多的HTTP请求路由到逻辑层的RPC接口。新上一个业务(逻辑层),网关不需要的重启的情况下如何发现它。

    二、自研网关的各个关键点

    2.1 自研网关需求剖析

    打造一个高性能的分布式网关(SaaS),实现HTTP请求转发到RPC服务、接口请求鉴权、反作弊(风控、antispam)等相关功能。

    要实现如下功能:

    1. 高性能分布式模块(这里模块指的Process)
    2. 鉴权功能
    3. 路由能力
    4. 简单实用的反作弊

    落实到技术层面,解决方案如下:

    1. 无状态设计
    2. 过滤器责任链设计(拦截器)
    3. 反作弊设计(拦截器)
      可以理解为责任链的一部分
    4. 路由方案设计

    架构参考

    整体架构基于Spring boot框架。


    image.png
    • 网关本质上是一个websever。

    • 注意上面的Filter责任链模式。 跨域问题
      比如,访问www.baidu.com,调用的js中有www.iqiyi.com。那么到了iqiyi的网关层,它发现主域名是来自于其他网站,就会考虑让不让它访问iqiyi,这就是一个跨域问题。

    • 网关属于高并发模块
      所以要逻辑简单,业务逻辑剥离到logic层

    • 缓存设计、异步线程设计
      反作弊模块,希望有一个黑名单缓存,比如map或set。(因为和外部交互影响性能)。黑名单应该是由数据分析得到的,比如放到redis里。那么我如何在进程内缓存呢?
      这时就要一个异步加载机制,比如每隔5s从redis里读出来覆盖set。(最终一致性),即进程内和进程外通讯。

    • 进程外缓存,配置平台
      进程外缓存就指的redis集群
      配置平台是路由逻辑用的,后面详解。

    image.png

    上面的图不对,需要换一下

    2.2 跨域问题

    从一个源(www.baidu.com)加载的文档或脚本(js),不能访问另一个源(www.iqiyi.com)的资源。

    image.png
    • Access-Control-Allow-Origin
      栗子:
      比如baidu的网页想嵌入iqiyi的一个url资源,那么它会先去iqiyi的网关层探测我能不能访问你的资源,如果iqiyi允许的话,会在网关层建立一个豁免清单(允许哪些第三方的域名访问)。

    • 跨cookie Access-control-allow-credentials
      cokie是种在url里的,比如种在api1.baidu.com里的,那么api2.baidu.com就不行了。如果设置为允许跨cokie,那么cokie在任何一个二级域名里都可以(*.baidu.com).

    • 允许哪些方法进行跨域访问

    2.3 Session设计

    image.png

    2.3.1 session绑定

    本质就是将uid hash到固定的节点。
    问题是高可用怎么保证呢? session一般是没必要持久化的。
    思路是网关冗余,模仿数据库主从复制。


    image.png

    但是,网关间的数据复制如何设计呢?(要考虑vip、主从复制等,简单问题复制化了)。所以session绑定在工业界很少用。
    所以一般用session绑定

    2.3.2 session 复制

    image.png

    而且是最终一致性的,存在session重写。这种方案也是不合理的。

    2.3.3 session共享

    image.png

    这里的redis是redis cluster。
    使用缓存服务Redis,统一存储Session。

    优点

    • 网关层无状态
    • 缓存服务本身高可用

    缺点

    • 多一次服务调用IO
      思考如果减少IO调用,且网关是无状态化的。很自然的想到session存在客户端。

    2.3.4 Session 客户端缓存

    image.png

    可以存在app的sqlite里
    优点:

    • 简单高性能
    • 网关层无状态
      缺点:
    • 依赖客户端Cookie(session)存储
      每次带cookie,消耗一些app端的流量。

    这个用的比较多,因为响应延迟低,且高可用。

    2.3.5 session 生成算法

    image.png

    session=AES(uid + TTL + checksum)
    用户第一次登录时,网关生成session,然后返回给客户端,之后每次登录时带着这个session。
    本地算法,AES解密看TTL是否过期,checksum是否正确。

    远程校验,是因为session在很多公司是在业务逻辑层生成的(因为更多的是业务逻辑的判断),而不在网关层生成。TTL过期后要到业务逻辑层去校验,业务逻辑层返回给GW一个新的session,GW返回给APP。这个可能很少概率。

    2.3.6 session 拦截器

    image.png

    拦截器中会生成logid,logid是app请求的唯一标识。

    以上主要两部分功能,1 是session校验,2是生成logid。

    2.4 网关层反作弊需求

    • 针对恶意流量,从网关层面进行拦截,防止对后端服务造成高并发压力
    • 为了防止误伤,对于黑名单数据定期释放能力


      image.png

    分析:

    1. 初期阶段
      数据量小的时候,可以内存中local cache。

    2. 高可用设计
      进程内缓存解决不了高可用

    3. 黑名单
      持久化怎么做

    image.png

    上面是数据量比较小的时候,那么数据量大的时候怎么做,几十G的话进程内缓存不了。
    风控挖掘的时候可以存在redis里,但是为了这种小概率的事读redis会导致耗时增加。
    所以可以用布隆过滤器。

    思考

    • 数据量大怎么做(布隆过滤器)
      如果每次读redis,为了这小概率事件开销太大
      但是布隆过滤器具体怎么做?后面详解
    • 实时性怎么破?
      如果5s拉一次可能不够实时,如果实时性要求高,可以改成redis有更新然后push的方式。

    2.5 自研网关各个击破:之路由

    image.png

    RPC客户端比如Dubbo,用来和网关后面的业务逻辑层的RPC services通信。

    架构设计原则

    1. 初期阶段约定大于配置:
      url什么规范,接口的约定。

    2. 服务端简洁化设计

    • 功能够简单
    • 使用用够方便

    负载均衡和服务发现

    • RPC框架实现

    熔断设计

    Hystrix

    协议约定

    • 网关和APP间的数据协议是JSON
    • 网关层调用业务逻辑层入参统一为Map<string,string>
    • 业务逻辑层返回统一的Result对象{code,data,msg}
      code:0, data:xxx, msg: success
      网关层拿到后再转化成json,然后返回给APP。

    2.5.1 路由设计

    image.png

    上图其中Sevrice比如分别对应用户、商品、交易的logic。
    其中RPC框架比如是Dubbo的RPC客户端,调用Dubbo的RPC服务端(即后端的logic)。

    uri->Service(比如User logic),Method对应User logic中的get user方法。
    这块主要做两件事:

    1. 建立url和服务间的映射关系(服务启动初始化,内存里建立映射)
    2. RPC通过反射实现远程调用。(反射生成对应的对象供调用)

    25.2 具体实现:

    image.png image.png image.png

    上面讲的其实网关1.0的路由实现,有如下几个问题:

    1. 启动耗时大
      比如有几百个业务逻辑,都去网关建立路由映射关系,那么服务启动初始化的时候就会非常耗时。

    2. 业务升级需要重启,耦合严重,降低开发效率。
      比如新加个服务,需要重新到网关层注册(建立路由映射),那么网关就需要重启进程。

    那么2.0就需要解决这两个问题。

    2.6 网关2.0

    image.png image.png
    • 路由到通用接口。接口再去路由到具体的服务。
      这样就不需要引入service,不需要重启。基于接口编程。
      proxy每增加一个服务的时候,需要上报CLASS和Method给存储层(Mysql),网关层每隔5s扫描存储层加载到内存里。这样网关层根据CMD对应的Class和Method拿到Service IP,然后调用固定的接口。
    image.png image.png

    思考 网关3.0的演进

    • 进一步解耦如何做?
      一定需要mysql作为存储层吗? 可否用注册中心或配置中心来做?
    • 泛化调用的逻辑?

    三、开源框架推荐

    image.png image.png

    相关文章

      网友评论

          本文标题:从0开始学架构: 3. 微服务网关源码剖析

          本文链接:https://www.haomeiwen.com/subject/mmjxmhtx.html