本文我们将讨论一些经常用在微服务应用中可扩展的设计模式:
起因
Uber, Gilt和其它的公司由于需要做应用扩展,已经将单体应用转变成为了微服务架构. 由于一个单体应用将所有的功能都运行在一个进程中,如果要扩展,就需要复制整个应用,这显然有局限性.
在集群关系数据库中严格遵循数据库范式的表显然不易扩展,因为分布式的事务和Join会引起并发的瓶颈.
微服务架构模式就是将一个应用开发成一些小的可独立部署的服务,每个服务都实现自己的一些功能. 微服务方式与典型的大数据部署是相融合的.你可以通过将服务部署到许多普通的硬件服务器上来实现模块化的、可扩展的并行处理及基于成本有效的可扩展服务. 微服务的模块性实现了独立的更新和部署,避免了单点故障,能防止大规模的服务不可用.
事件流
当将一个单体应用转到微服务架构时,事件溯源就是一个使用了只追加模式事件流的普通架构模式s,比如Kafka或MapR Streams (此框架提供了Kafka 0.9 API) . 通过用MapR Streams (或 Kafka),事件被分组成一些逻辑上的事件集合叫做Topics(主题). Topics被分区以便并行处理. 你可将一个已分区的Topic想象成一个队列, 事件以它们被收到的顺序被投递.
但与队列不同的是,事件是可被持久保存的,即使它们被投递了,它仍然保存在分区里,以便其它的消费者来消费.
旧消息被自动删除,取决于Stream的存活期设置,如果存活期被设置为0,那么消息永远不会被删除.
当消息被读后并不会从Topic里删除,topic可以有多个不同的消费者,这就允许同一条消息可被不同的消费者因不同的目的被处理. 管道技术使得消费者可将一个事件加工后再转发到另一个topic.
事件溯源
事件溯源架构模式是一个应用状态由事件的序列来决定的模式,每个事件被记录在一个只追加模式的事件存储或流中.作为一个例子,你可把每个事件想象成诸如一个对数据库条目的增量更新. 在这个例子中,一个特殊条目的状态只是简单的对所从属的条目的事件累积. 在下面这个例子中,流持久化了所有存款和取款的事件队列,并且持久化了当前的账户余额.
那么流和数据库哪个将是更好的记录系统呢? 流中的事件可用于重新构建数据库中的当前账户余额,但反之不然. 数据库的复制实际上就是通过主库将事件更改写入更改日志中,然后消费者即备库在本地重做事务更改事件. 类似的另一个很有名的例子就是源代码版本控制系统.
有了流,事件可被重放用于创建新的视图,索引,缓存和内存镜像或者数据的物化视图.
消费者只是简单地读取从最旧到最新的消息来创建一个新的数据视图.
用流来模块化应用状态有一些优势:
MapR Streams的复制提供了强大的测试或调试技术. 一个流的复制可用于重放事件的版本用于测试或调试目的.
满足不同需求的数据库和模式
市面上有很多数据库,每种数据库都使用了不同的技术,取决于数据是如何被用于和优化读写模式的: 图查询,搜索,文档... 如果你要为不同的数据库或不同的查询类型请求提供相同的数据集时该怎么办? 流可扮演多个数据库的分布式连接点,每个点提供不同的读模式. 应用状态的所有变化都被持久化到一个记录系统的事件存储器中. 这个事件存储器可用于通过重新运行流中的事件来重编译应用的状态.
事件通过漏斗的方式进入到流消费者所在的数据库中.通晓多语言的持久性提供了不同的特定物化视图.
CQRS
命令和查询职责分离 (CQRS)模式是一个将读模型和查询从写模型中隔离出来的模式,且命令通常使用事件溯源. 让我们来看下一个在线的购物应用的物品打分功能是如何通过CQRS模式来做到隔离的. 下面这个单体应用展示的功能由用户对他们已购买的物品进行打分和在购物时浏览已打分的物品组成.
在下面的CQRS设计中,我们使用事件溯源将给物品打分“命令”(写)从获取物品打分“查询”(读)中隔离出来. 给物品打分事件被分发到流中. 处理器进程从流中读取并持久化物品打分的物化视图到NoSQL的文档型数据库中.
NoSQL和反范式
通过使用MapR-DB,表可自动的根据键的范围被分区到集群里, 每台服务器存储一张表的一个子集. 根据键的范围对数据分组可做到对行键的快速读写. 通过MapR-DB 你可以设计你的数据库模式做到被同时读进的数据都被存储在一起.
有了 MapR-DB,你可以将多张遵循关系型数据库范式的表用反范式的方式存储到一张表中.如果你的实体存在一对多的关系, 那么那是有可能将它转化为 MapR-DB HBase的一行或MapR-DB JSON 的一个文档. 在下面的这个例子中,物品和其被打的分都存储在一起,而且也能够通过索引的行键一同被读出来.这就比Join表读得更快.
事件溯源: 对数据的新用法
使用事件流来给物品打分和其它与购物相关的事件的优势都列在了这里. 这个设计可让我们对数据的使用更广泛. 原始的或被加工过的事件可存储到像MapR-FS这样较便宜的存储上. 历史的打分数据可用于构建推荐系统的机器学习模型. 队列中的数据有一个长的记忆时间也是很有用的.例如, 那些数据可用于构建一个存储在Parquetr 上的历史购物事务集合,Parquetr 对查询很高效. 其它的进程可能会使用历史数据和实时的购物事件流数据并结合机器学习来做到对购物趋势的判断或反作弊调查或实时显示事务在哪里发生的.
流行零售商的事务驱动架构
一个主流的零售商需要提高旺季存货单的灵活性来对需求的变化和减价做快速的响应. 这个事件驱动架构如下:
总结
本文我们讨论了使用以下设计模式的事件驱动微服务架构: 事件溯源,命令查询职责分离和通晓多种语言的持久性. 在架构中讨论的所有组件都可运行在基于MapR集中数据平台的同一集群上.