前文链接
高可用系列文章之一 - 概述 - 东风微鸣技术博客 (ewhisper.cn)
三 技术方案
3.1 概述
单点是系统高可用最大的风险和敌人,应该尽量在系统设计的过程中避免单点。
保障系统的高可用, 方法论上,高可用保证的原则是「集群化」(或 「冗余」), 只有一个单点,该单点宕机所有服务都会受影响而不可用;如果有冗余或备份,其中一个点宕机还有其他冗余或备份节点能够提供服务。
保证系统高可用,架构设计的核心准则是:冗余。
有了冗余之后,还不够,每次出现故障需要人工介入恢复势必会增加系统的 MTTR。所以,又往往是通过「自动故障转移」来实现系统的高可用。
在下面的技术方案中,详细介绍了如何通过冗余+自动故障转移来保证系统的高可用特性。
3.2 制造业系统的典型架构
制造业系统一般采用分层架构, 最简单的典型架构的展示如下:
ℹ️ 备注:
数据库以 MySQL 为例.
常见的系统架构如上, 分为:
- 客户端层: 典型调用方式浏览器(browser) 和客户端(client)
-
应用服务层: 实现核心应用逻辑, 通常是 HTTP 协议或 TCP 协议. 这一层细分, 往往还包括:
- 表示层: 主要是 web 浏览页面;
- 业务逻辑层: 对具体问题进行逻辑判断和执行操作, 同时也是表示层和数据层的桥梁
- 可选: 服务层: 如果实现了服务化, 如 SOA 或微服务化, 就会有这一层;
- 数据访问层: 实现对数据的增删改查等操作, 并将结果反馈到业务逻辑层
- 可选: 数据缓存层: 缓存加速访问存储
- 数据库层: 数据库固话数据存储.
整个系统的高可用, 是通过对每一层的冗余+自动故障转移来综合实现的.
ℹ️ 备注:
通过更加细化和细致的分层, 也可以提高可用性. 如将以上架构细化为:
- 客户端层;
- 可选新增: 反向代理层
- 可选新增: 表示层(Web Server)层
- 应用服务层(App Server)层
- 可选新增: 服务调用层
- 可选新增: 缓存层
- 数据库层
本文暂不涉及这一内容.
3.3 制造业系统的推荐高可用架构
通过冗余这一核心原则, 优化后的高可用架构如下图所示:
ℹ️ 说明:
- 实线 : 请求调用
- 点+横线: 心跳检测
- 点虚线: 尚未真实发生的请求调用
- 短横虚线: 数据库主从同步
- "X" - 对应节点宕机不可用.
高可用方案调整说明如下:
- 在客户端层和应用服务层之间, 新增: 负载均衡层. 负责将客户端请求通过某种负载均衡方式科学地负载到应用服务外层;
-
负载均衡层: 这一层包含以下2个组件:
- NGINX: 负责 TCP/HTTP 请求的负载反向代理/负载均衡;
- Keepalived: 负责对外提供单个 IP, 且对 2 台 NGINX 进行心跳检测和故障时的故障转移;
- 应用服务层: 应用服务器至少为 2 个.
- 数据库层: 数据库进行主从同步, 读写分离
ℹ️ 备注:
上图中, 也画出了高可用的另一种实施方案, 本文不做详细讨论:
- 应用横向拆分: 单体应用(monolithic application)根据重要性进行拆分, 将重要性高的服务和重要性低的服务进行拆分, 单独部署.
- 重要性高的应用, 如低延迟类应用, 流水线上应用等;
- 重要性低的应用, 如高延迟类应用, 报表应用等.
除此之外, 还可以根据实际业务情况进一步将数据库进行拆分, 本文亦不做详细讨论:
- 数据库拆为 2 个库, 其中一个库通过数据同步从另一个库定时(实时或非实时)同步数据. 举例说明: 业务库, 报表库. (业务库定期同步数据给报表库)
- 重要性高的应用, 读取写入业务库;
- 重要性低的应用. 如报表类应用. 不允许使用业务库, 而是使用报表库.
下面逐一进行分层论述.
3.4 客户端层 -> 负载均衡层 高可用
客户端层 到 负载均衡层 高可用, 通过负载均衡层的冗余来实现的. 具体实现方式如下:
至少有 2 台 nginx, 其中一台提供服务, 另一台冗余以保证高可用. 并通过 Keepalived 的 virtual IP 来提供同一 IP(如上图为: 1.2.5.6), 通过心跳探测来进行故障检测和故障转移.
在上图中, NGINX 主节点提供对外服务.
当 NGINX 主节点(如: 192.168.0.1)发生宕机, Keepalived 能够探测到, 会自动进行故障转移, 将流量自动转移到 NGINX 从节点(如: 192.168.0.2). 由于使用的是相同的 virtual IP(仍为: 1.2.5.6), 这个切换过程对调用方是透明的.
3.5 负载均衡层 -> 应用服务层高可用
负载均衡层 到 应用服务层 的高可用, 是通过应用服务层的冗余来实现的. 在NGINX的配置文件 nginx.conf
中, 可以通过 upstream
指令配置多个应用服务器, 并且 nginx 能够探测到多个应用服务器的存活性.
ℹ️ 知识点:
在 NGINX 开源版本中, 如果不使用第三方插件,NGINX 的存活探测为: 被动探测.
当应用服务层 其中一个节点宕机的时候, nginx 能够探测到, 会自动进行故障转移, 不会将流量分发到发生故障的节点, 而是分发到其他的正常应用服务器节点, 整个过程由 NGINX 自动完成, 对调用方透明.
3.6 应用服务层 -> 数据库层高可用
数据库层建议采用「主从同步, 读写分离」架构. 数据库的高可用, 又可细分为: 「读库高可用」 和「写库高可用」 两类.
ℹ️ 备注:
由于制造业采用了多种数据库, 包括但不限于:
- Oracle
- SQL Server
- MySQL
不同数据库的高可用解决方案并不完全相同, 所以本文不对数据库的具体高可用技术做细节描述. 只进行理论论述.(以 MySQL 为例)
常见的数据库高可用方案有:
- MySQL: 主从同步;
- Oracle: RAC
- SQL Server: Alwayon
3.6.1 读库高可用
读库高可用, 是通过读库的冗余来实现的.
如果要对读库实现高可用, 一般来说至少有 2 个从库, 数据库连接池会建立与读库的多个连接, 每次请求会路由到这些读库.
当读库 - 从1发生宕机的时候, 应用服务层的数据库连接池能够探测到, 会自动的进行故障转移, 将流量自动迁移到其他的读库, 如读库 - 从2, 整个过程由数据库连接池自动完成, 对调用方是透明的.
ℹ️ 备注:
需要应用系统或中间件的数据库连接层实现数据库连接池功能.
3.6.2 写库高可用
写库的高可用, 是通过写库的冗余来实现的.
以 MySQL 为例, 可以设置两个 MySQL 双主同步, 一台对线上提供服务, 另一台冗余以保证高可用.
3.7 技术选型
3.7.1 负载均衡器技术选型
✔️ 选型结果:
- 负载均衡器: NGINX + Keepalived
- 版本:
- NGINX: 1.16.1 (❗ 选型版本至少每半年评估一次, 根据评估结果对版本进行调整)
- Keepalived: 2.0.10(❗️ 选型版本至少每半年评估一次, 根据评估结果对版本进行调整)
- 操作系统类型: Linux
- 操作系统版本: SUSE 12 (按需调整,遵循制造业的相关技术规范要求.)
ℹ️ 定义及概述:
在分布式系统中,负载均衡(load balance)是一种有效的将网络请求分配到多个服务器的过程。通过将负载进行负载均衡,可以有效地改进系统响应时间,提高系统的可用性。随着系统变的愈发复杂,用户增多和网络流量增大,负载均衡已经成为系统设计中的必要一环。
负载均衡器可以是硬件也可以是软件,它会将网络请求分发到服务器集群上。
选型过程概述
常见的硬件负载均衡器包括:
- F5
- A10
常见的软件负载均衡器包括:
- Nginx
- LVS
- HAProxy
结合制造行业最佳实践, 以及制造业的实际情况考虑, 制造业在全国乃至全球拥有多座工厂, 每个工厂拥有独立的机房. 采用硬件负载均衡成本过高. 确定采用软件负载均衡器作为负载均衡技术实现. 下面对软件负载均衡器逐一进行论述:
NGINX:
Nginx("engine x")是一款是由俄罗斯的程序设计师 Igor Sysoev 所开发高性能的 Web 和 反向代理 服务器.
优点:
- 工作在网络的 4 层(TCP/UDP)和 7 层(HTTP/websocket),可以针对 http 应用做一些分流的策略,比如针对域名、目录结构,其正则规则比 HAProxy 更为强大和灵活, 同时 NGINX 目前是使用最广泛的负载均衡器和 Web Server,适用场景丰富.
- Nginx 对网络稳定性的依赖非常小,理论上能 ping 通就就能进行负载功能;相反 LVS 对网络稳定性依赖比较大;
- Nginx 安装和配置比较简单,测试起来比较方便,NGINX 拥有完善的且可自定义的日志, 包括 access 日志和 error 日志。LVS 的配置、测试需要花费比较长的时间。
- NGINX 可以承担高负载压力且稳定,在硬件不差的情况下很容易能支撑几万次的并发量。
- Nginx 可以通过端口检测到应用服务器的故障,如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点。如用户正在上传一个文件,而处理该上传的节点刚好在上传过程中出现故障,Nginx 会将上传切到另一台服务器重新处理,如果是 LVS就直接断掉了。
- Nginx 不仅仅是一款优秀的负载均衡器/反向代理软件,它同时也是功能强大的 Web 应用服务器。LNMP 也是近几年非常流行的 web 架构,在高流量的环境中稳定性也很好。
- Nginx 作为 Web 反向加速缓也比较成熟,速度比传统的 Squid 服务器更快,在未来场景用, 也可以扩展 NGINX 的用途。
- Nginx 可作为反向代理使用,作为反向代理, Nginx 使用最广泛, 同类产品还有 lighttpd 了,不过 lighttpd 目前还没有做到 Nginx 完全的功能,配置也不清晰易读,社区资料也远远没 Nginx 活跃。
- Nginx 也可作为静态网页和图片服务器,这方面的性能也无对手。
- Nginx 社区非常活跃,第三方模块也很多。
缺点:
- 对后端服务器的健康检查, 开源版 NGINX 支持持被动检测. 不支持主动检测.
- 对于负载均衡的会话保持, 开源版 NGINX 默认不支持cookie会话保持. 但是能通过
ip_hash
实现源地址会话保持, 且可以通过第三方模块实现cookie会话保持.
LVS:
LVS:使用 Linux 内核集群实现一个高性能、高可用的负载均衡服务器,它具有很好的可伸缩性(Scalability)、可靠性(Reliability)和可管理性(Manageability)。
优点:
- 抗负载能力强、是工作在网络 4 层之上仅作分发之用,没有流量的产生,这个特点也决定了它在负载均衡软件里的性能最强的,对内存和cpu 资源消耗比较低。
- 配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西,所以并不需要太多接触,大大减少了人为出错的几率。
- 工作稳定,因为其本身抗负载能力很强,自身有完整的双机热备方案,如 LVS+Keepalived。
- 无流量,LVS 只分发请求,而流量并不从它本身出去,这点保证了均衡器 IO 的性能不会收到大流量的影响。
- 应用范围比较广,因为 LVS 工作在 4 层,所以它几乎可以对所有应用做负载均衡,包括 http、数据库、在线聊天室等等。
缺点:
- 软件本身不支持正则表达式处理,不能做动静分离;而现在许多网站在这方面都有较强的需求,这个是 Nginx+Keepalived 的优势所在。
- 如果是网站应用比较庞大的话,LVS 实施起来比较复杂了,特别后面有 Windows Server 的机器的话,如果实施及配置还有维护过程就比较复杂了,相对而言,Nginx + Keepalived就简单多了。
HAProxy:
HAProxy 是一个使用 C 语言编写的*及开放源代码软件,其提供高可用性、负载均衡,以及基于 TCP 和 HTTP 的应用程序代理。
优点:
- HAProxy 支持虚拟主机。
- HAProxy 的优点能够补充 Nginx 的一些缺点,比如支持 Session 的保持,Cookie 的引导;同时支持通过获取指定的 url 来检测后端服务器的状态。
- HAProxy 跟 LVS类似,本身就只是一款负载均衡软件。
- HAProxy 支持 TCP 协议的负载均衡转发。
- HAProxy 负载均衡策略比较丰富
缺点:
- 不支持 POP/SMTP 协议
- 不支持 SPDY 协议
- 不支持 HTTP cache 功能。
- 重载配置的功能需要重启进程,虽然也是 soft restart,但没有 Nginx 的 reload 更为平滑和友好。
- 多进程模式支持不够好
选型结论:
LVS 试用场景单一, 且存在硬伤(即: 后面有Windows Server的机器的话, 实施比较复杂). 直接排除.
HAPorxy 针对 HTTP 的支持没有 NGINX 丰富, 且重启中断相对 NGINX 时间更长.
另外, nginx 除了当前可以用作负载均衡器之外, 还可以用作 web server, http 缓存等场景, 且容易上手.
最终确定选择 NGINX 作为某制造业公司负载均衡器.
3.7.2 NGINX高可用技术方案选型
NGINX 高可用技术方案只有一种, 即: NGINX + Keepalived 实现高可用.
keepalived
开源项目包括三个组成部分:
-
keepalived
Linux服务器的守护程序。 -
虚拟路由器冗余协议(VRRP)的实现,用于管理虚拟路由器(虚拟 IP 地址或 VIP)。
VRRP 确保始终存在一个主节点。备用节点侦听来自主节点的 VRRP 通告包。如果在超过配置的广播间隔的三倍的时间内未收到广播包,则备用节点将作为主节点接管,并将配置的 VIP 分配给自己。
-
一种运行状况检查工具,用于确定服务(例如,Web 服务器,PHP 后端或数据库服务器)是否已启动并且可以运行。
如果节点上的服务未通过配置的运行状况检查次数,
keepalived
则将虚拟 IP 地址从主(主动)节点重新分配给备用(被动)节点。
3.7.3 NGINX 负载均衡策略
✔️选型结果:
负载均衡策略: RR(轮询, 默认策略)
会话保持策略: (非必须)
- 不需要会话保持, 则不进行配置.
- 需要根据源地址进行会话保持:
ip_hash
NGINX负载均衡策略:
- 轮询调度算法: rr (默认调度算法).
- 加权循环调度算法: wrr. 适用场景: nginx服务器性能不相同, 性能高的需要负载更多请求.
- 最小的连接数:
least_conn
. - 会话保持策略:
- IP会话保持:
ip_hash
-
hash
- 指定服务器组的负载均衡方法,其中客户机-服务器映射基于hash 值。key可以包含文本、变量及其组合。
- IP会话保持:
选型过程:
负载均衡策略,根据实际情况按需选择,无特殊要求的情况下选择 rr 即可。
会话保持策略, 需要根据特定的场景进行选择:
- 不需要会话保持, 则不进行配置.
- 需要根据源地址进行会话保持:
ip_hash
- 需要进行
cookie
会话保持:sticky
- 源地址会话保持和
cookie
会话保持均无法满足需求, 则可能需要通过hash
来定制会话保持策略.
3.7.3 应用服务层 -> 数据库层高可用选型
略.
由于应用系统的多样性, 本文不对应用服务层 -> 数据库层高可用选型做约束. 仅提供顶层架构要求:
- 数据库: 主从同步, 读写分离
- 应用:
- 实现数据库连接池功能. 可以配置多个数据库连接.
- 根据应用功能模块的重要性进行横向拆封. 将: 报表, 数据统计, 批处理类功能与低延迟重要业务功能剥离开来.
参考文件
参考文件 |
---|
Availability - Wikipedia |
High Availability - Wikipedia |
system-design-primer - GitHub |
High Availability Support for NGINX |
Usage of web servers broken down by ranking |
三人行, 必有我师; 知识共享, 天下为公. 本文由东风微鸣技术博客 EWhisper.cn 编写.