架构师训练营 1 期 -- 第十周总结
巨无霸架构产生的问题:
部署,编译困难
版本管控困难
团队协作困难
数据库连接池耗尽
耦合性高,系统之间互相影响,一个模块出问题(OOM),导致其它模块受牵连。
在微服务之前,也曾出现过 Web Service,使用一个注册中心,服务提供方注册服务,服务调用方发现服务并调用。这是注册发现机制的前身,虽然 Web Service 没有火起来,但是后来的微服务框架都采用了它的思想。
微服务框架需要考虑的技术功能点包括:
负载均衡,微服务框架应该实现负载均衡策略,调用方不用自己去实现它。
失效转移,一点服务调用失败,微服务应该能切换到其它服务进行调用。
高效的远程通信,调高性能,节省开销。
无侵入,尽量降低对代码的侵入,不影响业务开发。
服务版本管控,多版本同时存在,不同的客户端或者不同版本的客户端可以调用不同的版本。
Service Mesh 是一种服务网格技术,在微服务的基础上,再抽象出一层服务调用层,应用程序只需要与 Service Mesh 通信,而不用去关注服务的注册与发现。Service Mesh 在负载的应用系统中会带来一些优势,如果服务调用简单,还是需要慎重考虑。
微服务落地需要遵守的一些原则:
业务先行,先理清业务关系,确立好模块的职责,再考虑是否上微服务。如果要上微服务,也需要明确上微服务的目的是什么。
命令去查询职责隔离(CQRS),查询服务只提供查询功能,命令服务只提供数据操作功能。这样可以针对不同的服务做性能优化,同时也可以减少出错的可能。
时间溯源,按照时间顺序记录所有的数据操作日志,可以清楚的复现问题,也可以做事件的回滚。
需要设计好断路器,当部分服务不稳定时,断路器打开,减少对不稳定服务的调用,有利于提高整个服务的稳定性。
上游服务的调用超时时间应该大于下游服务的超时时间,如果上游服务超时时间小于下游服务超时时间,可能会出现大量的调用超时。
在技术的道路上,需要遵守的一个重要原则时,需求最大原则,应该从需求考虑,能带来什么价值,我们的原则是什么,然后再去实践,最后是选择合适的技术或工具。(Need->Value->Principle->Practise->Tools)。
在微服务系统中,几乎所有的请求都经过网关,网关的作用可以有很多,但都是一些非业务的功能,如鉴权,限流,降级,数据整合,负载均衡等等。在网关中,一般使用管道方式处理请求,也就是我们常见的责任链模式,这样可以比较灵活的添加或重组功能。
Flower 中的异步网关是使用了 Server3 中的异步请求功能,当前线程关闭后,HTTP 连接不关闭,其它线程依然可以通过 socket 发送数据给客户端。
对于要实现开放平台网关的服务,可以使用 Oauth2.0 技术。Oauth2.0 包含了资源所有者,资源提供方,客户端,以及授权中心。一个典型的基于 Code 验证模式的授权流程如下(以微信登录为例):
第三方应用提供微信登录连接。
用户点击微信登录,跳转到微信授权服务器提供的微信登录页。
用户扫码登录,通常会把用户 ID 和 redirectUrl 带过去。
扫码验证通过后,表明用户同意授权,则返回 Code。
然后跳转到 redirect,会带上用户 ID 和授权 Code。
第三方应用拿到用户 ID 和授权 Code,再向微信授权服务器发起请求,获取 token。
授权服务器验证,通过后返回 token。
第三方应用携带 token 访问资源服务器,就是微信服务器,获取相关资源,如头像,好友列表等。
在微服务设计中,与微服务技术或框架相比,更重要的是对业务的数据服务模块的拆分,可用到的一些方法包括 DDD。
与领域模型对应的是事务脚本,事务脚本的设计方式是将应用系统分成 controller,service 和 dao 等,大量的业务逻辑处理放在 service 中,而 service 和 dao 这些类,一般也不包含数据,只有方法,所以也成为贫血模型。与之对应的领域模型是指面向现实时间的模型编程,一个对象既包含状态数据,又包含与之对应的业务处理的方法,这种设计也被成为充血模型。
领域是一个组织所有做的所有事情,一个领域的范围通常比较大,可以对其进行拆分,划分成多个子域,与之相关的另一个概念是界限上下文,它限定了子域的边界,一般来讲,子域是逻辑上的划分,界限上下文是物理上的划分。域,子域,界限上下文以及界限上下文图,都是 DDD 中战略上的设计。
领域模型对象也叫实体,一般包含各种属性和相关计算的逻辑。与实体对应的是值对象,实体的状态是可以改变的,值对象的属性通常是不变的。而聚合是一个关联对象的集合,一个微服务中可以包含一个或多个聚合。 实体,值对象,聚合,聚合根是 DDD 中的战术设计。
软件设计是一项需要长时间积累的工作,体现了一个工程师的核心竞争力。
在软件设计过程中,组件需要遵守以下高类聚原则:
复用发布等同原则,你想要用户已怎样的粒度使用你的组件或服务,那你就用这样的粒度去设计它。个人觉得这条原则非常有用,微服务的粒度是很难把控的,遵守这个原则就不会困惑。另外在版本发布时,版本号应该使用主版本.次版本号.修订号的格式。
共同封闭原则,就是那些需要共同修改的类,应该放在同一个组件中。
共同复用原则,组件不应该强迫用户依赖他们不需要的类。
同时,组件设计需要遵守以下低耦合原则:
无循环依赖,直接和间接的循环依赖都是不好的,容易影响文件的稳定和问题的排查。
稳定依赖原则,不稳定的组件应该依赖稳定的组件。
稳定抽象原则,组件的抽象化程度,应当与其稳定性一致。这给我们的指导性意义是,如果一个组件它是不稳定的,那么可以设计出一组接口,把这组接口封装在一个专门的组件中。JDBC 就是一个稳定抽象的例子,其具体实现是不稳定的,而接口时稳定的。
组件的高类聚低耦合原则,只是给我们在组件设计时提供一些指导思想,通常还需要结合实际的业务场景或其它因素来进行设计。
在做具体的软件设计时,架构师应该更多的把精力放在问题本身,对其进行分析,整理,归类,划分出系统边界,进而进行软件设计。而不应该直接说我们用某个技术来解决某个问题。
评论