《Akka应用模式:分布式应用程序设计实践指南》读书笔记8

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 可用性  简单点来说就是系统能否正常使用。如果系统能够及时响应一个请求,则认为是可用的;如果响应时间过长或者根本不响应,则是不可用的。系统在停机或超载时是不可用的。一般用系统正常运行时长的百分比来计量系统的可用性,例如常常用N个9表示系统的可用性。

可用性

  简单点来说就是系统能否正常使用。如果系统能够及时响应一个请求,则认为是可用的;如果响应时间过长或者根本不响应,则是不可用的。系统在停机或超载时是不可用的。一般用系统正常运行时长的百分比来计量系统的可用性,例如常常用N个9表示系统的可用性。故障时间秒数=(1-可用性) * 365 * 24 * 3600

描述 通俗叫法 可用性级别 年度停机时间
基本可用性 2个9 99% 87.6小时
较高可用性 3个9 99.9% 8.8小时
具有故障自动恢复能力的可用性 4个9 99.99% 53分钟
极高可用性 5个9 99.999% 5分钟

   与可用性相关的几个概念在这里稍微提一下,虽然本书并没有提及。

  RPO:(Recovery Point Obejective,恢复点目标)是指业务系统所允许的在灾难过程中的最大数据丢失量,用来衡量容灾系统的数据冗余备份能力。

  RTO:(Recovery Time Objective,恢复时间目标)是指信息系统从灾难状态恢复到可运行状态所需的时间,用来衡量容灾系统的业务恢复能力。

  第七章提到了很多导致系统不可用的因素,而且无法完全避免出现故障。可用性则要求在出现故障时可以找到缓解故障的方法,尽可能快的恢复系统。

微服务和单体式应用

  应用程序一般由两种构建方法:单体式架构、微服务架构。一般处于二者中间状态。

  单体式应用程序是指把所有组件都部署为单个单元的应用程序。一般创建各种独立的库隔离复杂性,然后把这些库编织在一起构建成一个完整的大系统。微服务则通过较大的应用程序分成较小的服务来构建,以隔离的方式执行非常细微的任务,复杂性被隔离在各个独立的微服务之内,然后通过其他微服务进行组合。

  其实两种架构是对“分而治之”思想的不同粒度的解释。单体式应用从微观的角度拆分系统,微服务从整体的角度拆分系统。由此来看,并不是拆分的越细越好。

  虽然可用性跟哪种架构没太大关联,但系统拆分的粒度不同,则提供可用性和可扩展性的方法就不同。单体式应用只有一个可部署的单元,此时提高可用性一般就是把部署单元复制多份。这个实施起来简单粗暴,还有效。但有时候不一定能奏效。比如部署单元可以复制多份,但是数据库却不能简单的复制多份,毕竟数据才是王道。

  微服务就是把单体式应用拆分为多个子系统,每个系统是独立的,子系统可以看做单体式应用按照复制的方法提高可用性。

  Akka为多个微服务通信提供相关的工具。

用有界上下文划分微服务

  其实微服务的划分方法,每个人有不同的见解。我比较倾向于作者的划分方法,也就是从业务的角度划分微服务。DDD提供了一种将应用程序划分为较小部件的方法,有界上下文就是划分的界限。但有些人倾向于从系统的角度划分微服务,其实就是将系统的各个模块抽象、独立出来成为一个子系统。比如将一组逻辑上相关的jar包封装起来对外提供服务。这一点就见仁见智吧。其实DDD可以很自然的映射到Akka的相关技术,这里就不对作者提到的方法进行阐述了,读者自行体会吧。

细粒度的微服务

  有界上下文是划分应用程序的完美起点,但有时候需要分解成更小的规则。Akka经常把界面和域分成单独的微服务,这样就可以独立地扩展双方。关于这一点就需要我们根据系统的实际情况来平衡了。但我觉得基本的出发点就是封装变化,并对其进行扩展。

集群感知路由器

  使用本地的单个actor系统构建时,路由器可以提高可扩展性。处理分布式系统时,还可以将路由器作为一个提供可用性的工具。集群感知路由器与普通路由器类似,只不过它的路由可能驻留在集群中的其他节点上,允许这些路由器在可扩展性之外提供可用性。其实路由器有点类似于注册中心,路由器负责分发消息。集群感知路由器可以自动感知节点的位置,并根据路由策略发送消息。如果一个节点出现故障,路由器可以简单的把消息路由到另外一个不通过的活跃节点上。这就额外获得了可用性。

  集群感知路由器与本地路由器的路由策略稍有不同。比如使用最小邮箱的路由器不知道集群中哪个节点的邮箱比较小。集群感知路由器通过actor的相对路径收集集群中所有符合条件的actor,与单例代理不同,它不会缓存消息,也就是消息可能丢失。

 分布式数据

  在最终一致的分布式系统中,有时候会遇到瞬态数据,其实也就是临时数据。他们不需要保存在数据库,只存在应用程序运行期间,比如用户的会话信息。瞬态信息在所有节点上保持可用性对系统来说非常重要。比如用户信息如果在新节点上不可用,系统就无法继续为该用户提供正常的服务。其实吧,我觉得如果瞬态数据非常重要,那就保存在数据库呗,实在不行保存在分布式缓存也是好的。Akka为此还单独提供了相关的组件,真是考虑周到啊。

  Akka为我们提供了一种分布式的、最终一致的存储和检索数据的方法。这种最终一致的数据类型被称为无冲突复制数据类型或CRDT(Conflict-Free Replicated Data Types)。关于这个CRDT网上的资料不是很多啊。Akka实现了称为分部署数据的CRDT,目前还不稳定。

  CRDT要求数据类型必须包含一个无冲突的合并方法,此方法具有接收两种不同状态的数据(来自集群中两个不同位置)并将其合并在一起以创建最终结果的能力。如果合并完成没有遇到冲突,那么就可以使用此数据结构来跨节点进行复制。这就是CRDT的工作原理,当一个节点收到对数据更新的命令时,它将当前状态广播给其他节点。其他节点收到更新的状态时,与自己的状态进行合并,然后存储最终结果。关于这个CRDT可以参考wikipedia。不建议使用这个东西,毕竟用一个数据库或者分布式缓存就可以搞定了,还这么麻烦进行广播。这个技术只能说明Akka的强大和复杂而已。

优雅降级

  将应用程序分解为微服务的好处之一就是可以实现优雅降级,但前提是你的系统得支持优雅降级。优雅降级需要你衡量系统的重要性、优先级,也就是说那些服务是可以降级的。熔断器模式可以实现优雅降级。比如检测外部系统的故障是一个耗时的操作,如果每个后续请求都要等待连接超时知道资源再次可用,整个系统将承担很多额外的负担。熔断器可以快速的使后续请求快速失败,可以有效减少系统的负载,便于系统故障恢复,也可以提高系统的可用性。

  其实熔断器是“分而治之”的逆向思维,有时候过渡分解不是一件好事,把检测超时这个功能向上抽象汇总,提供统一的处理方式,可以有效的减少系统的负载,带来上述的好处。看来系统并不一定是越精细越好。

 部署

  即使应用程序提高了可用性,但如果部署时仍需要关闭整个应用程序,那么可用性就会大打折扣。所以提高可用性是一件比较困难的事情。

分阶段部署/滚动重启

  导致节点在系统中不可用的最常见的原因并不是错误,而是升级!这听起来挺扯的。即使你的应用程序设计的完美,不会宕机,但如果升级的时候需要停机,那么可用性这个指标就不会太高。特别是你有100台机器需要升级版本的时候,那就更加痛苦了。如果你的版本不兼容,那么就意味着100台机器需要同时关掉,然后一台台部署。想想就觉得呵呵。当然了,如果你的自动化运维比较完善,就会省事儿很多。

  分布式系统最常用的方法就是使用分阶段部署,也成为滚动重启。滚动重启有一个比较关键的技术就是对请求进行分流,也就是可以将系统的请求暂时路由到旧有系统,当新节点可用时,再将请求回流。当然了,这只是涉及一个系统,如果涉及多个系统,那就更麻烦了。如果两个系统必须同步升级,比如接口变化了,且版本不兼容,想想是不是更加觉得呵呵?另一个关键的技术就是版本兼容了。所以可用性并不是一件容易的事儿。

蓝绿部署

  滚动升级的替代方案被称为蓝绿部署,其实还是滚动升级。把50%的节点指定为“蓝色”,剩下的50%指定为“绿色”。绿色节点处理请求时,升级蓝色节点,检查运行状态,然后交替升级。

崩溃恢复/运维监测

  集群可用性的关键指标是能够识别出故障是什么时候发生的,然后对其进行适当的处理。当然是越早发现越好,这样就可以提高 可用时间。此时运维监测就非常重要了。

健康检查和应用状态页面

  大多数监测工具都是依赖某种健康检查机制。执行健康检查的最常见机制是使用HTTP状态页面,这一点感觉作者说的有点局限,只能说这是一种常见的显示机制,而不是执行机制。即使应用程序不需要HTTP接口,包含Akka HTTP健康检查页面也是一件好事。完全使用actor通信的微服务也可以从用Akka HTTP端点搭建的监控中收益。这个页面具体包含什么信息比较灵活,作者建议把外部依赖是否可用、应用程序版本号或提交HASH包含进来。

度量

  健康检查是一个很好的工具,但它具有滞后性,只能在出现问题的时候才去适当的措施。那么能不能预防故障的发生呢?常见的是使用服务指标度量系统,通常是一个时间序列数据库。把系统的服务指标进行可视化展示和响应的分析,就可以做到提前检测系统问题了。基于Akka或其他方式的分布式系统一般都会将入口点周围的计时器包裹到系统中,用来记录操作开始和结束的时间,计算差异值,然后存储。但需要特别说明的是,一定要注意时间字段获取的准确性!通常情况下,分布式节点的时间不一定同步或者有一定的误差!特别是在金融业务系统中,很多机器都会且日跑批量神马的,比较麻烦。

  度量是一个技术活,度量后如何分析就需要根据各个业务系统自行设计了。不属于Akka的范畴,就不再过多分析了。

日志

  度量之后发现了异常,下一步就需要确定原因,日志就变得至关重要了。基于Akka开发分布式一个好处就是,日志是异步打印的,不太会影响系统的性能。很多时候,生产商一般不开日志,因为怕影响性能,所以日志往往会被忽略。

看门狗工具

  发现了问题就需要采取对应的措施,首先需要某种通知机制提醒运维人员或者开发人员。常用的通知机制有邮件、短信、电话、微信。但不能只是简单粗暴的进行预警,如果预警多了,就会减少运维人员的注意力。如果能够采取一些纠正措施就更好了,比如重启。

  其实应用监测是一个比较大的议题,远超出了Akka的范围。很多工具需要组合使用,才能发挥最大的作用。

结论

  从本章可以看出,提高系统的可用性是一个系统工程,需要多种工具、策略来确保。这有时候比分布式系统本身更加复杂。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
4月前
|
存储 消息中间件 Apache
比较微服务中的分布式事务模式
比较微服务中的分布式事务模式
76 2
|
1月前
|
监控
Saga模式在分布式系统中保证事务的隔离性
Saga模式在分布式系统中保证事务的隔离性
|
2月前
|
人工智能 文字识别 Java
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
尼恩,一位拥有20年架构经验的老架构师,通过其深厚的架构功力,成功指导了一位9年经验的网易工程师转型为大模型架构师,薪资逆涨50%,年薪近80W。尼恩的指导不仅帮助这位工程师在一年内成为大模型架构师,还让他管理起了10人团队,产品成功应用于多家大中型企业。尼恩因此决定编写《LLM大模型学习圣经》系列,帮助更多人掌握大模型架构,实现职业跃迁。该系列包括《从0到1吃透Transformer技术底座》、《从0到1精通RAG架构》等,旨在系统化、体系化地讲解大模型技术,助力读者实现“offer直提”。此外,尼恩还分享了多个技术圣经,如《NIO圣经》、《Docker圣经》等,帮助读者深入理解核心技术。
SpringCloud+Python 混合微服务,如何打造AI分布式业务应用的技术底层?
|
2月前
|
存储 缓存 NoSQL
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
70 4
|
3月前
Saga模式在分布式系统中如何保证事务的隔离性
Saga模式在分布式系统中如何保证事务的隔离性
|
3月前
|
存储 NoSQL Java
分布式session-SpringSession的应用
Spring Session 提供了一种创建和管理 Servlet HttpSession 的方案,默认使用外置 Redis 存储 Session 数据,解决了 Session 共享问题。其特性包括:API 及实现用于管理用户会话、以应用容器中性方式替换 HttpSession、简化集群会话支持、管理单个浏览器实例中的多个用户会话以及通过 headers 提供会话 ID 以使用 RESTful API。Spring Session 通过 SessionRepositoryFilter 实现,拦截请求并转换 request 和 response 对象,从而实现 Session 的创建与管理。
分布式session-SpringSession的应用
|
3月前
|
存储 NoSQL Java
分布式session-SpringSession的应用
Spring Session 提供了一种创建和管理 Servlet HttpSession 的方案,默认使用外置 Redis 存储 Session 数据,解决 Session 共享问题。其主要特性包括:提供 API 和实现来管理用户会话,以中立方式替换应用程序容器中的 HttpSession,简化集群会话支持,并在单个浏览器实例中管理多个用户会话。此外,Spring Session 允许通过 headers 提供会话 ID 以使用 RESTful API。结合 Spring Boot 使用时,可通过配置 Redis 依赖和支持缓存的依赖实现 Session 共享。
分布式session-SpringSession的应用
|
2月前
|
缓存 网络协议 API
分布式系统应用之服务发现!
分布式系统应用之服务发现!
|
3月前
|
存储 运维 应用服务中间件
阿里云分布式存储应用示例
通过阿里云EDAS,您可以轻松部署与管理微服务应用。创建应用时,使用`CreateApplication`接口基于模板生成新应用,并获得包含应用ID在内的成功响应。随后,利用`DeployApplication`接口将应用部署至云端,返回"Success"确认部署成功。当业务调整需下线应用时,调用`ReleaseApplication`接口释放资源。阿里云EDAS简化了应用全生命周期管理,提升了运维效率与可靠性。[相关链接]提供了详细的操作与返回参数说明。
|
3月前
|
Dubbo Java 应用服务中间件
分布式(基础)-RMI简单的应用
分布式(基础)-RMI简单的应用