WeText项目:一个基于.NET实现的DDD、CQRS与微服务架构的演示案例
最近出于工作需要,了解了一下微服务架构(Microservice Architecture,MSA)。我经过两周业余时间的努力,凭着自己对微服务架构的理解,从无到有,基于.NET打造了一个演示微服务架构的应用程序案例,并结合领域驱动设计(DDD)以及命令查询职责分离(CQRS)体系结构模式,对事件驱动的微服务系统架构进行了一些实战性的探索。现将自己的思考和收获整理成文,分享给大家。
微服务架构
在介绍源代码之前,我还是想谈谈微服务架构,虽然网上有很多有关微服务架构的讨论,但我觉得在此再多说一些还是有必要的。大师级人物Martin Fowler在他谈论微服务的个人主页上提到,微服务并没有一个非常明确的定义。事实上有很多种分布式系统的实现都可以被看成(或者说勉强看成)是面向微服务架构的。就我个人而言,我觉得微服务架构应该满足以下几个特征:
- 整个系统被分为多个业务功能相对独立的一体化架构(Monolithic Architecture,或称单一化架构)的应用程序(也就是所谓的“微服务”),每个微服务通常遵循标准的分层架构风格或者基于事件驱动的架构风格,能够对自己相关的领域逻辑进行处理,使用本地数据库进行数据存储,并向上层提供相对独立的API接口或者用户界面。每个微服务还可以使用诸如缓存、日志等基础结构层设施,但如果是与其它的微服务公用这些设施,则该基础结构层设施需要满足下面的第三条特征
- 各个微服务之间可以使用以下方式进行通信(参见:http://howtocookmicroservices.com/communication/)
- 同步方式:最为常见的是基于RESTful风格的API,也可以是跨平台、跨语言的Apache Thrift IDL
- 异步方式:使用轻量级的消息通信机制,比如RabbitMQ、Redis等
- 整个系统是“云友好”(cloud-friendly)的。所谓的“云友好”,是指:
- 针对每个微服务,都应该避免单点失败的可能。例如针对一个系统中某个微服务A,需要有至少两个(或以上)的运行实例,并由API网关(API Gateway)或者负载均衡器(Load Balancer)根据一定的规则(比如各个A的运行实例的健康程度等)将来自客户端的服务请求分配到任意一个A的运行实例上完成处理
- 针对每个微服务,管理员可以根据一些特定的实时技术指标对这些应用程序的部署进行调整。例如,购物网站的查询服务负载明显要高于订单管理服务,那么管理员可以根据实际情况,增加查询服务的部署量(比如部署3个查询服务的实例),同时减少订单管理服务的部署量。与整个系统单一采用一体化架构相比,这样做的好处是显而易见的,它能够充分利用云端服务器资源,使得每个微服务都能够运行在合理的资源配置状态下,减少资源浪费
- 公有基础结构层服务设施也应该满足避免单点失败的条件,例如数据库服务需要配置Replication/Clustering,消息队列也需要使用类似的fault tolerance策略
- 基于“云友好”的需求,衍生了一大堆的部署和运维问题,比如微服务本身的配置模式(每台机器配置多个实例?还是每台机器配置一个实例?还是每台虚拟机配置一个实例?又或者是将实例配置到类似Docker这样的容器中)?消息队列如何配置才能支持同一个微服务的多个实例不会重复处理相同的消息?基于RESTful的通信如何让客户端找到动态改变的API地址?等等。我想,这些问题并没有一个特定的答案,还是需要根据实际情况来进行判定
相比传统的一体化架构系统,微服务架构系统有着以下一些优势:
- 每个微服务都相对较小,这样更加便于开发和调试
- 每个微服务都相对独立,这样不仅可以使开发人员仅关注在某个业务处理部分,而且还可以针对每个微服务自己的特征,采用不同的技术实现(比如部分微服务使用C#实现,部分使用Java或者Python等)
- 这种独立性使得微服务在容错隔离方面也有很好的表现:比如某个微服务出现了crash等问题ÿ