本文整理自胡丽麟(Beeto 平台研发)在 Apache APISIX Summit ASIA 2022 中进行的分享,介绍了中东社交软件 Beeto 如何使用 APISIX 实现本地化部署。
Beeto 介绍
Beeto 是一款面向中东市场主打阿拉伯语言的社交软件,在产品设计和技术架构上都是本地化落地实施的。曾在沙特 iOS 应用商店 Top Charts 榜单中超过老牌社交巨头 Facebook,位列第 4 名。 其实中东在互联网领域算是发展较成熟的区域,在社交网络中的活跃用户渗透率非常高,尤其在沙特区域,2019 年的互联网用户就已经达到了 90%,活跃用户渗透率在 2020 年就已经排到了第 9 位。
互联网市场的成熟,带来的是国际性软件的覆盖,像 WhatsApp、YouTube 和 Instagram 等都是当地主流的社交软件。但回过头看,你会发现在中东地区基本没有类似国内微博这种本地化的社交类软件。所以在 Beeto 产品诞生之前,就瞄准了「中东互联网成熟、渗透率高,但本地化少」的方向,并开启了专注「本地化特色」的产品准备。
Beeto 在中东其实对标的是 Twitter 和 Facebook 这种 Feed 流应用,所以在业务架构的部署上一开始就规划好了相对完整的框架。比如满足社交属性的关系互动、内容消费(图文、视频直播、同城广告等),还有金融类和服务类的打赏、提现、投票和抽奖等等各种业务,甚至包括平台侧的监管、内容安全审核等要求。
在前文我们也提到过,中东市场的互联网成熟度势必对一个产品的发布有着高质量的要求,所以想要切实打入中东市场,不可能先做一个简单功能的应用直接上线。
所以 Beeto 的第一版业务架构就是一个完整,并且符合主流社交软件应该具备的各种功能集一身的产品。同时 Beeto 的目标也很明确,就是要用「本地化特色」成为中东地区最大的阿拉伯语社交平台和最好的阿拉伯语社区。
Beeto 架构设计中的痛点
Beeto 产品要走本地化模式,除了在业务层面要满足当地现有的社交需求外,在技术层面也需要做一些本地化操作,比如服务部署和数据存储等都要要本地化。熟悉微博或者 Twitter 的技术朋友应该都知道,想要实现这种庞大信息流产品的背后,其实是需要几十甚至上百个架构系统来协作完成的。
单体服务架构设计
目前 Beeto 产品的业务主要可划分为以上这些。这些业务的实现其实都需要在中东地区进行本地化部署。如果把每项业务按照服务进行拆分的话,那每个服务其实就是独立的单体架构。
上图展示的是一个很常见的部署架构。拿 Beeto 的 Feed 流服务来说,想要实现用户浏览 Feed 流需求,就必须要支持公网访问,即南北向流量的访问;同时 Feed 流服务还会提供一些类似话题业务等形式的内部调用,即东西向流量调用。所以整体的服务属性是明确支持外部和内部两种调用模式,用户流量经过七层负载均衡,分配到不同的服务器再调用不同的存储资源,东西向也类似。整个七层集群负责处理南北和东西向流量,进行负载均衡、安全认证和节点监控。
当把多项业务的的服务组合在一起时,就会形成如下所示的整体架构:
可以看到,无论是适配层、业务层还是基础服务层,都存在着若干服务。每项服务的部署架构都拥有前文提到的单体架构细节,所以中间就会存在着若干个七层集群,这其实已经是一套非常庞大且复杂的系统架构了。
但由于目前 Beeto 产品还处于创业阶段,尤其是产品本身在中东本土落地,而研发人员在中国的情形,按照上述这个规模部署,需要投入非常大的服务器成本和维护成本。同时后期随着业务增加,单体服务的数量势必也会不断增加,不管在成本还是运维操作上都会变得更难控制。
多服务落地困难
除了上述提到的架构部署复杂外,其实在集群内部服务之间的调用也是非常复杂的。
南北向流量分散到各个服务池,东西向流量也交错在各个服务之间,这些服务的调用关系之间错综相交。对每一套服务而言都需要去维护这些调用关系,从而导致调用链路不清晰且不好管理。
除了调用关系复杂外,每个服务之间还存在技术栈的差异。比如在调用协议上,有些服务提供的是 HTTP,有些则是 RPC;而在开发语言上,则会出现 Java、Go 等多语言混合的情况。
从上述这些细节就可以看出,这样的多服务架构体系在进行本地落地时,就会很明显地暴露出部署与维护成本高的问题,同时每套七层服务都需要投入服务器成本,而各个服务的流量差异又会导致流量不均衡,从而导致服务器等资源利用率低,造成资源浪费。
由于目前 Beeto 的成本重点放在了业务升级与迭代上,所以在架构设计上更倾向于便于维护和统一管理,那么如何实现这个目标呢?
APISIX 网关为 Beeto 架构助力
为了解决服务管理不便与成本投入大的痛点,同时得益于 APISIX 配合 etcd 的动态表现更符合 Beeto 的产品需求,所以在架构部署中引入了 APISIX 作为网关,并搭建了网关集群,如下图所示。
网关集群对所有的服务都提供了注册中心、服务控制、服务监控、协议转发和应用插件等扩展工具。各个服务的集群都可以统一在网关进行注册,新服务上下线也都可以直接通过网关来完成。
同时引入网关后,整个集群的调用链路也变得非常清晰。南北向流量统一由网关进行路由转发,东西向流量由网关进行内网的服务转发。在功能层面,APISIX 负责统一维护这些流量所调用的认证,这样在网关层就能够清晰了解到各服务之间的性能差异和流量差异等信息。
总结来说,引入 APISIX 网关做架构整合之后:
- 解决了南北向和东西向流量统一的问题,节省了资源和人力成本,实现动态统一管理;
- 业务服务的部署架构重点在服务本身,从而实现网关独立存在和业务无感;
- 通过扩展插件,各服务的权限验证、路由分发和健康检查等功能均由网关托管;
- 新业务上线与服务迁移都可以动态完成,对运维十分友好。
当然,由于在此架构中,网关承载了所有的流量,后期随着服务的不断扩张,服务数量也会增加,届时网关的维护成本也会增大,就会需要考虑新的应对方案。但在目前背景下,该方案仍是最优选择。
应用 APISIX 后的业务实践
Apache APISIX 作为网关可以在网关层统一处理多种策略,比如安全认证、服务转发和健康检查等。因此 Beeto 在引入 APISIX 后,在业务实践层面也做了很多尝试。
安全性:认证插件
南北向流量-Cookie
我们前面讲了公网用户的访问流量统一经过网关。而对于公网用户的认证,则是基于 Cookie 认证的用户请求。当用户请求携带 Cookie 到达网关时,在网关上通过认证插件对其进行验证。
如上方流程图所示,插件内部会先进行本地化验证,然后根据策略进行远端服务的认证校验。当请求完成 Cookie 校验后,再转发到指定的服务上。
这样做的优势主要体现在两方面:
- 确保了用户 Cookie 的信息安全。因为 Cookie 属于敏感数据,在执行过程中确保只有网关层能够接收并进行处理,其他业务层均不能接触。防止业务处理规则不一致而导致的安全问题,也有效避免了人为因素和不规范问题导致的 Cookie 泄露等安全问题。
- 降低了各个服务 Cookie 认证的复杂性。前文提到了 Cookie 在过程中需要进行本地验证或远端验证,同时 Cookie 升级时,各个服务也都需要同步升级。通过网关进行统一管理与校验,在业务服务的处理上就省去了校验成本,只需关注结果,利用结果进行业务规则处理,从而保证各个业务处理更聚焦于业务本身。
东西向流量-Token
像下图中的 A 服务调用 B 服务的操作,通常来讲互相调用时只需提供一个 API 即可完成。但是在内部流程中,需要去了解「API 被谁调用了、通过什么方式调用的、是否需要进行权限校验,是否需要对调研方进行控制」等这些问题,都是需要内部去处理的。
有了 APISIX 网关之后,流程就变得简单很多。所有内部服务的互相调用只需在 Auth 认证服务上进行注册,给每个服务颁发 App key ,用来表明服务的身份 ID。同时内部服务互相调用也会经过网关,携带 Token 经过网关后,网关会通过 Token 插件进行 Token 认证。认证通过后会将认证标识传递给被调用的服务,整个过程中服务统一进行认证注册,完成互相调用。
得益于 App key 的 Token 规则,上述操作便于追溯调用来源,从而进行问题排查和权限控制,对非法调用也起到了有效的控制。
所以无论是南北向流量还是东西向流量的认证,统一认证的优势就是保证了集群的安全性与统一性,在问题排查溯源和调用控制等方面都有很大的帮助。
伸缩性:无状态服务扩容迁移
目前 Beeto 的集群整体部署架构是从上到下是按照 APISIX 网关集群-无状态服务的业务服务集群-有状态服务的数据中心集群组成。在中东本地落地部署时,都是部署在各大云集群上的。按照中东地区的云覆盖规模和不同地区的云厂商,在进行服务部署时就需要考虑云服务的扩容和迁移问题。
在迁移的过程中,Beeto 重点关注在无状态服务的迁移。因为数据中心的迁移成本,决定了它不适合适合做动态调整;同时大部分请求压力都是由无状态服务来承载的,所以保证无状态服务具有一个良好的伸缩性是非常重要的前提。
在 Beeto 的架构中,服务伸缩性主要体现在两个方面,即单体服务伸缩性和整体集群伸缩性。比如某个单体服务出现资源不够,需要进行扩容操作时,利用 APISIX 网关就可以进行动态节点添加实现扩容。同样在跨集群或者跨云情况下,可以通过部署多个 APISIX 网关,将不同的服务迁移到不同的网关节点下实现集群伸缩性。
对于业务服务来说,整体架构没有变化,就可以在网关层实现对各个服务的动态扩缩容、服务迁移等。整个过程的方案和目标都很明确,一旦涉及变更,也不会造成整体架构的不稳定。
功能扩展性:业务动态转发
除了上述这些耳熟能详的网关通用场景实践外,Apache APISIX 为 Beeto 的业务动态转发层面也提供了非常大的帮助。
熟悉 APP 端 UI 和后端的朋友应该都知道,不同的产品页面是由不同的服务提供。一个页面是由不同模块组成的,其中的内容全部由接口下发。接口下发什么模块的数据,端上就渲染成什么样。这是一种联合客户端的渲染规范,目的是让客户端的渲染过程更通用,业务处理更灵活。
比如上图 PageA 的实现,就是客户端调用了服务 A 的接口,下发对应模块数据,完成 PageA 的渲染。这种操作会出现一个问题,客户端需要去维护每一个页面,对接每一个服务的接口。如果内容出现变更,就需要进行发版解决,操作性和效率体现上都很不友好。
解决上述问题的主要思路就是在整体架构上实现服务的统一分发。即客户端首先统一请求接口地址,将这一类的所有请求都转发到一个接口,在网关层对 URL 地址进行请求参数和 URL 规则的处理,然后引入分发插件。最后按照配置规则,将解析后的请求在网关层直接将请求转发到指定的服务上去。
整个过程客户端只需确定渲染规范,无需关心数据来源。网关层承担了业务分发的职责,直接将流量进行转发。同时 APISIX 中的插件配置文件可以做到动态实时更新,转发规则也可以动态调整,十分灵活。其实类似像 BFF(Backend for Frontend) 架构的应用,这种需求都可以网关层进行解决。
总结
本文从 Beeto 的产品设计视角,呈现了 Beeto 引入 Apache APISIX 网关后的设计思路和与业务层面的一些应用实践。有了 APISIX 网关的加持,在控制资源成本与业务产品线多的前提下,也帮助 Beeto 实现了中东本地化部署、统一管理及运维友好的场景。