美文网首页
第十一章 规模化微服务

第十一章 规模化微服务

作者: 大唐雷恋 | 来源:发表于2019-07-09 21:50 被阅读0次

    11.1 故障无处不在

    硬盘可能会损坏,软件可能会崩溃。我们尽力尝试去限制引起故障的因素,但当达到一定规模后,故障难以避免。规模化后,即使你买最好的工具,最昂贵的硬件,也无法避免它们会发生事故的事实。我们需要嘉定故障会发生,如果以这种想法来处理你做的每一件事情,为其故障做好准备,那么就会做出不同的权衡。
    如果你知道一个服务器将会发生故障,系统也可以很好地应对,那么又何必再组织故障上花很多的精力呢。

    11.2 多少是太多

    • 响应时间/延迟
      各种操作需要多长时间?可以使用不同数量的用户来测量它,以了解复杂的增加会对响应时间造成什么样的影响。将监控的响应目标设置成一个给定的百分比是很有用的。
    • 可用性
      你能接受服务出现故障码?这是一个24/7服务吗?不同的场景对服务可用性的要求是不同的
    • 数据持久性
      多大比例的数据丢失是可以接受的?数据应该保存多久?不同的场景要求也不同。业务数据,日志数据。。。还有不同的环境

    11.3 功能降级

    构建一个弹性系统,尤其是当功能分散再不同的,有可能宕掉的微服务上时,重要的是能够安全降级功能。

    对于简单的单块应用程序来说,我们不需要做很多决定。系统不是好的,就是坏的。对于微服务系统来说,不同的场景下是有很多微妙的情况的。对于每个依赖多个小友合作者的微服务来说,你都需要问自己:如果这个微服务宕掉会发生什么?然后你就知道该做什么了。

    11.4 架构性安全措施

    正确设置超时,实现舱壁隔离不同的连接池,并实现一个断路器,以便再第一时间避免给一个不健康的系统发送调用

    11.5 反脆弱的组织

    理解分布式系统所需的思维方式上的转变。事情将会失败,事先做好对各种异常,错误,例外情况的处理预案,准备好如何应对各种故障的发生是非常重要的。
    猴子军队。


    image.png

    11.5.1 超时

    再使用下游系统时,正确处理超时是很重要的事。
    超时时间太短,你会将一个可能还在正常工作的调用错认为事失败的。
    如果不设置超时时间或超时时间设置过长,一个宕掉的下游系统可能会让整个系统挂起。

    给所有跨进程调用设置超时,并选择一个默认的超时时间,当超时发生后,记录到日志里看看发生什么,并相应地调整他。

    11.5.2 断路器

    image.png

    在家里,段力气会在电流尖峰时保护你的电子设备。如果出现尖峰,断路器会切断电路,保护你昂贵的家用电器。

    使用断路器时,当对下游资源的请求发生一定数量的失败后,断路器会打开。所有的请求在断路器打开的状态下会快速失败。一段时间后,客户端发送一些请求查看下游服务是否已经恢复,如果它得到了正常的相应,将重置断路器。

    11.5.3 舱壁

    舱壁,是把自己从故障中隔离开的一种方式。在航运领域,椽笔是船的一部分,合上舱口后可以保护船的其他部分。所以,如果船板穿透之后,你可以关闭舱壁们。如果失去了船的一部分,但其余部分仍完好无损。
    我们应该为每个下游服务的连接使用不同的连接池。这样的花,如果一个连接池被用尽,其余连接并不受影响。这样,可以确保,如果下游服务将来运行缓慢,只有那一个连接池会受影响,其他调用仍可以正常运行。


    image.png

    11.5.4 隔离

    一个服务越依赖于另一个,另一个服务的健康将月能影响其他正常工作的能力。如果我们使用的集成技术允许下游服务器离线,上游服务便不太可能收到计划内或计划外宕机的影响。

    11.6 幂等

    对幂等操作来说,其多次执行所产生的影响,均与一次执行的影响相同。如果操作是幂等的,我们可以对其重复多次调用,而不必担心回有不利的影响。当我们不确定操作是否被执行,想要重新处理消息,从而从错误中恢复时,幂等会非常有用。

    是否幂等取决于你的服务在处理这些调用时是否使用了幂等方式。

    11.7 扩展

    一般,扩展系统的原因有两个:

    • 帮助处理失败
    • 为性能扩展,无论是处理更多的负载,减少延迟或是两者兼有之。

    11.7.1 更强大的主机

    垂直扩展:一个有着更快的CPU和更好的I/O的机器,通常可以改善延迟和吞吐量,允许你在更短的时间内处理更多的工作。但是这非常昂贵。大机器能给我们更多的CPU内核,但如果写的如阿健没有充分利用它们也是不够的。另外,这种形式的扩展无法改善我们服务器的弹性。尽管如此,当同时使用了虚拟化供应商的服务,它允许你轻松地调整机器的大小。

    11.7.2 拆分负载

    分拆服务,让不同的服务承担自己该承担的责任,进而将不同业务请求的负载分配到对应的微服务上。

    11.7.3 分散风险

    确保不要把多个微服务部署到同一台主机上,因为主机的宕机会影响多个服务。
    另一种常见的减少故障的方法是,确保不要让所有的服务都运行在同一个数据中心的同一个机架上,而是分布在多个数据中心。

    11.7.4 负载均衡

    在一个负载均衡器后,放置堕胎主机运行你的微服务实例。对于微服务的消费者来说,你不知道你是在跟一个微服务实例通信,还是一百个。


    image.png

    一些负载均衡器提供了其他有用的功能。厂家按的一个是SSL终止,通过HTTPS连接入站负载均衡器后,当到实例本身时转换成HTTP连接。从经验上看,管理SSL的开销非常大,拥有要给负载均衡器来处理这个过程是相当有用的。VLAN是一个虚拟局域网,所有的外部请求只能通过一个路由器访问内部。在这个例子中,这个路由器也就是SSL终端负载均衡器。VLAN外部跟微服务通信的唯一方式是通过HTTPS,而内部的所有通信都是通过HTTP。


    image.png

    11.7.5 基于worker的系统

    11.7.6 重新设计

    系统最初的架构,可能和能够应对很大负载容量的架构是不同的。
    “设计应该考虑10倍容量的增长,但超过100倍容量时就要重写了。”
    避免过度设计,从一开始就构建大规模系统,这是很危险的,甚至可能是灾难性的。开始时,我们需要快速实验,并以此了解需要构建哪些功能。
    反例:曾经有人花了六个月的时间构建了一个产品,却压根没有人下载。他反思说,他本可以在网页上放一个连接,当有人点击时返回404,以此来检验是否真的有这样的需求。这样,那六个月就可以用来做更有意义的事。

    11.8 扩展数据库

    扩展无状态的微服务事相对简单的,扩展数据库呢?

    11.8.1 服务的可用性和数据的持久性

    对所有写入数据库的数据,我们可以将一份副本存储到一个弹性文件系统。如果数据库出现故障,数据不会丢失,因为有一个副本,但数据库本身是不可用的,这会使我们的微服务也不可用。
    一个常用的模式是使用副本,把写入著数据库的所有数据,都复制到备用副本数据库。如果主数据库出现故障,我的数据是安全的,但如果没有一个机制让著数据库恢复或提升副本为主数据库,即使数据是安全的,数据库依然不可用。

    11.8.2 扩展读取

    从主数据库复制到副本,是在写入后的某个时刻完成的,这意味着使用这种技术读取,有时看到的可能是失效的数据,但是最终能够读取到一致的数据,这样的方式被成为最终一致性。


    image.png

    几年前,使用只读副本进行扩展风靡一时,不过现在更建议你首先看看缓存,因为它可以提供更显著的性能提升,而且工作量往往更少。

    11.8.3 扩展写操作

    采用分片方式,会存在多个数据库节点。当有一块数据要写入时,对数据的关键字应用一个哈希函数,并基于这个函数的结果决定将数据发送到那个分片。
    分片写操作的复杂性来自于拆线呢处理。查找单个记录很容易,因为可以应用哈希函数找到数据应该在那个实例上,然后从正确的分片获取它。但如果查询跨越多个节点呢?需要查询每个分片,然后再内存里进行拼接。要么有一个替代的度数据库包含所有的数据集。跨分片查询往往采用一步机制,将查询的结果放入缓存。

    11.8.4 共享数据库基础设施

    要尽量避免共享数据库。如果该数据库的基础设施出现故障,它会影响多个微服务,这可能导致灾难性故障。

    11.8.5 CQRS

    CQRS(Command-Query Responsibility Segregation,命令查询指责分离)模式,是一个存储和查询信息的替代模型。
    这种形式的分离允许不同类型的扩展。我们系统的命令和查询部分可能式在不同的服务或再不同的硬件上,完全可以使用不同类型的数据存储。

    11.9 缓存

    缓存是性能优化常用的一种方法,通过存储之前操作的结果,以便后续请求可以使用这个存储的值,而不需要花时间和资源重新计算该值。通常状况下,缓存可以消除不必要的到数据库或其他服务的往返通信,让结果返回的更快。如果使用得当,它可以带来巨大的性能好处。

    11.9.1 客户端,代理和服务端缓存

    客户端缓存:数据副本再客户端,由客户端决定何时(以及是否)获取最新副本。(可大大减少网络调用次数,是减少下游服务负载的最快方法之一)
    代理服务器缓存:将一个代理服务器放在客户端和服务器之间。反向代理或CDN(Content Delivery Network,内容分发网络),是很好的使用代理服务器缓存的例子。
    服务端缓存:由服务器来负责处理缓存,可能会使用像Redis或Memcache这样的系统,也可能是一个简单的内存缓存。

    很多时候对各种缓存方式都是混用,或者选用其中的几种,或者都不用,根据不同的情况来决定。

    11.9.2 HTTP缓存

    11.9.3 为写使用缓存

    缓存常用于读操作,为写的缓存也是有意义的。消息队列就是一个例子。
    使用后写式(writebehind)缓存,如果对写操作的缓存做了适当的持久化,那么即使下游服务不可用,我们也可以将写操作放到队列里,然后当下游服务可用时再将它们发送过去。

    11.9.4 为弹性使用缓存

    缓存可以再出现故障时实现弹性。使用客户端缓存,如果下游服务不可用,客户端可以先简单地使用缓存中可能失效了的数据。H5中的LocalStorage有类似的功效,可提供离线浏览能力。

    11.9.5 保持简单

    避免再太多地方使用缓存,再你和数据源之间的缓存越多,数据就月可能失效,就越难确定客户端最终看到的是否是最新的数据。缓存越多就越难评估任何数据的新鲜程度。

    11.9.6 缓存中毒:一个警示

    使用缓存时,我们经常认为最糟糕的事情是,我们会在一段时间内使用到失效的数据。
    缓存可以很强大,但是你需要了解数据从数据源到总店的完整缓存路径,从而真正理解它的复杂性以及使它出错的原因。

    11.10 自动伸缩

    自动伸缩可以响应式地进行负载调整,比如再负载增加或某个实例发生故障时,来增加额外的实例,或再不需要时移除它们。
    响应型伸缩和预测型伸缩都非常有用,如果你是用的平台允许按需支付使用的计算资源,它们可以节省更多的资本。

    11.11 CAP定理

    一致性(consistency),可用性(availability)和分区容错性(partition tolerance)
    CAP定理告诉我们最多只能保证三个中的两个
    一致性是当访问多个节点时能得到同样的值。可用性意味着每个请求都能获得响应。分区容错性是指集群中的某些节点再无法联系后,集群整体还能继续进行服务的能力。

    image.png

    11.11.1 牺牲一致性

    如果同步终端,并且两个节点再系统分区后仍然能够服务请求,但失去了一致性。这通常被称为一个AP系统。最终某个时刻,两个数据库的数据会同步,这称为”最终一致性“

    11.11.2 牺牲可用性

    如果我们牺牲了可用性,系统就变为一致的和分区容错的,即CP系统。在这种模式下,我们的服务必须考虑如何做功能降级,知道分区恢复以及数据库节点之间可以重新同步。

    11.11.3 牺牲分区容错性

    那有没有CA系统呢?应该如何牺牲分区容错性呢?如果系统没有分区容错性,就不能跨网络运行。换句话说,需要在本地运行一个单独的进程。所以,CA系统在分布式系统中根本是不存在的。

    11.11.4 AP还是CP

    到底使用AP还是CP系统,现实中要视情况而定。AP系统扩展更容易,而且构建更简单,而CP系统由于要支持分布式一致性会遇到更多的挑战,需要更多的工作。

    对于库存系统,如果一个记录过时了5分钟,这可接受吗?如果答案是肯定的,那么解决方案可以是一个AP系统;但对于银行客户的余额来说呢?能使用过时的数据吗?不可以,所以应该是CP系统。

    11.11.5 这不是全部或全不

    系统作为一个整体,不需要全部是AP或CP的。可能一些服务是AP的,而另一些服务是CP的,而同时,有些服务甚至不必是CP或AP的。我们所需要做的就是把关于CAP定理的权衡,推到单独服务的每个功能中去。

    11.11.6 真实世界

    实际情况下,大部分的系统是AP的,除了构建CP系统的复杂性之外,它本身也无法解决我们面临的所有问题。

    11.12 服务发现

    11.13 动态服务注册

    11.13.1 Zookeeper

    Zookeeper(http://zookeeper.apache.org)最初是作为Hadoop项目的一部分进行开发的。它被用于令人眼花缭乱的众多使用场景中,包括配置管理,服务间的数据同步,leader选举,消息队列和命名服务。

    它是被充分使用和测试过的,并得到了广泛使用。

    11.13.2 Consul

    Consul(http://www.consul.io)也支持配置管理和服务发现。
    Consul还内置了一些你可能觉得有用的其他功能。比如,对节点执行健康检查的能力。
    Consul从注册服务,查询键/值存储到插入健康检查,都是用的是RESTful HTTP接口,这使集成不同技术栈变得非常简单。

    11.13.3 Eureka

    Eureka(https://github.com/Netflix/eureka).
    Eureka还提供了基本的负载均衡功能,它可以支持服务实例的基本轮询调度查找。它提供了一个基于REST的接口。各种语言都有适配Eureka的客户端。

    11.14 文档服务

    理想情况下,应该确保文档和最新的微服务API同步

    11.14.1 Swagger

    Swagger让你描述API,产生一个很友好的Web用户界面,使你可以查看文档并通过Web浏览器与API交互。能够直接执行请求是一个非常棒的特性。

    Swagger需要服务提供与其格式相匹配的附属文件。Swagger有大量不同的语言的库可以帮你做这些。例如,对于Java,你可以对方法使用注解来匹配API调用,然后就可以生成相应的文件。

    相关文章

      网友评论

          本文标题:第十一章 规模化微服务

          本文链接:https://www.haomeiwen.com/subject/yyqqkctx.html