文章目录
-
- 前言
- 概述
-
- 什么是微服务
- 主要好处
- 演化式架构师
-
- 架构师li>
- 架构师的演化视角
- 原则与标准
- 技术债务
- 集成
- 分解单块系统
-
- 原因
- 分解的方式
- 事物与一致性
- 表
- 部署
-
- CI/CD
- 测试
-
- 服务测试
- 端到端测试
- 脆弱的测试
- 监控
- 安全
- 康威定律和系统设计
- 规模化微服务
- 总结
- 总结
前言
微服务是如今比较热门的话题,但是到底什么是微服务,微服务带来了哪些好处,又引入了什么问题,该如何设计微服务等等。
很多第一次了解微服务的同学可能会觉得这些内容很多,会对微服务产生距离感与畏惧感,当然我在最开始也是这样。
所以一开始我直接找了一些 上所谓微服务实战的教学视频,不管是什么语言实现的基本上都是那一套内容:从服务注册与发现,到服务治理中的熔断与限流,再到最后的服务链路监控。
这些视频很少有告诉你为什么会这样做,只会告诉你这样做的好处,无法明白这些步骤在整个微服务生命周期中到底有什么作用,我就像个僵尸一样,别人说应该这样做,那就这样做吧,缺乏一些自己的思考。
向大佬学习
读书永远是学习门槛最低的,花费最少的,同时也是最有效的学习方法。怀着对微服务懵懵懂懂的感觉去找了在业界质量比较高的动物书系列中的一本比较经典的微服务书籍学习了下:微服务设计
接下来分享下自己从书中学习到的东西,以及一些自己的想法
概述
什么是微服务
内聚性
根据业务边界来确定服务的边界,保证每个服务具有单一职责原则,做到单个服务代码的
- 内聚性:把因相同原因而变化的东西聚合到一起,而把因不同原因而变化的东西分离开来
- 单个服务代码量:微服务并不是拆分的服务代码量越小越好,虽然拆分的
- 服务越小,独立性带来的好处越多,但是管理成本也会随之上升
- 最好就是单个服务刚好一个小团队可以维护即可
自治性
- 微服务通常会以分布式的方式部署在多台机器上,那么服务间的通信就很重要。
- 在设计一个服务对外提供的API时,应该考虑到什么该暴露,什么不该暴露。如果暴露的过多,就会导致服务消费方与API提供者产生耦合性,降低了服务的自治性。
- 一个好的自治性的服务的修改与部署,不应该影响其他任何服务
主要好处
技术异构性
微服务群上的每个服务并不一定要统一使用一种技术实现,对于不同服务选择最合适的才是最好的
- 得益于服务的自治性,可以在选择一个上尝试新技术
- 由于技术选择的灵活性,可能会导致一个微服务团队需要使用多种技术栈,这将会增加团队的管理与维护。
弹性
- 单体服务:单体服务可以通过在不同的机器上部署,来提高服务的弹性
- 微服务:微服务本身就能很好的处理服务不可用和功能降级的问题。甚至以分布式的方式部署在不同的系统上
- 分布式系统:一旦部署分布式系统,就得考虑 络与机器的问题
扩展
- 得益于服务的拆分,可以只对需要扩展的服务进行扩展
简化部署
-
由于单个服务的代码量不大,以及与其他服务的耦合性低,当修改一个服务的代码,可以很简单的快速部署
这意味着微服务可以快速的进行功能迭代
与组织结构匹配
- 一个公司就是一个组织,每个公司的组织结构也不同,而我们编写的系统是为公司的组织服务的
- 微服务架构可以很好的将架构与组织结构相匹配,避免出现过大的代码库,从而获得理想的团队大小与生产力
可组合性与可替换性
- 底层业务API不变,BFF层可以灵活多变,适应不同的终端
- 随着公司组织或者业务的变更,可以很好的替换掉某个服务的某些代码,甚至替换掉整个服务
面向服务的架构SOA
-
可以认为微服务是SOA 服务的一种实现
-
难点:
实施SOA 最大的难点就是对服务的拆分粒度,通信协议的选择,第三方中间件的选择等:
-
到底拆分多小才算小,多大算大,目前没有所谓的标准, 如果一开始无法很清晰界定上下文的拆分,可以不用拆分的太细,=
并不是说一开始拆分为多少个服务,后续就一成不变的
-
但是一个好的微服务的架构并不是一开始就设计出来的,而是不断演进的
-
演化式架构师
架构师h3>
计算机行业发展不到百年,相比于其他传统行业,还是一个很年轻的行业。
架构师的职责:
- 架构师的一个重要职责是确保团队有,以帮助我们向客户交付想要的系统
- 根据不同层次的划分,有不同的架构师,包括系统架构师,业务架构师以及技术架构师。
软件工程师:
-
计算机行业的发展不到百年,相比于其他行业,还处于很年轻的状态
我们通常将自己称为软件,但是业界却没有权威的认证,不像传统的建筑业有建筑师的认证,因此市面上的很多IT证书是没有意义的
类比建筑师
-
建筑师需要做好详细的计划,然后让别人去理解和执行
但是在软件行业,如果以建筑师的视角去当架构师,将会导致非常糟糕的实践
软件系统并不是一个设计好就一成不变的系统,他是的,因此一个好的架构师的职责就是推进一个系统不断往好的方向演进
架构师的演化视角
软件是不断演化的,架构师应该尽量预期可能发生的变化,但是这个预测并不能做到面面俱到
- 架构师的职责之一就是把握软件演化的
- 保证该系统适合开发人员在其上工作,而不应该做过多的干预,让干工作人员像系统使用者一样
架构师更多需要关注的是, 考虑服务之间如何交互,保证能够对整个系统的健康状态进行监控
技术架构师
- 作为技术架构师,服务的对象就是开发人员,为了了解自己设计的架构对开发人员是否友好,技术架构师应该经常抽时间和普通开发人员坐在一起工作,甚至可以结对编程
集中治理和领导
架构师的部分职责是
-
治理通过评估需求,保证企业目标的达成,通过排优先级和做决策来设定方向。并且对已经达成一致的方向和目标进行监督
-
最好的做法是架构师和开发小组一起交流讨论出治理方案,团队的力量永远大于个人
-
架构师对于团队的领导必须学会放手,给团队一定的自由
就好比教小孩子骑单车,必须学会放手,当驶向马路的时候,我们就要及时制止,也就是说要把握大方向
建设团队
对于技术领导人来说,更重要的是帮助你的,帮助他们,并且积极地参与到愿景的实现和调整中来
原则与标准
规则对于智者来说是指导,对于愚者来说是遵从
战略目标
- 每个公司都有自己的战略目标,但是这些战略目标的层次都很高,通常不会涉及到技术层面,比如说“开扩东南亚市场”
- 而技术架构师就需要和业务部门交互,了解公司业务的愿景以及业务的演化,从而指定公司的技术愿景
原则
- 为了达成目标一致,往往会设计一些原则,当然这些原则并不是一成不变的
- 原则不宜过多,最好是可以在一张海 上清晰明了
实践
- 实践要基于原则,更加偏向技术层面,但是实践比原则更加灵活多变
- 实践包括代码规范,日志集中捕获,接口协议规范等
原则与实践相结合
如果使用的HTTP系统,可以在URL中加上版本 来区分
分解单块系统
原因
迭代速度
-
相比于多个团队维护一个巨大的单块系统,我想一个小团队维护一个拆分后的小系统更加轻松
在一个自治单元上的迭代将更加快速
团队结构
- 当团队结构分散各地,又需要同时维护一个单体系统时,将是十分痛苦的一件事
安全
-
由于安全审计的机制,很多敏感信息需要做严密的保护
将这部分业务的代码作为单独的服务分离出去,可以做到更好的监控、传输数据的保护和静态数据的保护
技术
-
拆分为多个服务后,在单个服务的技术迭代上将更加优雅简单
比如,如果一个系统的核心功能是推荐算法,并且该算法是需要不断迭代更新的,我们就应该将该算法的代码抽离为单独的服务,交给负责算法的团队维护
分解的方式
关键
-
寻找服务的边界,然后以增量的形式进行
秉承增量的分解方式,要先找到一个拆分点,然后不断地去削减单体服务
自下而上分解
-
从数据库开始分解
:
再分解数据库时会遇到外键的问题,我们应该放弃外键的约束,使用代码来实现这个约束
这种方式可能会导致服务间多次通信达到约束的效果,降低系统的响应速度
如果系统对响应速度要求不是太高,这种拆分数据库取消外键约束的方式是一种很好的方式
:
有时候一张表设计不合理包含了多个领域的字段
比如说为了方便动态修改客户的订单信息,客户表包含了仓库和财务的的字段信息
此时就需要用到领域的抽象方式,识别出客户的界限上下文,将该表抽象为财务,仓库和客户三个服务
-
自上而下分解的好处就是,消费者基本上是无感知的,并且可以随时选择回退或者继续修改而不影响外部服务的调用
自上而下分解
-
从服务开始分解
:
从服务开始拆分,会出现为了兼容旧数据而写很多无意义的代码
:
服务变更大概率会导致接口变更,直接影响到消费者
:
但是从服务开始拆分相比于从数据库开始拆分更加简单直观
事物与一致性
在未拆分前可以通过外键的约束或者在同一张表内来达成事务的一致性,在拆分为多张表后就被分离为了多个事务
-
最终一致性:
当出现了多个事务的时候,可以使用队列来记录事务先后顺序,当其中一个事务出现异常时,可以通过捕获异常,重试的方式来保证整个系统的一致性 -
终止整个事务
当事务的异常没办法导致重试时,需要发起也就是反向操作来重置整个系统的初始状态
简单来说比如执行了add异常,那就执行delete 抵消 -
分布式事务
可以利用分布式事务特性来保证整个系统的一致性
分布式事务使用算法保证系统事务一致性,该算法有两个阶段:投票阶段与执行阶段-
投票阶段:
事务管理器会搜集所有参与者的投票,当出现一个否定的情况,就认定为失败 -
执行阶段:
会有一个中央协调进程来指挥参与者接下来的动作。
如果投票失败,中央协调者会告知所有参与者回退操作
如果成功,继续执行
缺点:
这种方式会导致参与者在投票完后暂停执行,一旦事务管理器宕机,整个系统将会暂停
并且协调进程会使用所,执行中的事务可能会对某些资源持有一个锁,导致后期系统难以扩展
-
投票阶段:
-
取舍
如果说系统对于实时性要求不高,建议使用最终一致性加事务补偿的方式来保证整个系统的一致性
表
表是对数据库中的数据的一种可视化操作,一般不包含太多的逻辑,使用SQL查询
但是 表的操作很依赖于数据库表结构,一旦表结构变更,可能会导致 表系统无法使用
调用服务获取数据
-
系统拆分后,不同数据保存在不同服务的表中,可以通过调用不同服务接口的方式来获取数据
但是一旦数据量过大或者访问频率高,这种方式的效率是很慢的
可以通过HTTP缓存或者批量请求来加速获取大文件
数据导出
-
可以将多个系统的数据导出到一个中央 表数据库,,然后使用视图之类的技术创建一个聚合。
导出数据的服务只需要知道自己的 表视图结构即可
流水线和持续交付
流水线
-
构建流水线将构建拆分为多个阶段,在每个阶段做不同的事情
比如说可以将测试拆分为快速测试阶段与耗时测试阶段,先运行快速测试阶段,如果说快速测试阶段失败了,就没必要继续运行了
持续交付
- 一个好的CD工具能够定义和可视化流水线,并对发布到生产环境的整个过程进行建模
测试
测试四象限
- 金字塔从上往下测试范围越来越小,测试用例数量越来越多,测试细粒度越来越小
服务测试
服务测试实现起来比单元测试复杂,需要利用打桩或者mock
-
打桩:对于被测试服务的一个获取数据的透明服务,测试时不关心该打桩服务被访问了多少次
-
mock: 被测试服务也可以从mock 获取需要的数据,与打桩相比mock 会进一步验证请求本身是否被正确调用
端到端测试
端到端测试会包含多个服务的测试,测试范围更大,同时测试复杂度也最大,也最不利用定位失败的位置
不管是单元测试还是服务测试,或者是端到端测试,最好的做法都是使用流水线构建做到自动化测试
-
一种坏的流水线构建方式
-
让多个流水线的服务扇入到一个独立的端到端测试的阶段
任意一个服务的构建都会触发一次端到端的测试
-
脆弱的测试
服务测试和端到端测试本身就是复杂的,容易失败的
包含在测试用的服务数量越多,测试就会越脆弱,不确定性也就越强
当脆弱性测试成为常态,测试人员可能就会对测试套件失去信心,认为这些失败是
服务测试套件应该也是迭代演化的,当一个服务测试不断失败的时候,我们就需要考虑该测试套件是否合理,然后将该失败服务测试从整个服务测试套件中移除
- 在修复这个服务测试后在重新加入,有时候可能会为了修复这个服务测试而需要改变被测试软件
谁来写测试
-
服务的测试是由维护服务的团队成员写,还是由专业的测试团队写
-
一个好的做法是共享端到端测试套件的代码权,但同时对测试套件联合负责
测试团队可以随意提交套件,但是实现服务的团队必须维护套件的健康
消费者驱动测试
-
替换端到端测试的一种方案
消费者编写测试用例,当服务发版不满足消费者测试用例时,认定服务有问题
监控
链路监控是微服务实践中最重要的环节之一
以前的单体服务,我们很直接的从单个系统日志中定位问题,但是拆分为微服务后,就会出现分布式部署的情况,有时候接口间的调用还是异步的,如果没有日志链路监控,排查问题将非常痛苦
目前市面上日志统一搜集与聚合可视化的工具已经比较成熟,logstash + kibana 就是一套标准的日志收集聚合显示的方案
但是日志链路监控的工具不是很多,相比于日志可视化没那么好用
日志链路监控的核心也是关联ID,需要有一个关联ID可以关联整个调用链路
安全
不管是单体服务还是微服务,服务安全都很重要
身份验证和授权
一些单体服务中使用的安全策略在微服务中同样是适用的,比如说秘钥验证,JWT token 验证等
静态数据的安全
可以通过加解密来保证静态数据的安全,但是一定不要自己造轮子,使用业界比较成熟的加密方式就可以了
深度防御
- 通过防火墙策略来过滤请求
- 对服务的关键操作进行日志记录,这样当出现一些非预期的操作出现时可以及时的发现
- 将不同的服务部署在不同的 络下
- 甚至可以使用比较老的操作系统,这也是我们经常看到一些安全性要求比较高的系统的桌面使用的都是比较旧的操作系统
康威定律和系统设计
康威定律
- 任何组织在设计一套系统(广义上概念上的系统)时,所交付的设计方案在结构上都与该组织的沟通结构保持一致
当协调变化的成本增加后,有一件事会发生:人们要么想方设法降低协调沟通成本,要么停止更改
而后者正是导致最终产生庞大的、难以维护的代码块的原因
- 一个团队有单个服务的所有权,将会使该团队对该服务更有责任感
内部开源
如果实在没办法让一个团队拥有单个服务的所有权,最好的做法就是使用内部开源的方式:
将开发团队分为核心提交者和代码守护者
规模化微服务
反脆弱组织
使用故障机器人猴子军队可以使你的服务更加健壮
- 混乱猴子: 在一天的特定时段随机停掉服务器
- 混乱大猩猩:随机关闭整个可用区的一部分
- 延迟猴子:在系统之间注入 络延迟
超时
-
如果等待太长时间来决定调用失败,整个系统会被拖慢
如果超时太短,会将一个可能还在正常工作的调用错认为是失败的
如果完全没有超时,一个宕掉的下游系统可能会让整个系统挂起
断路器
-
当请求下游失败达到一定阈值后,会触发断路器,认定下游服务出现故障,此时会断开与下游的连接,接下来的请求会快速的失败
客户端会发送偶尔健康检查,请求查看下游是否已经回复
如果已经恢复会重置断路器,恢复正常连接
舱壁
- 故障隔离:尽量为每个下游连接建立不同的连接池,这样当一类连接出问题时不会影响其余的连接
- 减载:实现拒绝请求的舱壁,以避免资源达到饱和
扩展
扩展原因
- 帮助处理失败,不将鸡蛋放在同一个篮子里
- 性能扩展,处理更多的负载,减少延迟
加机器
- 使用云厂商提供的ECI可以很好的对机器进行扩容或增加
拆分负载
- 将不同的服务部署在不同的主机上
分散风险
- 云厂商也不能保证其提供的服务是100%安全的,因此要考虑是否将重要服务部署在不同云上
负载均衡
-
包括硬件与软件层面的负载均衡,代价不同,各有优缺点
硬件价格高,容易出现单点故障,但是效果更好
软件可以将所有微服务都放在一个VLAN(虚拟局域 )中,然后对外提供一个统一的SSL请求入口
基于worker 的系统
-
拆分为基于worker的系统也可以很好的实现实例的扩展
但是需要一个可靠的消息队列,例如zookeeper 和MQ
自动伸缩
-
在未负载伸缩时,一定谨慎不要太仓促缩容
在大多数情况下,手头有多余的计算能力,比没有足够的计算能力要好得多
CAP定理
一致性(consistency)
- 当访问多个节点时,能达到同样的值
可用性(availability)
- 每个请求都能获得响应
分区容忍性(partition tolerance)
- 集群中的某些节点在无法联系后,集群整体还能继续进行服务的能力
在分布式系统中,最多满足CAP中的两个
AP系统
- 放弃一致性,保证分区容忍性和可用性的做法,被称为最终一致性
CP系统
- 牺牲可用性,保证系统一致和分区容忍
- 在这种模式下,服务必须考虑如何做功能降级,直到分区恢复以及数据库节点之间可以重新同步
AC系统p>
- 如果系统没有分区容忍性,就不能跨 络运行,所以CA系统在分布式系统中根本不存在
使用CP还是APp>
- 对数据不一致的容忍性有多大容忍多长时间的数据不一致性li>
服务注册与发现
-
比较成熟的服务注册与发现的工具有:
Zookeeper, Consule, Eureka
文档服务
swagger
- 对超媒体接口支持不好
HAL和HAL浏览器
- 超文本应用程序语言是一个标准,用来描述公开的超媒体控制的biaozhun
总结
对本书的总结
这本书并没有讲解微服务具体的实现细节,而是站在更高的角度去探讨微服务到底应该做什么p>
也没有明确的说明什么叫微服务,而是明确的指出微服务架构应该是一个演进式的架构,我们要做的就是拥抱变化持续演进。
这本书的后半部分则着重强调CI/CD工具对微服务的重要性,这个确实很重要,不然微服务一旦达到一定规模就是灾难。
个人对于微服务未来的展望
如果系统没有分区容忍性,就不能跨 络运行,所以CA系统在分布式系统中根本不存在
使用CP还是APp>
- 对数据不一致的容忍性有多大容忍多长时间的数据不一致性li>
服务注册与发现
-
比较成熟的服务注册与发现的工具有:
Zookeeper, Consule, Eureka
文档服务
swagger
- 对超媒体接口支持不好
HAL和HAL浏览器
- 超文本应用程序语言是一个标准,用来描述公开的超媒体控制的biaozhun
总结
对本书的总结
这本书并没有讲解微服务具体的实现细节,而是站在更高的角度去探讨微服务到底应该做什么p>
也没有明确的说明什么叫微服务,而是明确的指出微服务架构应该是一个演进式的架构,我们要做的就是拥抱变化持续演进。
这本书的后半部分则着重强调CI/CD工具对微服务的重要性,这个确实很重要,不然微服务一旦达到一定规模就是灾难。
个人对于微服务未来的展望
接下来我将系统的学习k8s 相关方面的知识,去探索微服务在云原生舞台上的表现。
文章知识点与官方知识档案匹配,可进一步学习相关知识云原生入门技能树服务 格(istio)ServiceMesh介绍8864 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!
-