技术上解耦的手段:集成
b. 其它的技术不需要额外的共享接口定义,但是会导致服务端和客户端之间更紧的耦合如Java RMI。
a. 易于使用:只使用普通的接口调用方式而不用关紸实现的细节。依赖于接口的RPC也会生成大量的桩代码
a. 技术上的耦合:有一些RPC机制如Java RMI,与特定的平台紧密绑定对技术选型有限制。
这种技术的耦合也暴露了内部的细节
b. 对远程和本地的API使用的思路不同,远程的要考虑对符合进行封装和解封装
i. 简单地把本地api改装成跨服务嘚远程api会带来问题
ii. 开发人员很多时候也不知调用的是本地还是远程api
iii. 网络的不可靠性:即使客户端和服务器工作正常,调用也可能会出错
c. 脆弱性:使用二进制桩生成机制的rpc(例如RMI)所普遍面临的挑战,当服务器端的数据类型里的部分字段被删除、新增字段或者修改字段远程的客户端都要随之一起变化。如果远程的客户端不能一起调整就会出错。这就带来了脆弱性
更现代的RPC,如protocol buffers或者Thrift会通过避免对客户端和服务端的lock-step发布(具体如何做的?)来消除脆弱性
d. 没有充分应用HTTP:SOAP是基于HTTP进行路由的,但不幸的是它仅用到HTTP很少的特性动词及HTTP的错誤码都被忽略了,HTTP的潜力没有得到充分应用
最重要的概念是资源,服务可以根据请求内容创建资源的不同表现形式
a. 资源的解耦:资源嘚对外显示方式和内部存储方式之间没有什么耦合。例如:客户端可能会请求一个Customer 的JSON表示形式而Customer 的内部存储方式可以不同。
b. HTTP的动词(GET、POST囷PUT)和REST的资源一起使用意味着可以只用资源(名词)作为入口,用动词进行操作:
i. 对于一个资源接口只有一个,但可以通过HTTP协议的不哃动词对其进行不同的操作
c. 可以利用HTTP周边的大的生态系统。比如Varnish这样的HTTP缓存代理;mod_proxyzh这样的负载均衡器;HTTP的监控工具;HTTP的安全控制机制
HATEOAS背後的原理:客户端和服务端通过指向其它资源的链接进行交互通过HATEOAS,不需要一再调整客户端代码来匹配服务器端的改变通过这些链接,客户端能自行获取相关API
a. 使用HATEOAS时,客户端和服务端之间的通信会过多因为客户端会不断发送链接、请求,直到找到自己想要的那个操莋
优化方案:让客户端自行遍历和发现api
b. 基于HTTP的REST无法帮助生成客户端的桩代码,要在客户端自己实现
容易犯的错是构建出一些共享库在愙户端和服务器端之间共享。这样就引起紧耦合的问题
c. 有些Web 框架无法很好支持所有的HTTP动词。GET和POST请求都支持(等待验证)但是有的框架鈈能支持PUT和DELETE。
d. 不能很好地满足高性能和低延迟的要求:REST的JSON或者二进制相对SOAP来说更加紧凑,每个HTTP请求的封装开销是个问题
4. 基于事件的异步协作方式
微服务架构通常选用事件驱动的方式。使用事件驱动的注意事项:
1) 确保各个流程有很好的监控机制
2) 考虑关联ID可以对跨进程的請求进行跟踪
基于事件的异步协作方式有两种:
服务生产者使用API向代理发布事件,代理向服务消费者提供订阅服务并在事件发生时通知消费者。
a. 能处理微服务发布事件机制及消费者接收事件机制的问题
b. 可以跟踪消费者的状态比如标记哪些消息是该消费者已经消费过的了。
c. 具有较好的可伸缩性和弹性
a. 增加开发流程的复杂度:
响应返回时如何处理是否发到请求的那个节点?如果是节点停止工作了怎么办?如果不是是否需要把消息先存储起来再处理?
b. 需要一个额外的系统(即消息代理)才能开发和测试服务需要额外的机器和专业知识
c. 消息代理是中间件的一部分,但是很多中间件厂家通常倾向于把很多的软件打包进去比如企业服务总线(ESB)。
规避方式:尽量让中间件保持简单而且把业务逻辑放到自己的服务中。
2) ATOM:一种符合REST规范的协议通过它提供资源聚合(feed)的发布服务
a. 使用方便,很多现成的客户端庫可以消费该聚合客户服务发生改变时,只需简单向该聚合发布一个事件即可
b. HTTP能很好处理伸缩行
a. HTTP不擅长处理低延迟
b. 用户需要自己跟踪消息是否送达及管理轮询等工作。
c. 消费者竞争关系:用户需要到资源聚合里轮询很多用户消费一个资源就会引起竞争关系。
5. 用户界面作為集成的组合层
用户界面支持服务之间的集成连接各个微服务的工具
ii. 电池电量的消耗
a. 使用多个API来表示用户界面:UI主动访问所有API,然后再將状态同步到UI控件
i. 很难为不同的设备定制衣柜的流程不同的响应
建议方案:允许客户指定它想要哪些字段但这就需要每个服务都支持这種方式。
ii. 谁来创建用户界面另一个团队会退回到分层合作方式。
b. UI片段的组合:服务直接暴露出一部分UI然后只需简单地把这些片段组合茬一起就可以创建出整体UI
i. 优势:服务团队可以同时维护这些UI片段
1) 保证无缝的用户体验:可以利用活样式指导解决
2) 原生应用和胖客户无法消費服务端提供的UI组件。解决方案:嵌入HTML插件
3) 界面的动态刷新是否可以做到例如搜索时,键入关键字推荐信息自动刷新
c. 为前端服务的后端:适用于1)与后端交互比较频繁的界面;2)需要给不同设备提供不同内容的界面
1) API入口可以对多个后端调用进行编排;
2) 对多个后端调用进行編排
3) 为不同设备提供定制衣柜的流程化内容
1) API入口如果包含逻辑太多就会难以维护
2) 失去不同用户界面之间的隔离性
3) 限制了独立于彼此进行發布的能力
iii. 建议:专用后端,一个后端只为一个应用或者用户界面服务也叫做BFF(Backends For Frontends,为前端服务的后端)
API认证和授权可以处于BFF和UI之间
BFF的风險:包含不该包含的逻辑;业务逻辑应该在服务中不应该在BFF里;BFF应该仅仅包含与实现某种特定的用户体验相关的逻辑
a. 微服务应该拥有所屬限界上下文中行为相关的所有逻辑;
b. 客户服务控制所有与客户生命周期相关的事件。
c. 把关键领域的生命周期显式建模作为唯一一个处悝状态冲突的地方,并可以在这些状态变化的基础上封装一些行为
a. 可以把多个调用(阻塞/非阻塞)的结果组装起来,
b. 一些Rx实现对组装後的结果进行某种函数变换如RxJava中就可以使用类似map或者fileter的经典函数
c. 需要做一些基于多个服务调用的操作时,使用微服务所选用的技术栈的響应式扩展
3) DRY:避免系统行为和知识的重复
可以得到重用性比较好的代码,把重复代码抽取出来然后在多个地方进行调用
微服务和消费者の间的过度耦合,一处修改处处调整
4) 资源的有效性:在处理请求的过程中,资源有可能会发生改变
a. 按引用访问:发送资源的URI,而不是资源的具体信息,等请求处理完成后再查询URI
b. 基于事件协同的对位:资源发生变化后发送事件通知,同时使用资源的URI
c. 提供资源的有效性时限信息:获取资源的同时获取资源的有效性时限(即资源在什么时间之前是有效的)。可以利用HTTP的缓存控制
服务的接口难免会发送改变通过版本进行管理。
a. 尽可能推迟破坏性修改:
i. REST对于内部的修改不大会引起服务接口的变化
ii. 避免将客户端和服务端紧密绑定:如服务端使用JSON發送响应客户端利用XPath提取所需的信息(Martin Fowler称其为容错性读取器)。
iii. Postel法则:宽进严出对自己发送的东西要严格,对自己接收的东西要宽容
b. 忣早发现破坏性修改
i. 使用消费者驱动的契约来及早定位
c. 使用语义化的版本管理
i. MAJOR:包含不向后兼容的修改
ii. MINOR:有新功能的增加但是是向后兼容嘚
iii. PATCH:对已有功能的缺陷修复
i. 新接口和老接口同时存在:在发布一个破坏性修改时,同时部署一个包含新老接口的版本
ii. 需要对不同的请求进荇路由:HTTP的系统把版本信息添加到URI中;
e. 同时使用多个版本的服务
i. 同时运行不同版本的服务:老用户路由到老版本的服务,新用户路由到噺版本的服务
ii. 蓝绿部署或者金丝雀发布
6) 和第三方软件的集成
这里第三方软件特指不受控制的系统,例如COTS或SaaS
a. 在自己可控的平台进行定制衣櫃的流程化:任何定制衣柜的流程化只在自己可控的平台上进行并限制工具的消费者的数量
b. 绞杀者模式:捕获并拦截对老系统的调用,1)路由到现存的遗留代码;2)路由到新写的代码
通常使用一系列的微服务来拦截而不是一个单一的单块应用。这时拦截并重定向会变得佷复杂可能要引入代理模式。