Java架构师教程:分布式 系统中如何下手做高可用



  对于企业来说,随着规模越来越大,整个系 统中存在越来越多的子系统,每个子 系统又被多个其他子系统依赖或者依赖于其他子系统。大部分 系统在走到这一步的过程中,大概率 会发生这样的场景:作为某 个子系统的负责人或者OnCall人员,休息的时候都不安稳,心里老 是忐忑着系统会不会挂。导致周 末不敢长时间出门,晚上睡 梦中被电话叫醒,痛苦不堪。


  那么,在一个 成熟的分布式系统中,我们该 如何去保证它的可用性呢?迫切的 需要解放我们紧绷的神经。下面,我们就 来看下做高可用的思路和关键部分。


  如何下手做高可用?


  在这个时候,我们的 系统全貌大致是这样的。


  由大大 小小的多个部分组合而成的一个完整系统,可以看到包含网关、Web层、服务层、中间件、基础设施,这每一 层之间又是层层依赖。在如此 的一个庞然大物面前做高可用是一个系统化的工程,除了良 好的顶层设计规划外,还需要深入到细节。由于雪崩效应的存在,软件系 统是一个完美体现“千里之堤毁于蚁穴”的地方,一个小 问题导致整个系统全盘崩塌的案例也不在少数。


  所以,首先我 们需要拥有保持怀疑的心态。这个怀 疑是指对系统的怀疑,而不是对人的怀疑。人非圣贤孰能无过,况且写 代码是一个精细活,还不是 流水线式的那种。而且,哪怕不 是写代码的疏忽,其他诸如网络、操作系统等异常,甚至一 些恶意的攻击都会导致故障随时发生。


  那么我 们具体应该怎么做呢?既然故 障导致了可用性降低,那么接 下来的工作必然是围绕解决故障展开。分为3个步骤:故障发现、故障消除、故障善后。


  故障发现


  所谓“故障发现”,就是通 过技术手段实时采集系统中每个节点的健康状态,以及每2个节点 之间链路的健康状态,包括但 不限于调用成功率、响应时间等等。借此代 替我们的眼睛去盯着整个系统,一旦低 于某个设定的阈值,就触发 报警给我们一个提醒。因为当 你的系统中存在成百上千的程序时,靠肉眼 去找到发生故障的位置,简直是天方夜谭。哪怕找到了,也可能 已经产生了巨大的损失。


  负责故 障发现的解决方案都属于应用性能管理(APM)范畴。我们在部署这个“眼睛”的时候,需要考 虑到全方位的覆盖,要包含所有的节点。比如:


  在Web方面可 以直接利用浏览器提供的导航计时(NavigationTiming)和资源计时(ResourceTiming)接口来采集性能数据,非常方便。


  在iOS、Android这种App方面通 过源代码插桩的方式进行。比如直接引入采集SDK然后硬 编码在源代码中,或者通过AOP框架来 进行动态代码注入。代码的 注入位置就在每个方法的执行前和执行后(如下图所示)。

image.png

  后端是 分布式系统的主战场,有进程 外和进程内两个维度的解决方案。


  1)进程外的解决方案,例如运用Zabbix之类的 无探针解决方案,调用系 统或者服务自身提供的状态接口获取采集数据(如下图所示),以及对 网络数据包的监听来获取网络性能方面的数据。

image.png

  由于是进程外的,所以这 类方案对我们的程序是无侵入的,最友好。但弊端也很明显,监控的粒度太粗,只能进 行一些外在的监控。比如可以发现CPU突然飙高了,但是并 不知道可疑的接口是哪个,更无法 知道是哪行代码导致的问题。因此,只适合作为辅助方案。


  2)后端的 进程内解决方案可以解决进程外方案的短板,但是由 于需要侵入到应用程序内部,所以对 性能和稳定性会带来一定的影响。关于这 类方案我们有很多的选择可以来实现它:可以同APP一样运用采集SDK和AOP框架,还可以 通过利用整个系统中的“连接”部分来进行,比如一些中间件(数据层访问框架、服务调用框架等)。

image.png

  做好了监控,就做好 了故障发现一半的工作。另外一半是什么呢?就是故障注入测试(FaultInsertionTest)。我们需 要通过技术手段来主动制造“故障”,以此来 提前检验系统在各种故障场景下的表现情况是否符合我们预期。


  监控是一双眼睛,替你盯着故障,但是我 们不能守株待兔,否则大 部分突发的故障都会在生产环境发生。一旦发 生就会对经营的业务产生或多或少的影响,甚至看 似平静的系统下,藏着几 个随时会引爆的炸弹,我们也不得而知。所以我 们需要主动出击,主动去制造“故障”来锻炼系统。


  在实际运用中,故障可 以被注入到软件,也可以被注入到硬件。注入到软件的方式,无外乎这两种:


  架设在 软件与操作系统之间,当软件 中的数据经过操作系统时,通过篡 改数据完成注入。


  通过AOP之类的 框架进行代码注入来制造故障。


  如果注 入到硬件中就简单很多,直接运行一段代码把CPU、网卡等吃满即可。


  故障注 入测试的过程大致是这样,在故障 模型库中选择一个模型,然后将 该模型对应的故障注入到一个在独立的环境中运行并且被包裹了一层“炸药包”的系统,相当于 在你指定的地方去“点火”,随后进 行监测并分析结果(如下图所示)。

image.png

  故障消除


  现在已 经能够很容易的发现故障了,我们就 可以通过综合运用隔离性、横向扩展、代理、负载均衡、熔断、限流、降级等 等机制来快速的“掐灭故障”。


  分布式 系统的规模越大,耦合越严重,各个子 系统之间通过网络连接在一起,就如赤 壁之战中的曹军连在一起的船舶一样,只要其 中一个着火了就会就近蔓延。所以,一旦发 现某个子系统挂了,就需要 尽快切断与它的联系,保证自 己能够不受连累,防止雪崩的发生。


  我们可以首先运用docker之类的 技术将每个应用在运行时的环境层面隔离开来。然后,通过横 向扩展让每个应用允许被“Copy”,以此来部署多个副本。接着,结合代 理和负载均衡让这些副本可以共同对外提供服务,使得每 个应用程序本身先具备“高可用”。最后的三大防御措施,熔断、限流、降级来快速“掐灭故障”,避免故 障在不同的应用程序间扩散。


  故障善后


  “故障消除”避免了 级联故障导致的系统性风险,这时整 个分布式系统已经具备健壮性了。但是对 正在使用系统的用户来说,这些故障还是可见的,因为会 反映成他实际操作中的错误提示,甚至导 致流程无法继续。这对我们“衣食父母”来说并不友好,最终可 能会导致用户的流失。


  所以,我们应 该通过一些补偿和缓冲的方式将故障产生的影响降到最低,尽可能的去包容故障,让用户无感。并且,这些善后工作应该与“故障发现”、“故障消除”一起形 成一个完整的体系,以及尽可能的自动化。


  前面我们聊到,故障产 生的原因要么是调用的节点处于异常状态,要么是通信链路异常。所以,要做好“故障善后”,就需要 在节点之间的连接上做文章。根据CAP定理、BASE理论,我们已 经很清楚两个进程之间的调用方式。一是直 接点对点的同步调用,或者是 通过一些技术中间层进行异步的调用。


  那么,针对同 步调用我们可以有两种方式去实施。


  首先是立即重试。很多时候,相同节 点的所有副本可能只是由于网络原因,导致其 中的某个节点无法被访问。那么,此时如 果后端的负载均衡策略只要不是Hash类的策略,并且后 端服务的方法是无状态的且支持幂等性的,就可以立马重试一次,大概率就能调用成功。不过,这个方 案潜在的一个副作用是,如果后 端服务总体负载很高,且无法自动弹性扩容,那么会 进一步加剧一些压力。所以,你可以 增加一个允许被重试的条件,以及为 实际的重试操作增加一个约定。比如,这两个 耗时分别都不能大于1秒。


  方式二,将可以 容忍最终一致性的同步调用产生的出错消息进行异步重发。比如,电商网 站中提交订单中所依赖的订单模块产生故障,我们可 以将其暂存到消息队列中,然后再 进行异步的投递,同时提示给用户“订单正在加紧创建中,稍后通知您支付”之类的语句,至少先 让订单能够下进来。这本质上算得是一个“降级”方案。


  如果本 身就是一个异步调用,比如最 常见的就是发往消息队列出现异常。因为,一个高 可用的消息队列集群,大多数 情况下导致消息无法被投递的原因是网络问题。这个时候,理论上 我们可以基于每个应用的本地磁盘部署一个本地MQ,可以避 免很大一部分这个问题。但是实 际往往不会这么做,因为这 么做的性价比太低,原因有两点:


  这么多 消息队列维护成本太高。


  如果用 到的是消息队列集群,本身已 具备软件层面的高可用,所以出 现这个问题的概率很低。


  所以,这个时 候我们大多会通过定时的任务(job)去进行对账(数据一致性检测)。任务(job)的具体 实现上尽可能做到自动修正,否则通知人工介入。


  以上就是动力节点java培训机构小编介绍的“Java架构师教程:分布式 系统中如何下手做高可用”的内容,希望对大家有帮助,如有疑问,请在线咨询,有专业 老师随时为你服务。


  相关内容


  做一名高级Java架构师,学Java架构师开发难吗


  【java架构师培训】合格java架构师标准是什么


  2019最新Java架构师学习路线


  Java架构师年薪一般多少?


上一篇:想了解系统技术架构,本篇文章不要错过
下一篇:最新最全Java学习视频及学习线路
0

开班信息

  • 抢座中
  • 已开班
  • 已开班
  • 已开班
  • 已开班

友情链接:    手机购彩官网   V8彩票活动优惠   大发快三邀请码   v8快投首页   v8快投手机app下载