这两天花时间看了下《微服务设计》,对微服务总算有了框架性的认知。这本书我个人总体上还是挺满意的,首先比较薄,适合快速阅读,但知识点一点也不少,作者给了很多的引用与案例,可以深入的研究下去,而且针对不同的选型给出了很多参考意见。下面是本书中我总结的相关的主要笔记。
也可以直接看我整理的大纲:
http://naotu.baidu.com/file/ec17996ffdd7db86b8bc09a8f84fd8fe?token=30c2fd9e299b9390
一、什么是微服务
微服务就是一些协同工作的小而自治的服务。其中最主要的就是两点,小跟自治。
小说的是专注做一件事,一个微服务只专注一个领域,那怎么才算小,作者给的判断方法是只要你不觉得太大了,那它就是小的,不需要拆分,如果一个系统已经感觉到代码库比较大,那就需要拆解了;
自治说的是微服务是一个独立的实体。可以独立部署,服务之间是通过网络进行通信,直接从物理上对服务进行了隔离。
微服务相对于单块服务,主要优点有:
弹性:即容错性,微服务可以很好的处理服务不可用与功能降级的问题。而单块服务只能通过部署多份以及负载均衡来降低功能完全不可用的概率。
可伸缩性:单块服务中如果存在部分功能有性能问题,也需要对整个服务进行扩展;而微服务只需要针对那些有性能问题的微服务进行扩展。
技术异构性:微服务天然的隔离,使得不同的功能模块可以采用不同的技术实现,这样使得我们可以更快的采用新的技术,并且风险较小。
微服务与SOA有什么区别?
微服务是SOA的一种特定方法,微服务在实施SOA上,有了更多具体的建议,SOA原本并没有指导如何将很大的应用程序划小。
实施微服务的原则
1.围绕业务概念建模
2.接受自动化文化
3.隐藏内部实现细节
4.让一切都去中心化
5.可独立部署
6.隔离失败
7.高度可观察
二、微服务如何实施
2.1 如何建模服务
原则:高内聚,低耦合。
有一个重要概念:限界上下文,一个由显式边界限定的特定职责。如果谈论的是某一个模块系统,那限界上下文可以认为是该模块本身以及对外接口的总和。注意共享的隐藏模型,理清内部与外部表示,不共享内部表示;确保服务边界与领域的限界上下文能保持一致,且微服务能够很好的表示这些限定上下文,这样才能做到高内聚低耦合。
不要过早对系统进行划分,应该由单块系统去逐步拆分。
服务一定会慢慢变大,直至需要拆分。
洋葱架构由于存在很多层次,纵切时会异常困难。
2.2 集成方案
避免数据库集成
REST还是RPC的问题,应该用REST做为起点
相比编排,优先选择协同
避免破坏性修改
理解Postel法则,对自己严格,对他人宽容
使用容错性读取器
将用户界面视为一个组合层
2.3 如何拆分单块系统
数据库,这通常是微服务最难拆分的一块内容。数据库的拆分,作者提供了几个思路:
打破外键
共享静态数据,类似于城市这样的公共静态数据,可以每个微服务复制一套表;也可以直接用文件方式进行存储;也可以单独抽取公共微服务。
共享动态数据,通常这些动态数据需要提取出来,单独做一个服务。
共享字典表,可以在每个微服务里有这些字典表,但是里面只保存各自服务需要的项。
数据库拆分,这是微服务拆分必须要做的事,这样才能确保数据库没有依赖。
事务,两种方法:分布式事务,或者采用最终一致性
报表,由于数据库拆分,导致的报表数据来源可能来源于多个微服务,这时候报表数据的来源就存在问题。解决方案有三个:
各微服务提供批量API,能够获取到批量的数据
将各个微服务的数据导出到报表系统中
各微服务的数据实时推送到报表系统,一般采用这种方案,延时较小
2.4 如何部署
持续集成至微服务,确保每个微服务有一个CI
为微服务构建流水线和持续交付
构建物的种类:平台特定的构建物、操作系统的构建物、镜像作为构建物
尽量保证每个服务一个容器,相对可以简化部署
拥抱自动化,如果没有自动化,微服务的部署非常困难
2.5 如何测试
测试种类:功能测试,UAT测试,端到端的测试,冒烟测试,CDC测试
消费者驱动的契约测试 (CDC)测试方法只测试单个微服务,而且只测试生产者,并且该微服务的所有外部合作者都被打桩或者mock;
作者建议尽量用CDC测试来替代端到端的测试,原因在于端到端的测试很难发挥作用;
但CDC的测试也有一些限制场景,尤其是针对第三方的API进行测试,就没有办法使用。
2.6 如何监控
监控分两类:服务监控与系统监控。
服务监控:
对每个服务而言,最低需要监控的有:请求响应时间,错误率,下游服务的健康状况,下游服务的响应时间与错误率。
标准化收集指标以及存储指标。
系统监控:
标准化关联标识,能够对整个请求链路做监控。比如zipkin
聚合CPU之类的主机指标。
使用可查询工具来对日志进行聚合和存储。比如Kibana ElasticSearch
2.7 安全措施
身份认证与授权,相关技术:SSO与OpenID
服务间的身份认证与授权,作者整理了三种方式:
隐式信任,即边界内允许一切
验证调用方身份
要求调用方提供原始主体的凭证
静态数据的安全
尽量使用众所周知的算法进行加密,比如AES-128/AES-256,还有加盐密码哈希;以确保加密算法的安全性
对于数据存储与备份也需要进行加密
深度防御
日志:剔除敏感信息
防火墙
入侵检测
网络隔离
操作系统,定期打补丁
三、微服务规模化运作
这是本书的重点,也是微服务在运维中的重点。
首先有一个重要的观点:在分布式架构中,故障无处不在。本身网络就是不可靠的,所以故障难以避免。而且在规模化后,故障也成了必然事件。针对不可避免的故障,不要试图浪费太多的时间,而是应该花更多的时间去优雅的处理它们。作者举了一个谷歌管理硬盘的例子:谷歌把硬盘暴露在服务器机箱外,并且扣在尼龙搭上面,是为了在硬盘坏掉后,很快的换掉它们,而不是试图去阻止硬盘损坏。
架构性安全措施:
这里有个很重要的观点:响应非常缓慢是最糟糕的故障模式之一。如果一个系统宕掉了,你会很快发现。但当它只是很慢时,你需要等待一段时间,然后再放弃。并且响应缓慢的请求会占用保贵的连接池资源,会影响到其它的功能。
怎么去解决:设置超时,断路器,舱壁,隔离(上游服务允许下游服务离线),幂等
重新设计
设计系统应该考虑10倍容量的增长,但超过100倍容量时就要重写了。
不要一开始就构建大规模系统;有可能构建出来是不需要的。
伸缩数据库
读伸缩:主从复制
写伸缩:分片
选择NoSQL
命令查询职责分离(Command-Query Responsibility Segregation)+事件溯源(Event Sourcing)
缓存
三种缓存:
客户端缓存,即浏览器缓存,受HTTP缓存相参数的控制:cache-control,Expires,Entity Tags
代理缓存,专门服务器设置在实际源服务前面,如:Squid, Varnish, Apache Traffic Server
服务端缓存,比如Redis,Memcache
问题:
隐藏源服务,大量缓存失效时,大量的请求会被放送到源服务,可能会导致源服务宕掉。解决方案是:在缓存失效时,可以让原始请求快速失败,向源服务推送异步消息,由后台重建缓存。
缓存中毒,在Expires:Nerver情况下,缓存永远不会失效,直到浏览器缓存已满或者用户手动清理它们。解决方案是:改变这些网页的URL,以便重新获取它们。
CAP理论
即一致性(Consistency)、可用性(Availability)、分区容忍性(partition tolerance)只能保证其中两个。
因此,分布式系统中每一个功能,只能在一致性与可用性中保证一个。
AP:会存在过时数据,但是可以保证可用性与最终一致性;举例:库存查询
CP:强一致性,快速失败。举例:转帐
服务发现与服务注册
相关技术:DNS,zookeeper, consul, eureka
文档服务
相关技术:Swagger, HAL
四、架构师职责
演进式架构师应该承担的职责:愿景,同理心,合作,适应性,自治性,治理。
代码治理:范例,服务代码模板
五、微服务团队
康威定律:任何组织在设计一套系统(广义上概念上的系统)时,所交付的设计方案在结构上都与该组织的沟通结构保持一致。强调了试图让系统设计与组织结构不匹配导致的危险。
小团队会比大团队的工作更有效。两个比萨团队:即没有一个团队应该大到两个比萨不够吃。
适应沟通途径
团队之间的沟通会有成本,如果多个团队负责同一个系统,有一件事情最终会发生:人们要么想方设法天协调/沟通成本,要么停止更改。而后者正是导致我们最终产生庞大、难以维护的代码库的原因。
如果构建系统的组织更加松耦合,其所构建的系统则倾向于更加模块化, 因此耦合度更低;一个拥有许多服务的单个团队对其管理的服务会倾向于更加紧密的集成,而这种方式在分布式组织中是很难维护的。