架构师训练营第一期 - 第十周学习总结
微服务架构是目前互联网系统的主要架构方式,很多人搞微服务关注的重点是微服务的框架如何使用,甚至很多时候只是关注RPC远程调用,但这并不是微服务关注的重点,怎么设计好的服务才是微服务最重要的点。
国内最开始搞微服务的是阿里,是因为庞大的单体架构系统带来了困难:一是一个war包几个G,编译、部署困难;二是代码分支管理困难,代码merge 的时候总会发生冲突;三是数据库连接耗尽,集群里每台服务器都需要建立所有应用的数据库连接,几百上千台的服务器连接数据库就把数据库资源耗光了;
四是新增业务困难,想要在一个已经如乱麻般系统中增加新业务、维护旧功能,难度非常大。
解决方案就是拆分,将模块独立部署,降低系统耦合性:
纵向拆分:将一个大应用拆分为多个小应用,如果新增业务较为独立,那么就直接将其设计部署为一个独立的Web应用系统。
横向拆分:将复用的业务拆分出来,独立部署为微服务,新增业务只需要调用这些微服务即可快速搭建一个应用系统。
因此就产生了微服务,独立维护,独立开发,职责变得清晰、简单,应用间的依赖也变少了,问题就变少了。
十几二十年前的SOA就展现了微服务的思想。Web Service 虽然有着成熟的技术规范和产品实现,以及在企业应用领域有许多成功的案例,但是也具有一些固有的缺点:臃肿的注册与发现机制,低效的XML 序列化手段(超过一半的信息是冗余无效的),开销相对较高的HTTP 远程通信,复杂的部署与维护手段。
这些问题导致Web Service 难以满足大型网站对系统高性能、高可用、易部署、易维护的要求,因此就被后来兴起的微服务替代了。
微服务框架除了要支持服务注册与发现、服务调用等标准功能,还需要能够支持负载均衡、失效转移、高效的远程通信、版本管理及对应用无侵入这些功能。
最近几年比较火还有一个比较火的Service Mesh,它其实是在微服务框架框架的基础上增加了一个Service Mesh的实例层。Service Mesh从架构原理的角度讲是对微服务的调用构建了一个虚拟层,服务调用,服务发现,服务的路由配置相关的这些都由Service Mesh虚拟层去做。它从架构理念上是符合整个架构发展方向的,但是你要使用虚拟层那就意味着你是足够复杂的,要屏蔽掉这些足够复杂的东西它才能带来价值、简化问题。现在看来,Service Mesh对复杂的场景还是合适的,没那么复杂的场景去使用Service Mesh还是要慎重考虑。
微服务架构落地的关注点:业务先行,先理顺业务边界和依赖,技术是手段而不是目的;先有独立的模块,后有分布式的服务;业务耦合严重,逻辑复杂多变的系统进行微服务重构要谨慎;要搞清楚实施微服务的目的是什么:是业务复用还是开发边界清晰或者是提升分布式集群性能。
微服务相关的其他一些最佳实践策略:
命令与查询职责隔离(CQRS):在服务接口层面将查询(读操作)与命令(写操作)隔离,实现服务层的读写分离。其带来的好处是更清晰的领域模型、针对读写分别优化,实现更好的性能、查询服务不会修改数据,更好地保护数据。
事件溯源:将用户请求处理过程中的每次状态变化都记录到事件日志中,并按时间序列进行持久化存储。利用事件溯源,可以精确复现任何用户状态、进行复核审计,还可以有效监控用户状态变化并在此基础上实现分布式事务。
断路器:当某个服务出现故障,响应延迟或者失败率增加,继续调用这个服务会导致调用者请求阻塞,资源消耗增加,进而出现服务级联失效,这种情况下使用断路器阻断对故障服务的调用。断路器的三种状态:关闭,打开,半开。
服务重试及调用超时:上游调用者超时时间要大于下游调用者超时时间之和。
所有技术都应该遵循的一个落地的指导思想是:先有个需求即想要达到什么样的目标,然后有了目标以后,再去分析达到这个目标能带来什么价值,为了达到这样的价值应该遵循什么样的原则,基于这些原则有哪些最佳实践可以去参考,实现这些最佳实践的工具框架技术手段有哪些,最后选择一个合适的工具框架去解决我们的问题。
对于微服务的调用是通过一个统一网关来完成的,微服务网关具备如下功能:
1.统一接入,由网关实现负载均衡、高性能、高并发、高可靠;
2.安全防护,防刷控制,黑白名单,拦截网络攻击即各种注入操作;
3.协议适配,可以适配多个微服务框架协议,支撑多种微服务调用;
4.流量控制和容错,进行限流、降级、容错,保护整个系统;
网关本身没有什么业务,主要职责是做各种校验与拦截,这些职责可以通过管道技术连接起来,实现管道技术的责任链设计模式。
微服务的设计主要是使用领域驱动模型DDD,通过DDD把业务理清了,从而开发出更好的微服务。很多项目的实际情况是:用户或者产品经理的需求零零散散,不断变更;工程师在各处代码中寻找可以实现这些需求变更的代码,修修补补;软件只有需求分析,并没有真正的设计,系统没有一个统一的领域模型维持其内在的逻辑一致性;功能特性并不是按照领域模型内在的逻辑设计,而是按照各色人等自己的主观想象设计。
在了解DDD之前,需要先了解两个概念:贫血模型和充血模型。对象只有方法没有成员变量,需要进行方法调用时使用数值对象进行参数传递,这样的模型叫做贫血模型。对象既有方法没又有成员变量的模型叫充血模型。
领域模型是合并了行为和数据的领域的对象模型。通过领域模型对象的交互完成业务逻辑的实现,也就是说,设计好了领域模型对象,也就设计好了业务逻辑实现。和事务脚本被称作贫血模型相对应的,领域模型也被称为充血模型。
DDD可分为战略设计和战术设计两大块。DDD的战略设计包括:领域战略设计主要从业务视角出发,建立业务领域模型,划分领域边界,建立通用语言的限界上下文,限界上下文可以作为微服务设计的参考边界。战术设计则从技术视角出发,侧重于领域模型的技术实现,完成软件开发和落地,包括:聚合根、实体、值对象、领域服务、应用服务和资源库等代码逻辑的设计和实现。
软件需要进行模块化、组件化设计。组件的设计遵循高内聚低耦合原则,分为组件内聚原则和组件耦合原则。
组件内聚原则主要讨论哪些类应该聚合在同一个组件中,以便组件既能提供相对完整的功能,又不至于太过庞大。它包含如下三个原则:
1.复用发布等同原则:软件复用的最小粒度应该等同于其发布的最小粒度。也就是说,如果你希望别人以怎样的粒度复用你的软件,你就应该以怎样的粒度发布你的软件。这其实就是组件的定义了,组件是软件复用和发布的最小粒度软件单元。这个粒度既是复用的粒度,也是发布的粒度。
2.共同封闭原则:应该将那些会同时修改,并且为了相同目的而修改的类放到同一个组件中。而将不会同时修改,并且不会为了相同目的而修改的类放到不同的组件中。
3.共同复用原则:不要强迫一个组件的用户依赖他们不需要的东西。
组件耦合原则讨论组件之间的耦合关系应该如何设计。它包含如下三个原则:
1.无循环依赖原则:组件依赖关系中不应该出现环。如果组件A 依赖组件B,组件B 依赖组件C,组件C 又依赖组件A,就形成了循环依赖。
2.稳定依赖原则:组件依赖关系必须指向更稳定的方向。较少变更的组件是稳定的,也就是说,经常变更的组件是不稳定的。根据稳定依赖原则,不稳定的组件应该依赖稳定的组件,而不是反过来。
3.稳定抽象原则:一个组件的抽象化程度应该与其稳定性程度一致。也就是说,一个稳定的组件应该是抽象的,而不稳定的组件应该是具体的。这个原则对具体开发的指导意义就是:如果你设计的组件是具体的、不稳定的,那么可以为这个组件对外提供服务的类设计一组接口,并把这组接口封装在一个专门的组件中,那么这个组件相对就比较抽象、稳定。
评论