前言
前面我们有文章介绍了架构设计的目标以及DDD相关的领域知识,本章重点会介绍DDD到底在架构设计中解决了什么问题。
1. 系统复杂性的6个来源以及通用解法
架构设计的目标是管理系统复杂性以及高效率匹配资源。那系统复杂性源于好处呢?
1.1 高性能
软件系统找那个高性能带来的复杂性主要体现在两方面:
- 单台计算机内部为了高性能带来的复杂性
单机为了压榨服务器资源使用率,会由单进程单线程演变成多进程多线程模式。多进程让多任务能够并行处理,但有可能要解决进程间的互相通信问题,包括管道、信号量、消息队列、套接字、共享存储等。而在单进程内部,多子任务的并行处理交由多线程来处理。有了多线程后,操作系统调度的最小单位就变成了线程,而进程变成了操作系统分配资源的最小单位。
- 集群性能带来的复杂性
让多台服务器配合起来达到高性能,常见的方式有任务分配和任务拆解。
任务分配
任务分配是每台服务器都能完整处理业务任务,不同的任务分配法不同的机器上。常见的任务分配方式如硬件(F5、交换机),软件(LVS)、负载均衡(Nginx,HAProxy)或者自研调度。任务分配带来了新的问题:
- 任务分配需要将不同的任务分配到不同的服务器
- 服务器数量增多,状态管理和故障处理难度增大
任务分解
任务分配能够突破单机服务器性能瓶颈,但是如果业务本身负责,单纯通过任务分配,边际效应递减。所以有一种新的方式——任务拆解,将复杂的任务拆解成小而简单,多个子任务配合完成。任务分解能提升性能的主要点是:简单系统能够更容易做到高性能,而且子任务拆解后,更能发现性能瓶颈点,针对单个瓶颈点改造风险小、收益好。但拆解任务不是万能的:
- 任务拆解理论上有一个阈值,不是拆解得越细越好
- 系统增多,链路变长,时延和状态维护复杂度增加,运维成本上升。
1.2 高可用
高可用的本质是通过增加冗余机器来做备份。常见的做法有
- 计算高可用:计算不能调度到哪一台服务器,相同的输入和算法,产出的结果相同。
- 存储高可用:存储高可用需要将数据从一台服务器搬迁到另一台服务器,有线路传输。存储高可用的难点不在于如何备份数据,而在于如何减少或者规避数据的不一致性。
1.3 高扩展性
可扩展性是系统为了应对未来需求变化而提供的一种能力,当有新需求出现的时候,无需改动或者只需要少量改动即可支持。设计良好的系统,具有两个特性:
- 正确预测变化:预测变化的复杂性在于:不能为每个设计点都考虑扩展性、不能完全不考虑扩展性以及所有的预测都存在错误的可能。所以如何预测变化会是一件负责的事情,没有通用标准,更多的是经验、直觉。
- 封装变化:应对变化常见的做法有封装变化,提炼出一个“抽象层”和一个“实现层”。抽象层是稳定的,实现层可以根据具体业务需要定制开发,当加入新的功能时,只需要增加新的实现,无须修改抽象层。
1.4 低成本
低成本本质上和高性能、高可用是冲突的,低成本很多时候不是架构设计的目标,而是架构设计的约束。低成本往往给架构设计带来的挑战是:只有创新才能达到低成本目标。这里的创新包括:开创一个新技术、引入一个新方案等;
1.5 安全
从技术角度讲,安全分为功能安全和架构安全。
- 功能安全:常见的 XSS 攻击、CSRF 攻击、SQL 注入、Windows 漏洞、密码破解等,本质上是因为系统实现有漏洞。从实现角度来看,功能安全更多和具体的编码相关,是一个攻防的矛盾体,只能在攻防中逐步完善;
- 架构安全:传统的架构安全主要通过防火墙来隔离网络,但性能一般,而且资源耗费大,所以互联网领域架构安全并没有太好的设计手段,更多依靠运营商或者云服务商的大带宽、大流量能力。
1.6 规模
规模的复杂性通常由”量变引起质变“,常见的有:功能越来越多,系统复杂性上升;数据越来越多,系统复杂性上升。
2. 微服务解决的高可用、可扩展性问题以及问题
微服务架构通过对系统做拆分,解决了应用高可用和可扩展性问题,但是微服务相对于单体服务,引入了新的问题:
- 复杂度提升:系统增多,从团队管理和系统融合上负责度都有数量级提升
- 成本上升:每项微服务都有自己的成本
- 性能下降:微服务链路变长,系统性能下降。
3. DDD帮助微服务控制规模复杂度
微服务设计后期会面临一个必选题:服务的粒度拆分到何种粒度?这个问题引申开来,就会形成微服务拆分的边界,只有确定了服务边界后这个问题才能迎刃而解。
DDD能够帮助我们设计出清洗的领域和应用边界。DDD包含战略设计和战术设计两部分。战略设计主要从业务视角出发,建立业务领域模型,划分领域边界,建立通用上下文语言边界,这些边界就可以作为微服务设计的参考。战术设计则从技术视角出发,着重于领域实现,包括聚合根、值对象、领域服务、应用服务和资源库等代码逻辑实现。
领域设计中,建立领域模型是重中之重,针对领域模型的建立,有一些列的方法。常见的流程有:
- 在DDD战略设计中,采用用例分析法,梳理业务过程中的用户操作、事件和外部依赖,从而梳理出领域实体对象;
- 根据领域实体之间的业务关联性,形成聚合,确定聚合中的聚合根、值对象和实体;
- 根据业务和语义边界,将聚合划定在一个限界上下文内,形成领域模型。这些限界上下文可以作为微服务设计的参考边界,从而确定了应用端的微服务边界。