同时也可以看到有一Command命令都是采用异步事件的方式进行写入,因此不存在同步和长连接占用的问题,有利于提升整个平台在大并发下的整体响应性能 。
当然,采用CQRS模式最大的一个问题点就是无法实现命令和查询两部分内容的强一致性保障,即很可能你界面上查询到的数据不是最新的持久化数据库里面的数据,这个本身和消息管道异步写入的实时性有关系 。
其次在使用CQRS模式的时候,有一个重要假设就是,在事件和命令发出后,无特殊情况在事件接收方都必须要能够接收事件成功处理,否则就存在大量的异常错误消息的异步回写,反而增加系统的复杂度 。举个简单例子来说:
当我们在电商平台购买一个商品的时候,只要订单提交成功,那么这个订单就一定能够生效,也一定有库存能够发运和配送,而不是在后续到了配送环节的时才发现没有库存而导致订单取消 。如果这样的话就极大的降低了系统本身的易用性 。即在异步命令和事件发送场景,当命令发送成功时候,虽然我们没有及时接收到处理方的事件处理结果信息,但是我们默认是接收方能够成功处理事件 。但是我们也看到在CQRS场景框架下,只要命令事件发出,我们并不需要等待任何反馈信息 。
另外还有一种CQRS实现场景,即虽然在内部对Command命令处理的时候是基于事件机制,异步响应,但是客户在前端的操作是同步等待返回 。在这种情况下我们就可以保持前端连接,但是是否后端的类似DB连接等 。
在CQRS模型下,由于职责分离,可以看到我们通过事件和消息的订阅,可以实现多个读库的订阅,这些读库既可以是结构化数据库,也可以是非结构化数据库;既可以用来实现业务功能本身的查询读,也可以用来做海量数据本身的分布式全文检索 。
对于CQRS框架的实施,不是简单的设计模式使用问题,更加重要的仍然是是否能够接受最终一致性要求,同时在该要求下将传统的同步请求下业务功能和逻辑处理机制转变为异步事件价值下的事件链驱动模式 。要实现这种转变就必须能够拆分出独立,自治的命令和事件,同时确保这些事件在朝后端业务功能和逻辑模块发送的时候能够处理成功(即该做的校验必须提前做完) 。
将同步接口调用转为本地消息缓存这个类似消息中间件的功能,举例来说我们设计了一个同步发送订单到ERP系统的接口,如果在同步实时调用这个接口服务的时候出现异常,那么我们可以首先将消息存储到本地,然后设置定时任务和重试机制,通过重试方式将消息发送到目标系统 。
即对于业务功能来说不用关心实时是否发送成功,而由业务系统自身机制来完成消息发送的重试 。
而要做到这点,在接口功能设计时候,最好要做到单据业务完整性校验接口和实际的数据发送接口分离,即先调用接口进行完整性校验,在校验没有问题后再进行消息发送 。以确保最终发送的消息不会因为数据完整性的原因导致无法发送成功 。
查询数据的本地化缓存或落地
文章插图
memcached是一套分布式的高速缓存系统,由LiveJournal的Brad Fitzpatrick开发,但被许多网站使用 。这是一套开放源代码软件,以BSD license授权发布 。对于实时查询类接口,将查询的基础数据进行本地化缓存,即如果在实时查询出现异常的时候,我们可以直接查询本地缓存的数据,减少对业务功能使用的影响 。
memcached的API使用三十二比特的循环冗余校验(CRC-32)计算键值后,将数据分散在不同的机器上 。当表格满了以后,接下来新增的数据会以LRU机制替换掉 。由于memcached通常只是当作缓存系统使用,所以使用memcached的应用程序在写回较慢的系统时(像是后端的数据库)需要额外的代码更新memcached内的数据 。
比如查询供应商接口服务,如果主数据系统提供的接口出现异常,我们可以直接查询本地缓存的供应商数据 。这种模式对于变更不频繁的数据基本都适应,同时本身也减少实时调用接口带来的性能损耗 。如果是接口服务注册在API网关或ESB服务总线上面,我们还可以考虑在ESB服务总线上启用缓存能力,即对于调用过的接口,在同样参数重复调用的时候能够通过缓存数据获取,这样即使在源端业务系统不可用的情况下,也不好影响到当前接口服务的成功调用 。
可以适度考虑数据落地
推荐阅读
- 利用USO服务将特权文件写入武器化
- 微软承认Windows 10新BUG:错误显示没有网络连接
- 英雄联盟特权服务15个皮肤有哪些?
- 哪些高速公路收费站和服务区关闭关停?何时开放?怎样绕行?公示汇总信息在这儿查
- 福建白茶区土壤介绍,安溪试用微生物技术降解茶叶农药残留
- 微服务核心技术——负载均衡
- 超简单本地备份服务器搭建攻略
- 花了17年!微软修复Windows DNS服务器漏洞
- 微博|还有两个月退休,我该什么时候向领导提出交接工作?
- 分布式系统架构之构建你的任务调度中心