个推微服务网关架构实践 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
getui
V2EX    推广

个推微服务网关架构实践

  •  
  •   getui 2019 年 3 月 5 日 2003 次点击
    这是一个创建于 2519 天前的主题,其中的信息可能已经有所发展或是发生改变。

    作者:个推应用平台基础架构高级研发工程师 阿飞

    在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用 N 个微服务的接口完成一个用户请求。因此,在客户端和服务端之间增加一个 API 网关成为多数微服务架构的必然选择。

    在个推的微服务实践中,API 网关也起着至关重要的作用。一方面,API 网关是个推微服务体系对外的唯一入口;另一方面,API 网关中实现了很多后端服务的共性需求,避免了重复建设

    个推微服务网关的设计与实现

    **个推微服务主要是基于 Docker 和 Kubernetes 进行实践的。**在整个微服务架构中,最底层的是个推私有部署的 Kubernetes 集群,在集群之上,部署了应用服务。

    **个推的应用服务体系共分为三层,最上一层是网关层,接着是业务层,最下面是基础层服务。**在部署应用服务时,我们使用了 Kubernetes 的命名空间对不同产品线的产品进行隔离。除了应用服务外,Kubernetes 集群上还部署了 Consul 来实现配置的管理、Kube-DNS 实现服务注册与发现,以及一些辅助系统来进行应用和集群的管理。

    下图是个推微服务体系的架构图。

    个推对 API 网关的功能需求主要有以下几方面:

    1. 要支持配置多个产品,为不同的产品提供不同的端口;

    2. 动态路由;

    3. URI 的重写;

    4. 服务的注册与发现;

    5. 负载均衡;

    6. 安全相关的需求,如 session 校验等;

    7. 流量控制;

    8. 链路追踪;

    9. A/B Testing。

    在对市面上已有的网关产品进行调研后,我们的技术团队发现,它们并不太适合应用于个推的微服务体系。第一,个推配置的管理都是基于 Consul 实现的,而大部分网关产品都需要基于一些 DB 存储,来进行配置的管理;第二,大部分的网关产品提供的功能比较通用,也比较完善,这同时也降低了配置的复杂度以及灵活性;第三,大部分的网关产品很难直接融入到个推的微服务架构体系中。

    最终,个推选择使用了 OperResty 和 Lua 进行自研网关,在自研的过程中,我们也借鉴了其他网关产品的一些设计,如 Kong 和 Orange 的插件机制等。

    个推的 API 网关的插件设计如下图所示。

    OpenResty 对请求的处理分为多个阶段。个推 API 网关的插件主要是在 Set、Rewrite、Access、Header_filter、Body_filter、Log 这六个阶段做相应的处理,其中,每一个插件都可以在一个或多个阶段起到相应的作用。在一个请求到达 API 网关之后,网关会根据配置为该请求选择插件,然后根据每个插件的规则,进一步过滤出匹配规则的插件,最后对插件进行实例化,对流量进行相应的处理。

    我们可以通过举例来理解这个过程,如上图所示,localhost:8080/api/demo/test/hello 这个请求到达网关后,网关会根据 host 和端口确定产品信息,并提取出 URI(/api/demo/test/hello),然后根据产品的具体配置,筛选出需要使用的插件 Rewrite_URI、Dyups 和 Auth,接下来根据每个插件的规则配置进行过滤,过滤后,只有 Rewrite_URI 和 Dyups 两个插件被选中。之后实例化这两个插件,在各个阶段对请求进行处理。请求被转发到后端服务时,URI 就被 rewrite 为“/demo/test/hello ”,upstream 也被设置为“ prod1-svc1 ”。请求由后端服务处理之后,响应会经网关返回给客户端,这就是整个插件的设计和工作的流程。为了优化性能,我们将插件的实例化延缓到了请求真正开始处理时,在此之前,网关会通过产品配置和规则,过滤掉不需要执行的插件。从图中也可以看出,每个插件的规则配置都很简单,并且没有统一的格式,这也确保了插件配置的简单灵活。

    网关的配置均为热更新,通过 Consul 和 Consul-Template 来实现,配置在 Consul 上进行更新后,Consul-Template 会将其实时地拉取下来,然后通过以下两种方式进行更新。

    ( 1 )通过调用 Update API,将配置更新到 shared-dict 中。

    ( 2 )更新配置文件,利用 Reload OpenResty 实现配置文件的更新。

    个推微服务网关提供的主要功能

    1.动态路由

    动态路由主要涉及到三个方面:服务注册、服务发现和请求转发。

    如下图所示,服务的注册和发现是基于 Kubernetes 的 Service 和 Kube-DNS 实现的,在 Consul 中,会维持一个服务的映射表,应用的每一个微服务都对应 Kubernetes 上的一个 Service,每创建一个 Service 都会在 Consul 上的服务映射表中添加一项(会被实时更新到网关的共享内存中)。网关每收到一个请求都会从服务映射表中查询到具体的后端服务(即 Kubernetes 中的 Service 名),并进行动态路由。Kube-DNS 可以将 Service 的域名解析成 Kubernetes 内部的 ClusterIP,而 Service 代理了多个 Pod,会将流量均衡地转发到不同的 Pod 上。

    2.流量控制

    流量控制主要是通过一个名为“ Counter ”的后端服务和网关中的流控插件实现的。**Counter 负责存储请求的访问次数和限值,并且支持按时间维度进行计数。**流控插件负责拦截流量,调用 Counter 的接口进行超限查询,如果 Counter 返回请求超限,网关就会直接拒绝访问,实现限次的功能,再结合时间维度就可以实现限频的需求。同时流控插件通过输出日志信息到 fluent-bit,由 fluent-bit 聚合计次来更新 Counter 中的计数。

    3.链路追踪

    整个微服务体系的链路追踪是基于分布式的链路追踪系统 Zipkin 来实现的。通过在网关安装 Zipkin 插件和在后端服务中引入 Zipkin 中间件,实现最终的链路追踪功能。具体架构如下图所示。

    4. A/B 测试

    在 A/B 测试的实现中,有以下几个关键点:

    ( 1 )所有的策略信息都配置在 Consul 上,并通过 Consul-Template 实时生效到各个微服务的内存中;

    ( 2 )每条策略均有指明,调用一个微服务时应调用 A 还是 B (默认为 A );

    ( 3 )网关中实现 A/B 插件,在请求到达网关时,通过 A/B 插件配置的规则,即可确定请求适用的 A/B 策略;

    ( 4 )网关会将请求适用的 A/B 策略通过 URL 参数传递下去;

    ( 5 )每个微服务通过传递下来的策略,选择正确的服务进行访问。

    下图给出了两种场景下的调用链路。

    总结

    以上就是个推微服务网关的设计和主要功能的实现。之后,个推的技术团队会不断提升 API 网关的弹性设计,使其能够在故障出现时,缩小故障的影响范围;同时,我们也会继续将网关与 DevOps 平台做进一步地结合,以确保网关在迭代更新时,能够有更多的自动化测试来保证质量,

    1 条回复    2019-03-06 09:20:43 +08:00
    Livid
        1
    Livid  
    MOD
    PRO
       2019 年 3 月 6 日
    这类推广内容请只能发布到这个节点:

    go/promotions

    这个主题已经被移动。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3698 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 04:16 PVG 12:16 LAX 20:16 JFK 23:16
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86