《微服务设计》4、5章笔记
上一篇 《微服务设计》1~3章笔记
第四章 集成
目标:
- 保持自治
- 独立修改和发布
4.1 寻找理想的集成技术
- 避免破坏性修改
- 保证api的技术无关性
- 使你的服务易于消费者方使用(使用客户端库会有耦合问题)
- 隐藏内部实现细节(修改服务本身对消费者而言不修改)
4.3 数据库集成
- 消费者不修改表结构
- 数据库是共享的大API,同时也不稳定。
更改可能需要做大量的回归测试。 - 现在看来似乎关系型数据库有优势。
或许以后会发现非关系型才是更好选择 - 行为(服务怎么共享行为呢?)
而且很难做到不被破坏。
4.4 同步与异步
- 同步:似乎很合理,反馈成功与否。
- 异步:对运行时长较长的,较为有用。(保证网卡)
技术复杂性。
事件发布协作
对于整个系统都是很聪明的。
业务逻辑并非集中在某个核心大脑,而是平均分布在不同的协作者中。
4.5 编排与协同
编排:驱动整个流程
缺点
- 中心控制承担太多职责,会导致一些“上帝”服务、贫血服务、基于curd的服务。
- 不稳定
- 修改代价大
协同
各个部分清楚自己各自的职责。
- 优点-->消除耦合。
- 缺点-->看不到明显的业务流程。
==》结合领域模型
==》可以和异步结合
4.6 远程过程调用
RPC主要卖点:简单容易使用。
问题:
- 技术耦合(比如:java RMI)
- 本地调用和远程调用是不同的,
性能问题在RPC服务,封装+解封
网络本身是不可靠的 - 脆弱性(所有客户端重新生成桩,对象序列化的问题)
- RPC很糟糕么?
protocol buffer 或 Thrift 可以消除部分问题。
注意:不要对远程调用过度抽象,确保你可以独立升级。
4.7 REST
本质:资源概念
REST和HTTP
- http缓存代理
- 负载均衡
- 对终端用户透明
- 安全控制
- 有不少很好的特性与标准
留心过多的约定
- 不要轻易暴露存储对象
- 服务是由消费者需求驱动衍生出来的(推迟了数据存储的集成)
缺点
- 无法帮助你生成桩代码。==》又会走回rpc的服务器与客户端共享库。
- 性能。(封装性能问题?)
- webscoket性能更高(更低的延迟)
- udp或者其他的rpc框架
4.8 实现基于事件的异步协作方式
**技术选择(服务发布事件+消费者接收事件)** - mq(代价:服务器+流程) - atom(使用方便,追踪消息+管理轮询) 还可以自定义
异步架构的复杂性
- 不仅是发布,而且怎么响应处理呢?
- 思维上的转变
- 建立死信对立(存储失效的消息)
- 建立管理ID
4.11 微服务世界中DRY和代码重用的危险
> Don't Repeat Yourself ! 不要拷贝代码 分布到各个系统中,只会产生各种问题bug.
问题
- 共享库,对微服务来谁可能是危险的。(耦合)
- 跨服务调用也很有可能引入耦合!!
- 作者经验:在跨服务中可以偶尔违反 DRY。
- 服务之间耦合可能带来更大的问题。
4.12 按引用访问
思考:如何传递领域实体?
微服务应该包含核心领域实体全生命周期的相关操作。
- 传递所有用户信息?写入队列,处理时候用户信息被改了怎么办?
解决-->传入userId(缺点:负载问题-->加缓存) - 有些服务并不需要整个用户信息
https://martinfowler.com/articles/richardsonMaturityModel.html
4.13 版本管理
- 尽可能推迟(不改+避免client与server耦合)
- 宽进严出
对自己发送出去的数据严格,对接收的东西要宽容。 - 及早发现破坏性修改
- 使用语义化的版本管理
http://semver.org/lang/zh-CN/
5. 不同的接口共存(保留老接口)
扩展、收缩模式
扩展服务的能力,对老的消费者采用新的方式,收缩API去掉旧的功能
==》多个版本实体(痛苦)
6. 同时使用多个版本的服务
老用户路由到老服务,新用户路由到新服务。(比较难)
怀疑?
第五章 分解单块系统
恐怖而庞大的存在
5. 1 关键是接缝
理清楚代码库,甚至识别出服务边界。
5. 2 分解MusicCorp
给代码找位置,剩下的就是上下文的代码。
5. 3 分解单块系统的原因
增量开凿!!
- 改变的速度
- 团队结构
- 技术
5. 4 杂乱的依赖
识别出哪些接缝会比较难处理。
5. 6 识别出关键性问题
- 工具SchemaSpy
- 识别出不同上下文的表之间的耦合
5. 7 打破外键关系
- 两次服务调用代替外键!(一定程度的慢是可以接受的)
- 系统的期望行为是什么,跟着它去做决定。
5. 8 共享静态数据
解决:
- 复制表
- 共享静态数据到代码,或放到一个枚举。
- 放到一个服务去
5. 9 共享数据
可变数据共享,是一个麻烦。
领域概念不是在代码中建模,相反是在数据库中隐式进行建模。
财务服务-->客户服务
仓库服务-->客户服务
5. 10 共享表(分离)
5. 11 重构数据库
实施分离(不影响消费者)
5. 12 事务边界
分离后就被抹掉了。
- 再试一次-->最终一致性(√)
- 终止整个操作(重置会最初的状态)
- 分布式事务(两阶式提交)
- 应该怎么处理呢?
5. 13 报告(日志监控)
5.15 通过服务调用获取数据
多次调用多次封装,大量数据就不适用了。
报告系统
- 依赖一些sql接口
- 遍历所有用户,显得低效。
- 解决,调用生成存储的cvs,共享位置下载。
5.16 数据导出
导出到单独的数据库(去除耦合)
建议:导出程序和报告系统版本控制。
也可以使用视图(聚合),性能取决于你选的数据库
另一个方向
- 一系列的json数据导出到AWSS3,数据集市。
- 数据量很大之后就不适用了。
5.17 事件数据导出
- 好处:与源微服务底层数据库耦合消除了。
- 关键:设计事件
- 缺点:事件广播,数据量大的时候
思考:
数据备份?
5.19 走向实时
所有都要马上输出么?
5.20 修改的代价
- 要知道,改变会影响多少东西。
- 在白板上写上服务边界,运行用例,然后就会发生什么呢?
类-职责-交互(写卡片,理清楚自身和其他东西的关系)
5.21 理解根本原因
大服务拆分小服务。为什么要这样做呢?
- 服务一定会慢慢变大的。
- 巨大到不健康之前,发现它。
推荐书籍:《修改代码的艺术》