架构师训练营 第十周 学习总结
一. 微服务
1. 微服务架构
1.1 注册中心
注册中心可以说是微服务架构中的”通讯录“,它记录了服务和服务地址的映射关系。在分布式架构中,服务会注册到这里。当服务消费需要调用其它服务时,就到这里找到服务的地址,进行调用。
1.2 服务提供者
服务提供将自己的服务信息注册到注册中心,并通过心跳检测维持链接,实时更新链接信息。当服务下线时,注册中心会发通知给服务消费。
1.3 服务消费者
通过注册中心获取需要的服务信息,然后去调用相关服务。
2. 微服务需要支持的特性
2.1 失效转移
对于大型网站的微服务而言,即使是很少的访问的简单服务,也需要集群部署。同时还需要支持服务提供者的失效转移机制,以实现服务的高可用。
2.2 负载均衡
对于集群部署的服务提供者,服务请求者可以使用加权或者轮询的方式,是服务提供者集群实现负载均衡。
2.3 高效的远程通信
对于大型网站,核心服务可能会调用数以亿计的次数。如果没有高效的通信手段服务调用者可能会成为整个系统性能的瓶颈。
2.4 对应用的最少入侵
网站技术是为业务服务的,是否使用微服务需要根据业务发展规划,微服务也需要渐进式的演化。
2.5 版本管理
为了应对快速变化的需求,服务器版本升级不可避免,如果仅仅是服务实现升级,这个升级对服务而言是透明的。如果是服务的访问接口发生变化,就需要服务消费者和服务提供者同时升级才不会导致服务调用失败。企业应用系统可以申请停机维护,同时升级接口,而网站服务不可能中断,需要服务提供者既要升级接口,并同时提供历史版本的服务供服务消费者调用,当服务消费接口升级完成后才能将历史版本的服务关闭。
2. 微服务架构实践
2.1 微服务架构落地
业务先行,先理解业务边界和依赖,技术是手段而不是目的。
先有独立的模块,后有分布式服务。
业务严重耦合,逻辑复杂多变的系统进行微服务重构要谨慎。
要搞清楚实施微服务的目的是什么,业务复用?开发边界清晰?分布式集群提升性能?
2.2 命令和查询职责隔离(CQRS)
在服务接口层面将查询(读操作)与命令(写操作)隔离,实现服务层的读写分离。
更清晰的领域模型。
针对读写分别优化,实现更好的性能。
查询服务不会修改数据,更好的保护数据。
2.3 事件溯源
将用户请求处理过程中的每次状态变化都记录到事件日志中,并按时间序列化进行持久化存储。
利用事件溯源,可以精确复现任何用户状态,进行复核审计。
利用事件溯源,可以有效健监控用户状态变化,并在此基础上实现分布式事务。
2.4 断路器
当某个服务出现故障,响应延迟或者失败率增加,继续调用这个服务会导致调用者请求阻塞,资源消耗增加,进而出现服务级联失效,这种情况下使用断路器阻断对故障服务的调用。
断路器的三种状态: 关闭,打开,半开
2.5 服务重试及调用超时
上游调用者超时时间要大于下游调用者超时时间之和。
2.6 需求第一
需求(Needs)
价值(Values)
原则(Principles)
最佳实践(Practices)
工具(Tools)
3. RPC 协议实现原理
3.1 远程过程调用(RPC)
3.1.1 RPC架构基本组件
客户端(Client):服务调用方(服务消费者)
客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端
服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理
服务端(Server):服务的真正提供者
3.1.2 具体调用过程
服务消费者(client客户端)通过本地调用的方式调用服务
客户端存根(client stub)接收到调用请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息体
客户端存根(client stub)找到远程的服务地址,并且将消息通过网络发送给服务端
服务端存根(server stub)收到消息后进行解码(反序列化操作)
服务端存根(server stub)根据解码结果调用本地的服务进行相关处理
本地服务执行具体业务逻辑并将处理结果返回给服务端存根(server stub)
服务端存根(server stub)将返回结果重新打包成消息(序列化)并通过网络发送至消费方
客户端存根(client stub)接收到消息,并进行解码(反序列化)
服务消费方得到最终结果
3.1.3 为什么要设计私有协议
充分并有效利用通讯协议中的每个字段,减少冗余数据传输。
灵活满足自定义通讯需求,例如 CRC校验,Server Fail-fast,自定义序列化器。
最大程度满足性能要求:IO模型和线程模型的充分利用。
常见协议模式
序列化协议
4. API网关
4.1 作用
统一接入,路由转换,高可用,高并发。
安全防护,防刷控制,黑白名单。
流量管控与容错,限流,降级,熔断。
协议适配,http,dubbo,jsf。
4.2 开放授权协议 OAuth 2.0
四种授权方式
授权码
隐式授权
密码式
凭证式
授权码模式
5. 领域驱动设计 DDD
5.1 为什么需要 DDD
过去系统分析和系统设计都是分离的,需求分析的结果无法直接进行设计编程,而能够进行编程运行的代码却扭曲需求,导致客户运行软件后才发现很多功能不是自己想要的,而且软件不能快速跟随需求变化。
DDD则打破了这种隔阂,提出了领域模型概念,统一了分析和设计编程,使得软件能够更灵活快速跟随需求变化。
DDD与传统CRUD或过程脚本或者面向数据表等在开发效率上比较
5.2 领域
领域是一个组织所做的事情以及其包含的一切,通俗的说就是组织业务范围和做事方式,也是软件开发的目标范围。
领域驱动设计就是从领域出发,分析领域内模型及其关系,进而设计软件系统的方法。
5.3 子域
子域就是领域内可拆分的独立的模块,多个子域组成一个完整的领域。
5.4 界限上下文
在一个子域中,会创建一个概念上的领域边界,在这个边界中,任何领域对象都只表示特定于该边界的确切含义。这样的边界称为限界上下文。
通常限界上下文对应一个组件或者一个模块,或者一个微服务。
5.5 上下文映射图
不同界限上下文,也就是不同的子系统或者模块之间会有各种的交互合作。DDD使用上下文映射图来设计这种交互。
5.6 实体
领域模型对象也被称为实体,每个实体都是唯一的,具有一个唯一标识,一个订单对象是一个实体,一个产品对象也是实体,ID是他们的唯一标识。实体可能会发生变化,例如状态会发生变化,但是他们的唯一不会变。
实体设计是DDD的核心所在,首先通过分析,识别出实体对象,然后通过相关的业务逻辑设计实体的属性和方法。重要的是把握住实体的特征是什么,实体应该承担什么职责,不应该承担什么职责,分析的时候要放在业务场景和界限上下文中,而不是想当然地认为这样的实体就应该承担什么责任。
5.7 值对象
并不是领域内的对象都应该被设计为实体,DDD推荐尽可能将对象设计为值对象。
值对象的一个特点是不变性,一个值对象创建以后就不能再改变了。
5.8 聚合
聚合是一个关联对象的集合,我们将其作为一个单元处理数据更改。每个集合都有一个根和一个边界。边界定义了聚合的内容。根是聚合中包含的单个特定实体。
聚合根:将多个实体和值对象聚合在一起的实体。
5.9 DDD 分成架构
领域实体的组合调用和事务控制在应用层。
5.10 DDD 六边形架构
领域模型通过应用程序封装成一个相对比较独立的模块,而外部的系统通过不同的适配器和领域模型交互。
5.11 战略设计和战术设计
DDD战略设计: 领域,子域,界限上下文,上下文映射图。
战术设计: 实体,值对象,聚合,CQRS,事件溯源。
通过战略设计,划分模块和服务的边界及依赖关系,对微服务的架构设计至关重要。
版权声明: 本文为 InfoQ 作者【李君】的原创文章。
原文链接:【http://xie.infoq.cn/article/3602981916cc72563be3b6052】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论