微服务设计 笔记

微服务设计

一、微服务架构理论

1.六边形架构
1)六边形架构(Hexagonal Architecture),又称为端口和适配器架构风格;使用适配器与外界进行交互,外界通过应用层API与内部进行交互。
2)经典分层架构更多的精力放在抽象的分离上,每个层的职责分的很明确。 在六边形架构中,是用“组件化”的形式来避免耦合的出现,每个业务单元尽可能的最小化,这种方式用一个词来概括,那就是“扁平化”。
3)经典分层架构分为四层,而对于六边形架构,一般会分成三层:领域层、端口层、适配器层。
2.服务的大小
1)某些场景下,认为每个微服务的开发工作量不应大于2个周。
2)黄金法则,对一个微服务的修改及部署,不影响其他服务。
3.微服务的优势
1)技术异构性
2)高容错,服务可降级(舱壁)。单个服务故障,不会引起整个系统故障。
3)已于扩展 只需扩展高负载的应用即可。
4)简化部署 相对于部署单一大型应用,更简单。
5)与组织结构相匹配,易于工作分派。
6)组合、重用性。
7)可替代性优化 可以避免无法改造大型单一应用的痛苦。
4.OSGI
OSGI(Open Services Gateway Initiative)支持模块热部署,方便模块管理.但是其最终基于jvm,一个服务的故障依然会导致整个jvm crush.osgi适合构建单一服务节点的内部应用,对于微服务架构来说,大部分场景下有点不实用;java9之后推出JPMS方式,OSGI的应用场景就更受挤压了。

二、微服务架构师

1.原则
1)演化 架构师应该从演化的角度看待问题,不应关注具体技术细节,追求完美。
2)分区 架构师不应过多关注服务内部的问题,而应更多的关注区域之间的问题。
3)战略目标的设定不是架构师的职责
4)代码治理 把控范例
5)评估技术债务
6)进行例外管理
7)集中治理和团队建设
2.设计标准
1)监控 健康监控应该标准化,不应该为特定服务改变监控服务。
2)接口
a.API应该与消费方解耦,应选择技术不相关的实现方式,并易于升级,如可随意增加字段,而不影响已有消费者。
b.REST API设计应该基于“资源“,无状态,URL中不出现动词,只用名词,使用GET、POST、DELETE等操作资源。
GET:查询,POST:新增,PUT:更新,DELETE:删除
c.API应该有版本的概念。
d.使用Token进行身份校验,而不是cookie。
e.RFC标准中URL中大小写是敏感的,虽然实际使用中不敏感,但应统一使用小写,使用-而不是_做字符串分隔符。搜索引擎认为字符"-"是多个关键词,IE浏览器对"_"的支持不好。
f.速度限制
如果对访问的次数不加控制,很可能会被DDos攻击。为此RFC6585引入了HTTP状态码429(too many requests)。
Github API 使用的三个相关的头部:
X-RateLimit-Limit: 用户每个小时允许发送请求的最大值
X-RateLimit-Remaining:当前时间窗口剩下的可用请求数目
X-RateLimit-Rest: 时间 窗口重置的时候,到这个时间点可用的请求数量就会变成X-RateLimit-Limit的值
g.使用HTTP头处理缓存和并发
h.对大结果集应进行分页
i.避免多个服务共享一个数据库的情况
3)关注架构安全性 应妥善处理错误请求,可使用断路器

三、微服务建模

1.原则 高内聚 松耦合
2.使用领域工程和界限上下文来划分服务
3.避免过早划分服务
4.优先考虑地理位置和组织结构,按照技术接缝划分并不一定正确。

四、集成

1.选择合理的接口技术
2.合理选择编排与协同
通常协同可以更好的降低耦合度

3.避免灾难性故障转移 如:会导致消费者崩溃的消息,应设置最大重试次数,并及时移入死信队列。
4.按引用访问服务资源 如调用邮件发送模块时,往往是延迟发送的,发送内容可能已经被修改了,正确的方式是,只发送引用,在发送邮件时,再查询详细信息。
5.服务应该采用容错性读取。
Postel法则,鲁棒性原则 每个模块都应该宽进严出,对自己发送的东西严格,对接收的东西容错。

五、分解单块系统

1.通过界限上下文,找出系统接缝,通过接缝拆分服务及数据库。 重构数据库的最佳实践是,先分离数据库,再拆分应用。

六、部署

1.CI(Continuous Integration,持续集成)
CD(Continuous Delivery,持续交付)
a.构建流水线,将构建分解为多个阶段,快速失败。
b.在项目初始阶段,所有服务可以放在一个构建里,当服务稳定后,应该每个微服务都有自己的构建。
c.定制化镜像,加速部署;将微服务本身也预安装在镜像中,将镜像作为构建物。
d.统一配置文件管理,开发专用部署系统。

七、测试

1.消费者驱动契约测试(Consumer-Driven Contract,CDC)
CDC可以有效避免变更破坏新服务的消费者。CDC会定义消费者的期望,这些期望会变成对生产者的测试代码。
2.部署后再测试
仅仅依靠部署之前的测试,不可能把缺陷率将为0。部署与上线是不同的阶段,可以通过蓝绿部署,部署两套系统,但只有一套系统接受真正的请求。 也可以采用金丝雀发布,将一小部分真正的流量引向新版本,进行验证。
3.平居故障修复时间MTTR胜过平均故障间隔时间MTBF
4.Scrum敏捷软件开发中,将自动化测试分为了单元测试、服务测试、用户界面测试三层。

八、监控

1.使用语义监控,我们可以在生产环境运行一些测试用例,当这些案例如果没有达到我们预期的值时,我们会认为生产环境的某个环境出问题了;如定时打开首页等。
2.通过关联标识,标记调用链,例如在HTTP首部追加标识。
3.建立标准化的日志,以标准格式记录日志,统一服务指标名称(响应时间、错误率、应用指标等)。

九、安全

1.身份验证和授权方式
1)SSO
2)SAML安全断言标记语言 基于XML/SOAP的开源标准数据格式
3)OpenID Connect协议 4)单点登录网关 使用网关验证身份与授权;认证通过后,网关将主体信息放在HTTP头上。
应该进行深度防御,不应完全依赖单点登陆网关。也可以在网关上终止HTTPS,进行入侵检测等。
单点登陆网关应该只负责粗粒度的授权,细粒度的授权应该在服务中实现。
2.服务间身份验证和授权
1)在边界内允许一切。
2)使用HTTPS基本身份验证
3)使用SAML或OpenID Connect
4)使用客户端证书
5)在HTTP之上使用HAMC
当使用HTTPS性能损耗较大,且不能缓存时,可以使用HMAC。
HMAC(Hash-based Message Authentication Code,基于HASH的消息码),它使用对称密钥,将请求的主体和密钥一起,进行HASH处理。
服务器也进行hash就知道数据是否被篡改了,但不能防止数据泄露。在亚马逊S3中使用了该方式。
6)API密钥
7)SSL之上的流量不能被反向代理服务器缓存。HTTPS的CDN价格较高。
8)混淆代理人问题
成功通过认证的用户可能会伪装成其他用户,访问他人数据。
3.数据安全
使用加盐的密码hash
不应把敏感的数据写入日志
4.深度防御
防火墙/日志/入侵检测/网络隔离/操作系统
5.OWASP安全框架 安全威胁Top10

十、组织与系统设计的关系

1.康威定律
任何组织所交付的设计方案在结构上都与该组织的沟通结构保持一致。
反向康威定律
设计糟糕的系统有时迫使组织修改其结构,以适应系统。
2.组织耦合度
通常松耦合的组织开发的产品模块化更好,耦合度更低。
典型的紧耦合组织如商业产品公司,松耦合组织如开源社区。
3.组织与软件质量的关系
在windows vista的开发中发现,与组织结构相关联的指标和软件质量的相关度最高。而非代码复杂度等常见指标。
4.组织应对服务的整个生命周期负责
组织应对服务具有所有权,而非多个组织共享服务所有权。
在涉及多个组织的项目中,不共享服务所有权,会带来沟通问题。较为有效的解决方案是实行内部开源,互相开放代码与文档,像开源项目那样贡献与合并代码。
保证代码质量,与持续可维护性。
5.组织结构应该与界限上下文保持一致。
6.不同业务线间的服务应采用异步批处理方式,以便可以随时停机维护。

十一、规模化微服务

1.部署名词
1)蓝绿部署
同时部署两套冗余系统,实现不停机升级。涉及在途业务及数据迁移。
2)A/B测试
一部分用户用老系统/一部分用新系统 验证新系统可靠性。
3)灰度发布/金丝雀发布
在保持老版本可用的情况下,部署一套新系统,新系统有问题立即切换回老系统。
4)滚动发布
只有一套集群,无冗余,每次取出一部分,如20%的服务器升级,直到全部升级完成。
2.架构安全性措施
在出现故障时,应当能够恰当的功能降级,而非使整个系统下线。
要防止由于某一服务的故障导致级联大崩溃。
架构安全性措施:
超时/延迟带来的危害往往致命,要注意超时机制的使用。
断路器,下游出现问题时,及时断开,快速失败。
舱壁,隔离影响。
隔离,设计上允许下游离线,服务间相互隔离。
3.幂等
4.扩展
垂直扩展 更好的主机
拆分负载 拆分成不同服务
分散风险 分散部署
负载均衡 SSL往往会在负载均衡器前终止,为了防止信息泄露,可以尝试把负载均衡器与后端实例放在一个局域网内。
基于worker的系统 除了负载均衡,也可以通过消息队列来降低脆弱性,降低负载。
5.数据库扩展
读写分离 扩展缓存往往比读写分离更有效。
写扩展 数据分片,更好的主机,分片扩展困难,不能解决HA。
避免共享一个数据库基础设施 一个物理数据库建立多个schema。
尝试使用CQRS(命令查询职责分离模式) 将应用程序分为两部分:命令端和查询端。命令端处理程序创建,更新和删除请求,并在数据更改时发出事件。查询端负责查询。
6.缓存
1)客户端缓存/反向代理和CDN缓存/服务器端缓存(一级缓存、二级缓存)
2)HTTP缓存
a.cache-control TTL(Time To Live)指定缓存几秒
b.设定Expires头部 指定缓存到某一具体时间,如:新版本上线时间
c.设置Etag 在URL后增加随机字符串
3)必要时增加写缓存,先写缓存,再写入数据库。
4)使用弹性缓存 在下游出现故障时,使用缓存的数据,比停止服务好。
5)隐藏源服务 在缓存故障或大量失效时,要避雪崩。可以通过快速失败、数据库本地一级缓存等措施保护源服务。
6)应避免多级缓存,不要使用过长的缓存过期时间,在ISP和用户浏览器中的缓存是不受控的。
7)卫报使用了爬虫技术,爬取自己的网页,在系统故障时,有一个可使用的静态网页。
7.CAP定理
无法同时满足一致性Consistency、可用性Availability、分区容错性Partition
由于分布式系统必须要分区,所以往往权衡选择AP或CP。
可以在部分功能使用AP、另外一些功能使用CP。

十二、微服务原则

1.微服务理念

核心 自治的小服务
围绕业务概念建模
自动化的文化
隐藏内部实现细节
一切都去中心化
独立部署
隔离失败
高度可观察
2.问题
要熟悉业务领域,划分服务。
集群的部署/监控等问题。
不建议从0开发微服务,优先考虑单体服务。
不应使用数据集成。
微服务应面向业务建模,而非面向技术建模;应避免技术导向。

转载于:https://my.oschina.net/dajianguo/blog/3077962