- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
高可用系列文章之一 - 概述 - 东风微鸣技术博客 (ewhisper.cn) 。
单点是系统高可用最大的风险和敌人,应该尽量在系统设计的过程中避免单点.
保障系统的高可用, 方法论上,高可用保证的原则是「集群化」(或 「冗余」), 只有一个单点,该单点宕机所有服务都会受影响而不可用;如果有冗余或备份,其中一个点宕机还有其他冗余或备份节点能够提供服务.
保证系统高可用,架构设计的核心准则是:冗余.
有了冗余之后,还不够,每次出现故障需要人工介入恢复势必会增加系统的 MTTR。所以,又往往是通过「自动故障转移」来实现系统的高可用.
在下面的技术方案中,详细介绍了如何通过 冗余+自动故障转移 来保证系统的高可用特性.
制造业系统一般采用分层架构, 最简单的典型架构的展示如下
ℹ️ 备注
数据库以 MySQL 为例. 。
常见的系统架构如上, 分为
整个系统的高可用, 是通过对每一层的 冗余+自动故障转移 来综合实现的. 。
ℹ️ 备注
通过更加细化和细致的分层, 也可以提高 可用性 . 如将以上架构细化为
- 客户端层;
- 可选新增: 反向代理层
- 可选新增: 表示层(Web Server)层
- 应用服务层(App Server)层
- 可选新增: 服务调用层
- 可选新增: 缓存层
- 数据库层
本文暂不涉及这一内容. 。
通过 冗余 这一核心原则, 优化后的高可用架构如下图所示
ℹ️ 说明
- 实线 : 请求调用
- 点+横线 : 心跳检测
- 点虚线 : 尚未真实发生的请求调用
- 短横虚线 : 数据库主从同步
- "X" - 对应节点宕机不可用.
高可用方案调整说明如下
ℹ️ 备注
上图中, 也画出了高可用的另一种实施方案, 本文不做详细讨论
- 应用横向拆分: 单体应用(monolithic application)根据重要性进行拆分, 将重要性高的服务和重要性低的服务进行拆分, 单独部署.
- 重要性高的应用, 如低延迟类应用, 流水线上应用等;
- 重要性低的应用, 如高延迟类应用, 报表应用等.
除此之外, 还可以根据实际业务情况进一步将 数据库 进行拆分, 本文亦不做详细讨论
- 数据库拆为 2 个库, 其中一个库通过数据同步从另一个库定时(实时或非实时)同步数据. 举例说明: 业务库, 报表库. (业务库定期同步数据给报表库)
- 重要性高的应用, 读取写入业务库;
- 重要性低的应用. 如报表类应用. 不允许使用业务库, 而是使用报表库.
下面逐一进行分层论述. 。
客户端层 到 负载均衡层 高可用, 通过 负载均衡层 的冗余来实现的. 具体实现方式如下
至少有 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), 这个切换过程对调用方是透明的. 。
负载均衡层 到 应用服务层 的高可用, 是通过 应用服务层 的冗余来实现的. 在NGINX的配置文件 nginx.conf 中, 可以通过 upstream 指令配置多个应用服务器, 并且 nginx 能够探测到多个应用服务器的存活性. 。
ℹ️ 知识点
在 NGINX 开源版本中, 如果不使用第三方插件,NGINX 的存活探测为: 被动 探测. 。
当 应用服务层 其中一个节点宕机的时候, nginx 能够探测到, 会自动进行故障转移, 不会将流量分发到发生故障的节点, 而是分发到其他的正常应用服务器节点, 整个过程由 NGINX 自动完成, 对调用方透明. 。
数据库层建议采用「 主从同步, 读写分离 」架构. 数据库的高可用, 又可细分为: 「读库高可用」 和「写库高可用」 两类. 。
ℹ️ 备注
由于制造业采用了多种数据库, 包括但不限于
- Oracle
- SQL Server
- MySQL
不同数据库的高可用解决方案并不完全相同, 所以本文不对数据库的具体高可用技术做细节描述. 只进行理论论述.(以 MySQL 为例) 。
常见的数据库高可用方案有
- MySQL: 主从同步;
- Oracle: RAC
- SQL Server: Alwayon
读库高可用, 是通过读库的冗余来实现的. 。
如果要对读库实现高可用, 一般来说至少有 2 个从库, 数据库连接池会建立与读库的多个连接, 每次请求会路由到这些读库. 。
当读库 - 从1发生宕机的时候, 应用服务层的 数据库连接池 能够探测到, 会自动的进行故障转移, 将流量自动迁移到其他的读库, 如读库 - 从2, 整个过程由数据库连接池自动完成, 对调用方是透明的. 。
ℹ️ 备注
需要应用系统或中间件的数据库连接层实现 数据库连接池 功能. 。
写库的高可用, 是通过写库的冗余来实现的. 。
以 MySQL 为例, 可以设置两个 MySQL 双主同步, 一台对线上提供服务, 另一台冗余以保证高可用. 。
✔️ 选型结果
ℹ️ 定义及概述
在分布式系统中,负载均衡(load balance)是一种有效的将网络请求分配到多个服务器的过程。通过将负载进行负载均衡,可以有效地改进系统响应时间, 提高系统的可用性 。随着系统变的愈发复杂,用户增多和网络流量增大,负载均衡已经成为系统设计中的必要一环.
负载均衡器可以是硬件也可以是软件,它会将网络请求分发到服务器集群上.
常见的硬件负载均衡器包括
常见的软件负载均衡器包括
结合制造行业最佳实践, 以及制造业的实际情况考虑, 制造业在全国乃至全球拥有多座工厂, 每个工厂拥有独立的机房. 采用硬件负载均衡成本过高. 确定采用 软件负载均衡器 作为负载均衡技术实现. 下面对软件负载均衡器逐一进行论述
NGINX
Nginx("engine x")是一款是由俄罗斯的程序设计师 Igor Sysoev 所开发高性能的 Web 和 反向代理 服务器. 。
优点
缺点
ip_hash
实现源地址会话保持, 且可以通过第三方模块实现 cookie会话保持 . LVS
LVS:使用 Linux 内核集群实现一个高性能、高可用的负载均衡服务器,它具有很好的可伸缩性(Scalability)、可靠性(Reliability)和可管理性(Manageability).
优点
缺点
HAProxy
HAProxy 是一个使用 C 语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于 TCP 和 HTTP 的应用程序代理.
优点
缺点
选型结论
LVS 试用场景单一, 且存在硬伤(即: 后面有Windows Server的机器的话, 实施比较复杂). 直接排除. 。
HAPorxy 针对 HTTP 的支持没有 NGINX 丰富, 且重启中断相对 NGINX 时间更长. 。
另外, nginx 除了当前可以用作负载均衡器之外, 还可以用作 web server, http 缓存等场景, 且容易上手. 。
最终确定选择 NGINX 作为某制造业公司负载均衡器. 。
NGINX 高可用技术方案只有一种, 即: NGINX + Keepalived 实现高可用. 。
keepalived 开源项目 包括三个组成部分:
keepalived Linux服务器的守护程序.
虚拟路由器冗余协议 (VRRP)的实现,用于管理虚拟路由器(虚拟 IP 地址或 VIP ).
VRRP 确保始终存在一个主节点。备用节点侦听来自主节点的 VRRP 通告包。如果在超过配置的广播间隔的三倍的时间内未收到广播包,则备用节点将作为主节点接管,并将配置的 VIP 分配给自己.
一种运行状况检查工具,用于确定服务(例如,Web 服务器,PHP 后端或数据库服务器)是否已启动并且可以运行.
如果节点上的服务未通过配置的运行状况检查次数, keepalived 则将虚拟 IP 地址从主(主动)节点重新分配给备用(被动)节点.
✔️选型结果
负载均衡策略: RR(轮询, 默认策略) 。
会话保持策略: (非必须) 。
ip_hash
NGINX负载均衡策略
least_conn
. ip_hash
hash
- 指定服务器组的负载均衡方法,其中客户机-服务器映射基于hash 值。key可以包含文本、变量及其组合。 选型过程
负载均衡策略,根据实际情况按需选择,无特殊要求的情况下选择 rr 即可。 会话保持策略, 需要根据特定的场景进行选择
ip_hash
cookie
会话保持: sticky
cookie
会话保持均无法满足需求, 则可能需要通过 hash
来定制会话保持策略. 略. 。
由于应用系统的多样性, 本文不对应用服务层 -> 数据库层高可用选型做约束. 仅提供顶层架构要求
参考文件 |
---|
Availability - Wikipedia |
High Availability - Wikipedia |
system-design-primer - GitHub |
High Availability Support for NGINX |
Usage of web servers broken down by ranking |
三人行, 必有我师; 知识共享, 天下为公. 本文由东风微鸣技术博客 EWhisper.cn 编写. 。
最后此篇关于高可用系列文章之二-传统分层架构技术方案的文章就讲到这里了,如果你想了解更多关于高可用系列文章之二-传统分层架构技术方案的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我应该编写一个函数来打印一组给定的三个数字中两个较大数字的平方和。 我对这种情况的处理相当笨拙。我没有编写返回一组 3 中最大的两个数字的函数,而是编写了函数,以便表达式减少到两个所需的数字。 # S
如果有人可以提供帮助,我将不胜感激。我一直在敲我的头一天试图让这个工作。我已经在互联网上搜索并重新阅读了手册,但我就是不明白。 guile << __EOF__ ( define heading-li
目前我正在处理一个方案问题,其中我们正在使用方案列表表示一个图。我们使用的第一个变体是表示为 的边列表图 '((x y) (y z) (x z)) 我们正在使用的图的第二个变体被称为 x 图,表示为
我正在尝试创建一个函数,该函数将两个函数作为参数并执行它们。 我尝试使用 cond ,但它只执行 action1 . (define seq-action (lambda (action1 act
我提前为我的原始英语道歉;我会尽量避免语法错误等。 两周前,我决定更新我对 Scheme(及其启示)的知识,同时实现我在手上获得的一些数学 Material ,特别是我注册的自动机理论和计算类(cla
Scheme中有没有函数支持分数的“div”操作? 意思是 - 11 格 2.75 = 4。 最佳答案 我认为你的问题的答案是:没有,但你可以定义它: #lang racket (define (di
我在scheme中实现合并排序,我必须通过定义两个辅助方法来实现:merge和split。 Merge 需要两个列表(已经按递增顺序)并将它们合并在一起。我这样做了如下: (define merge
尝试从终端加载方案文件。我创建了一个名为 test.scm 的文件,其中包含以下代码: (define (square x) (* x x)) (define (sum-of-squares x y)
我有以下代码: (define (howMany list) (if (null? list) 0 (+ 1 (howMany (cdr list))))) 如果我们执行以
我有点了解如何将基本函数(例如算术)转换为Scheme中的连续传递样式。 但如果函数涉及递归怎么办?例如, (define funname (lambda (arg0 arg1)
我正在尝试附加两个字符串列表 但我不知道如何在两个单词之间添加空格。 (define (string-concat lst1 lst2) (map string-append lst1
这个问题已经有答案了: How do I pass a list as a list of arguments in racket? (2 个回答) 已关闭 8 年前。 我有一个函数,它需要无限数量的
我对这段代码的工作方式感到困惑: (define m (list 1 2 3 '(5 8))) (let ((l (cdr m))) (set! l '(28 88))) ==>(1 2 3 (5 8
我正在为学校做一项计划作业,有一个问题涉及我们定义记录“类型”(作为列表实现)(代表音乐记录)。 我遇到的问题是我被要求创建一个过程来创建这些记录的列表,然后创建一个将记录添加到该列表的函数。这很简单
我有以下代码: (define (howMany list) (if (null? list) 0 (+ 1 (howMany (cdr list))))) 如果我们执行以
我正在尝试附加两个字符串列表 但我不知道如何在两个单词之间添加空格。 (define (string-concat lst1 lst2) (map string-append lst1
如何使用抽象列表函数(foldr、foldl、map 和 filter 编写函数),无需递归,消耗数字列表 (list a1 a2 a3 ...) 并产生交替和 a1 - a2 + a3 ...? 最
我试图找出在 Scheme 中发生的一些有趣的事情: (define last-pair (lambda (x) (if (null? (cdr x))
这个问题在这里已经有了答案: Count occurrence of element in a list in Scheme? (4 个答案) 关闭 8 年前。 我想实现一个函数来计算列表中元素出现
我正在尝试使用下面的代码获取方案中的导数。谁能告诉我哪里出错了?我已经尝试了一段时间了。 (define d3 (λ (e) (cond ((number? e) 0) ((e
我是一名优秀的程序员,十分优秀!