写点什么

雪球基于 Apache APISIX 的双活架构演进

  • 2022-06-08
  • 本文字数:3368 字

    阅读完需:约 11 分钟

雪球基于Apache APISIX的双活架构演进

本文整理自雪球基础组件团队在 Apache APISIX Summit ASIA 2022 上的分享。更多技术干货,详见内容专题

背景


雪球成立于 2010 年,起步于投资社区,现已成为国内领先的集投资、交流和交易为一体的在线管理平台,为投资者提供优质内容、实时行情、交易工具、财富管理等多种服务。


其中实时行情服务对接了多种上游数据源,通过数据流式计算、存储与分发,为投资者提供稳定的数据服务。所以实时行情一直是雪球业务系统中的资源消耗大户,持续在高水位运行。雪球内部一项重要的工作就是持续进行稳定性建设,其中包括对行情服务进行性能优化。即便如此,在偶然发生极端行情的情况下,部分系统仍会因为数据量激增而发生响应变慢,甚至是不可用的情况,从而影响用户体验。


在此背景下,雪球为了向广大投资者提供稳定优质的服务,启动了服务双活改造计划。Apache APISIX 能极大地简化双活架构的实施复杂度。同时 APISIX 自身的云原生功能特性、丰富的社区生态和插件等,也为雪球未来云原生架构的演进打下了良好基础。本文将介绍雪球公司如何借助 Apache APISIX 实现内部双活架构的演进。



 上图是雪球单机房时期的简单架构描述,用户流量从云端入口(SLB)进来后,经网关进行简单的公共性逻辑处理,向后端服务转发。后端服务会通过 SDK 的方式,由集成在服务中的鉴权模块向雪球用户中心发起用户鉴权,通过后则继续进行后续的业务处理。

双活改造痛点


在实践业务场景中,该架构下一些痛点也开始逐渐显现。


  1. SDK 鉴权模块复杂

在双活改造实施过程中,微服务的提供方和消费方无法完全同步进行部署上线。当行情服务首先在云端上线,而雪球用户中心还不具备云端服务能力时,便会出现跨机房调用的情况。根据用户中心统计,其 RPC 调用量日均约数十亿,峰值可达到 50K QPS,在行情高的 QPS 场景下会带来较高延迟。


同时雪球鉴权业务复杂度较高,除 OAuth2.0 / JWT 协议外,还需要兼顾客户端版本、雪球旗下多个 APP 等多种因素。由于鉴权模块嵌入了服务内,导致升级也变得较为困难。


  1. OpenResty 功能性稍有不足


雪球在之前一直将 OpenResty 作为网关,其自身功能性上略有不足。所以将 OpenResty 集成雪球现有监控体系时,仍需要一定的工作量;同时扩展流程繁琐,还需要运维侧去添加自定义脚本进行实现。


  1. 依赖自研注册中心


目前雪球的 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,最终实现全域南北流量的管理。

2022-06-08 10:153898

评论

发布
暂无评论
发现更多内容

行业分析| 为什么uni-app在音视频领域这么火?

anyRTC开发者

uni-app 音视频 移动开发 语音通话 视频通话

为何每次用完ThreadLocal都要调用remove()?

热爱java的分享家

Java 程序人生 编程语言 经验分享

帧彩视界之Pseudo HDR:为普通SDR设备用户提供HDR体验

微帧Visionular

视频编码 HDR

艾媒报告:百度输入法AI功能领跑行业 用户满意度第一

百度开发者中心

百度 AI

Alibaba最新神作!耗时182天肝出来1015页分布式全栈手册太香了

热爱java的分享家

Java 面试 分布式 编程语言 经验分享

pringBoot + Mybatis Plus + ClickHouse增删改查入门教程

程序员万金游

MySQL 数据库 mybatis Clickhouse

多商户入驻系统开发多商户入驻app源码开发

风行无疆

掌握Java的内存模型,你就是解决并发问题最靓的仔

华为云开发者联盟

Java 内存模型 线程 并发 工作内存

你的web知识有所欠缺。

喀拉峻

Web 安全

外卖跑腿系统专业开发外卖跑腿app源码开发

风行无疆

秋招拿到offer之后,分享面试阿里、头条、腾讯的经过以及一些总结

Geek_1df311

Java 编程 程序员 架构 面试

如何修复org/jacoco/agent/rt/internal_773e439/Offline异常?

Changing Lin

11月日更

论文解读丨无参数的注意力模块SimAm

华为云开发者联盟

卷积神经网络 视觉 注意力模块 SimAm 神经元

CSS布局(四)之文本布局

Augus

CSS 11月日更

DAS易用性设计

赫杰辉

TypeScript 之 Typeof Type Operator

冴羽

JavaScript typescript html5 翻译 大前端

Go语言学习查缺补漏ing Day6

Regan Yue

Go 语言 11月日更

优秀!阿里甩出GC面试小册,仅7天Github获赞96.9K

热爱java的分享家

Java 架构 程序人生 编程语言 经验分享

在牛客逮到一个阿里10年老Java开发,聊过之后收益良多...

Geek_1df311

Java 编程 架构 面试 计算机

Pulsar 分级存储 -- S3 演示

Apache Pulsar

大数据 架构 云原生 分布式存储 Apache Pulsar

元气部落盲盒软件原生开发芒趣盲盒app源码

风行无疆

会声会影编辑面板常用功能介绍

懒得勤快

Micro Focus Fortify 最新能力发布,应用安全进入“一切皆代码”新时代

趣谈哈希表优化:从规避 Hash 冲突到利⽤ Hash 冲突

热爱java的分享家

Java 架构 编程语言 经验分享 哈希表

24 K8S之Service资源及其模型

穿过生命散发芬芳

k8s 11月日更

彻底搞懂访问者模式的静态、动态和伪动态分派

Tom弹架构

Java 架构 设计模式

工具 | 一条 SQL 实现 PostgreSQL 数据找回

RadonDB

数据库 postgresql RadonDB

分区丢失导致文件丢失?巧用EasyreCovery找回!

淋雨

数据恢复

又一次漏洞复现与分析

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 漏洞挖掘

干货必收藏!墨天轮最受DBA欢迎的250份学习文档合集

墨天轮

MySQL 数据库 oracle postgresql

Function Mesh:Serverless 在消息与流数据场景下的火花

Apache Pulsar

大数据 架构 云原生 Apache Pulsar pulsar社区

雪球基于Apache APISIX的双活架构演进_架构_雪球基础组件团队_InfoQ精选文章