猪八戒网随着业务访问量的直线增长,用户增长达到一定规模后,同时面临着高并发业务和海量数据的挑战,传统单机房在服务器容量上存在瓶颈,而且在一些不可预知场景下,导致整个网站出现故障,例如机房断电、火灾等这些不可抗拒因素都会导致所有服务器出现宕机从而导致业务瘫痪,即使有备份,恢复业务花费的时间也比较长。所以公司根据实际业务情况选择了同城双活流量高可用架构,当然还有两地三中心、异地多活等方案。本文主要基于同城双活流量叙述猪八戒网这 16 年的双活流量架构演进之路。
初期
2014 年前猪八戒网的服务器都是托管于传统 IDC 机房,虽然业务应用、基础组件、数据库等都设计了高可用模式,但是避免不了机房宕机导致整个网站出现故障的问题。如图 1:
图 1:单点机房
直到 2015 年初的时候,由于机房人员日常维护的时候,不小心把我们的核心交换机网线碰松了,然后导致整个猪八戒网打不开,我们通过各种排错才定位到这个问题,经过此事件后,上层领导高度重视网站的可用性问题,为了解决机房不可控的因素,所以 2015 年中旬开始建设备用机房,解决机房单点问题。(注:当时基础组件及业务应用不具备双活条件,只支持主备架构模式)如图 2
优点:
·主机房发生故障时,通过 DNS 解析到备用机房,解决机房单点故障问题;
·主备架构模式简单,持久化数据异步同步到备用机房,不用考虑脑裂问题。
缺点:
·由于备用机房平时处于空闲状态,造成大量资源浪费问题。
图 2:同城主备
中期
经过 1-2 年的迭代,大概在 2017 年的时候,随着基础组件的升级改造,例如:数据库、缓存、队列、对象存储、配置中心等都支持了双活流量架构模式,然后业务应用纷纷改造适配双活流量架构模式。终于我们可以把网站域名同时解析到 2 个机房了。如图 3:
图 3:同城双活(基于 DNS 的双活)
基于 DNS 切换流量模式还是有瑕疵的,在猪八戒网运行了 3 年左右,在此期间多次出现某机房不稳定事件进行全局流量切换,主要问题体现在某些 DNS 服务器不跟着协议走,导致切换流量生效时间慢,流量切换不彻底的问题。
提示:一般情况我们遇到的单个机房故障,主要体现在基础组件、业务大面积瘫痪等问题上,不涉及到入网流量的问题,假如真的是入网流量异常了,也只有等 DNS 解析生效了。
鉴于以上遇到的问题,我们换个思路解决如何快速切换流量,最终方案是在 HTTPS 层的 Nginx(ngx_lua)代理服务器实现快速动态分流的功能(项目为:Signpost),为什么采用 ngx_lua?因为 ngx_lua 在猪八戒网稳定运行 5 年+,不管是开发效率及性能,Lua 有着天然的优势,语言表达能力也更强,而且 ngx_lua 是同步非阻塞(100% non-blocking)的,再次感谢章亦春 (agentzh)大佬的开源作品 lua-nginx-module。如图 4:
图 4:HTTPS 代理层分流
如何基于 ngx_lua 设计动态分流功能呢?简单通俗一点就是如何快速动态切换 nginx 的 upstream 进行分流而不执行 nginx reload。关于 Upstream 是如何动态生成的?请查阅上篇:【技术分享】猪八戒网Nginx的动态服务发现演进之路
首先管理人员配置分流策略到 CMDB 系统中,然后 CMDB 同步到 Redis 缓存,当用户请求时,Nginx 接受到请求后,先从 worker 缓存获取分流策略,如果 worker 缓存没有,就到 lua_shared_dict 缓存获取,如果 lua_shared_dict 也没有,那就到 Redis 中读取,然后依次缓存,根据匹配的分流策略执行指令。假如没有获取到分流策略,那就按照默认策略分流。如图 5:
图 5:动态切换 Upstream 架构
为什么会有三级缓存?因为 worker 缓存支持数据结构缓存,而且没有锁竞争,lua_shared_dict 缓存有锁竞争,不支持数据结构存储,Redis 缓存需要 TCP 连接消耗,最终都是为了性能!
现在
经历了数月的开发及基础架构改造,终于在 2020 年 9 月初,基于 HTTPS 层的 Nginx(ngx_lua)快速动态分流的功能成功上线了,主要支持了全局模式、单域名模式的流量切换,还额外支持了域名动态 HTTP/HTTPS 协议切换。如图 6 - 9:
图 6:同城双活(基于 NGX_LUA 的 Signpost)
图 7:双活流量控制台
图 8:单域名切换功能
图 9:单域名切换日志
最后,关于 Signpost 软件的主要特性,支持多活流量管理,根据不同维度进行分流,例如:IP 段、地区、Cookie、浏览器、GET 参数等,流量切换可以精确到秒级,而且全程用户零感知。
希望以上内容能对有需要的人有所帮助
欢迎大家一起探讨交流