背景
雪球成立于 2010 年,起步于投资社区,现已成为国内当先的集投资、交换和交易为一体的在线治理平台,为投资者提供优质内容、实时行情、交易工具、财产治理等多种服务。
其中实时行情服务对接了多种上游数据源,通过数据流式计算、存储与散发,为投资者提供稳固的数据服务。所以实时行情始终是雪球业务零碎中的资源耗费小户,继续在高水位运行。雪球外部一项重要的工作就是继续进行稳定性建设,其中包含对行情服务进行性能优化。即便如此,在偶尔产生极其行情的状况下,局部零碎仍会因为数据量激增而产生响应变慢,甚至是不可用的状况,从而影响用户体验。
在此背景下,雪球为了向宽广投资者提供稳固优质的服务,启动了服务双活革新打算。Apache APISIX 能极大地简化双活架构的施行复杂度。同时 APISIX 本身的云原生性能个性、丰盛的社区生态和插件等,也为雪球将来云原生架构的演进打下了良好基础。本文将介绍雪球公司是如何借助 Apache APISIX 实现外部双活架构的演进。
上图是雪球单机房期间的简略架构形容,用户流量从云端入口(SLB)进来后,经网关进行简略的公共性逻辑解决,向后端服务转发。后端服务会通过 SDK 的形式,由集成在服务中的鉴权模块向雪球用户核心发动用户鉴权,通过后则持续进行后续的业务解决。
双活革新痛点
在实际业务场景中,该架构下一些痛点也开始逐步浮现。
- SDK 鉴权模块简单
在双活革新施行过程中,微服务的提供方和生产方无奈齐全同步进行部署上线。当行情服务首先在云端上线,而雪球用户核心还不具备云端服务能力时,便会呈现跨机房调用的状况。依据用户核心统计,其 RPC 调用量日均约数十亿,峰值可达到 50K QPS,在行情高的 QPS 场景下会带来较高提早。
同时雪球鉴权业务复杂度较高,除 OAuth2.0 / JWT 协定外,还须要兼顾客户端版本、雪球旗下多个 APP 等多种因素。因为鉴权模块嵌入了服务内,导致降级也变得较为艰难。
- OpenResty 功能性稍有有余
雪球在之前始终将 OpenResty 作为网关,其本身功能性上略有有余。所以将 OpenResty 集成雪球现有监控体系时,仍须要肯定的工作量;同时扩大流程繁琐,还须要运维侧去增加自定义脚本进行实现。
- 依赖自研注册核心
目前雪球的 HTTP 服务注册是在后端服务启动时,申请注册核心将本身注册到网关,服务进行时申请注册核心进行服务节点摘除,注册核心会定期轮询服务节点进行健康检查。但自研的服务相比开源我的项目而言,保护老本较高。
API 网关选型
所以在这些痛点之上,雪球外部心愿在不引入过多变量的同时,尽量保障对业务方通明以及最小化改变;能够将问题在基础设施层面进行对立解决,并且尽量将鉴权服务在本机房实现。综上思考,雪球决定将鉴权服务移至 API 网关进行实现。
基于在业务实际场景中逐步浮现的痛点,雪球基础设施团队开始了针对网关产品的调研。通过外部诉求和目前市场中网关产品的比照,最终抉择了基于 Apache APISIX 进行后续架构的调整与应用。
基于 Apache APISIX 的实际
调整后架构
如上图是目前雪球行情双活架构。左侧展现的是在原机房里对应的架构,并没有进行太多改变;右侧展现的则是上云之后基于多 Region 设计的多活架构。
上述架构次要基于 APISIX 进行了如下调整:
- 将鉴权模块对立调整到代理层,利用 APISIX 进行对立鉴权形式。其中波及到 JWT 类型的能够间接利用 APISIX
jwt-auth
插件进行本地鉴权; - 兼容 OAuth 2.0 模式,利用 APISIX 对立调用雪球用户核心进行解决;
- 对接雪球后端 RPC 服务注册核心,用于 JWT 鉴权失败时应用雪球后端服务来鉴权。
利用场景展现
在后端服务接入 APISIX 后,次要在网关鉴权和可观测性等层面进行了一些实际。
场景一:网关鉴权
在前文中提到过,雪球之前架构模式中的鉴权形式并不对立。一种须要依赖于外部的利用端,通过 SDK 模式去调用用户核心实现鉴权,另一种则应用 JWT 鉴权。当两种鉴权形式共存时,会带来扩展性和维护性较差的问题。
接入 APISIX 作为网关之后,在鉴权计划的革新上则是通过 APISIX 网关层来对立治理。基于官网插件 jwt-auth
去代替原有的 JWT 鉴权形式;同时联合雪球外部本身的业务要求,应用 APISIX grpc-transcode
插件代理调用鉴权服务,来解决之前 OAuth 2.0 相干的鉴权形式。
jwt-auth
插件的配置应用较为简单,在 Dashboard 中将路由和上下游等相干信息配置齐全即可开启应用。这里次要形容下雪球外部是如何利用 APISIX 调用 gRPC 来实现鉴权。
在实现调用之前,雪球外部思考了以下三种解决方案:
- 计划一:Lua 间接调用 gRPC。因为此计划在执行中,须要去思考负载平衡和动静上游等相干实现,过程会比拟麻烦,故舍弃。
- 计划二:Lua 协程回调 Golang。因为公司外部不足相应的实践经验,不可妄自尝试,故舍弃。
- 计划三:Lua 进行 HTTP 调用,gRPC 接口采纳 APISIX 的
grpc-transcode
插件进行实现。得益于 APISIX 社区对插件优化迭代快的前提,最终抉择了计划三去实现 gRPC 调用。
在执行过程中,目前仍须要对 protocol buffers 文件进行手动同步。因为如果用户核心批改了该 protocol buffers 文件,然而与 APISIX 保留的 protocol buffers 文件不统一的话,会导致鉴权呈现问题。
场景二:可观测性下的多维监控
雪球的日常应用场景中,通常在网站上线后是须要监控很多指标的,重点次要是以下三局部:
- NGINX 连贯状态和进出口流量
- HTTP 谬误状态码速率(用于排查 Service 或上下游问题)
- APISIX 申请提早耗时(APISIX 进行转发时逻辑执行带来的耗时)
比方 APISIX 的提早指标会在某些状况下,呈现指标十分高的景象(如下图所示),这种其实是跟该提早指标的计算逻辑无关。目前 APISIX 提早指标的计算逻辑是:单条 HTTP 申请在 NGINX 上的耗时工夫 - 这条申请路由到上游的提早。两个耗时之间的差数值即为 APISIX 提早指标数据。
应用 APISIX 后,在新增或批改一些插件时会导致一些逻辑的变更,变更之后可能会导致耗时相干的数据呈现偏差。为了避免出现混同数据真实性的景象产生,雪球在监控层面还减少了基于插件级别的耗时监控。在保障各数据监测的准确性下,还不便了后续进行插件级的业务革新时,提前通过耗时定位一些问题,从而不便排查。
同时能够利用 APISIX 的可观测性能力,收集 Access 日志信息,并通过格式化对立投递到流量大盘中进行视图汇总。更不便地从多角度提前理解整体趋势,发现潜在问题并及时进行解决。
场景三:扩大 ZooKeeper 注册核心
目前,雪球 gRPC 服务调用是基于 Zookeeper 注册核心进行注册和发现。在实现鉴权过程中,API 网关在本地 JWT 校验失败时,须要拜访雪球用户核心的 gRPC 服务进行鉴权,这就要求 API 网关可能从注册核心获取后端 gRPC 服务地址列表。APISIX 官网插件 apisix-seed
能够去集成 ZooKeeper 进行服务发现,但联合雪球本身应用场景需要,在 APISIX 上则是进行了更针对自家业务的相干拓展。
具体实现次要是在 APISIX 的一个内容节点上,当 Worker 过程启动时去轮询像下图中的 ZK-Rest 集群,而后定时去拉取整个服务的源数据信息以及理论信息,更新到 Worker 过程内的本地缓存,用于服务列表的更新。
通过上图也能够看到,ZK-Rest 集群相当于通过 Rest 的模式进行拜访 ZooKeeper 的数据。所以整个过程其实实现的性能比拟少(次要是基于本身业务场景需要),只须要减少它的一个实例就能够实现高可用个性,免去一些简单操作。
但这样操作也会带来一个比拟显著的毛病。当须要定时去轮询 ZK-Rest 集群时,可能会导致服务列表在更新上呈现提早。所以这里也是提供给大家一个思路,仅供参考。
总结及瞻望
目前,Apache APISIX 在雪球外部作为网关层运行良好。具体表现在:
- 实现了在网关层对立鉴权、熔断与限流等性能;
- 升高了整体零碎的耦合度,进步了双机房场景下的服务质量;
- 借助于 APISIX 监控体系,欠缺了从网关到服务的对立监控计划;
- 对全链路排查起到了很好的撑持;
- 对 gRPC 协定的转换与服务治理都提供了比拟优雅的实现形式。
在后续的应用中,雪球也在布局如下过程:
- 应用 APISIX Ingress Controller 利用于 K8s 集群;
- 利用 grpc-transcode 插件进行 HTTP/gRPC 协定转换,达到后端对立接口模式;
- 利用
traffic-spilt
插件进行流量打标、对接 Nacos 注册核心,实现全链路灰度等服务治理。
并在后续打算中,用 Apache APISIX 去代替现有的 OpenResty,最终实现全域南北流量的治理。