前段时间跟一个朋友聊起kafka,flint,spark这些是不是某种分布式运算框架。我自认为的分布式运算框架最基础条件是能够把多个集群节点当作一个完整的系统,然后程序好像是在同一台机器的内存里运行一样。当然,这种集成实现方式有赖于底层的一套消息系统。这套消息系统可以把消息随意在集群各节点之间自由传递。所以如果能够通过消息来驱动某段程序的运行,那么这段程序就有可能在集群中任何一个节点上运行了。好了,akka-cluster是通过对每个集群节点上的中介发送消息使之调动该节点上某段程序运行来实现分布式运算的。那么,kafka也可以实现消息在集群节点间的自由流通,是不是也是一个分布式运算框架呢?实际上,kafka设计强调的重点是消息的接收,或者叫消息消费机制。至于接收消息后怎么去应对,用什么方式处理,都是kafka用户自己的事了。与分布式运算框架像akka-cluster对比,kafka还缺了个在每个集群节点上的”运算调度中介“,所以kafka应该不算我所指的分布式运算框架,充其量是一种分布式的消息传递系统。实际上kafka是一种高吞吐量、高可用性、安全稳定、有良好口碑的分布式消息系统。

kafka的本质是一种commit-log,或者“事件记录系统”:上游产生的数据(即事件)会按发生时间顺序存入kafka,然后下游可以对任何时间段内事件按序进行读取,重演运算产生那段时间内的某种状态。这不就是妥妥的CQRS模式吗?当然kafka也可以使用在其它一些场景如:消息队列,数据存储等,不过这些都是commit-log的具体应用。

常常看到网上有朋友抱怨akka-cluster的一些处理方式太底层或太基础了。用户往往需要自己来增加一些方法来确保使用安全。我想作为一种消息驱动系统,如何保证akka消息的正确产生和安全使用应该是最基本的要求。而恰恰akka是没有提供对消息遗漏和重复消息的保障机制。我想这也是造成akka用户担心的主要原因。上面提到kafka是一种高吞吐量、高可用性、安全稳定的分布式消息系统,特别是它提供了对exactly-once,“保证一次”的消息使用支持。那么通过kafka实现一套CQRS模式的实时交易处理系统应该是可行的。这也是我使用kafka的主要目的。

上面提到,希望能充分利用kafka commit-log特性来开发一个基于CQRS的实时交易系统,比如支付系统、库存管理系统,从实践中了解kafka。kafka支持多种语言终端,怪异的是没有scala终端。kafka是用scala开发的,不提供scala终端实在是说不通啊。不过akka在alpakka社区提供了alpakka-kafka:这个东西是个基于akka-streams的kafka scala终端编程工具,稍微过了一下,感觉功能比较全面,那就是它了。不过在开始前先把kafka的原理和基本情况做个介绍:

从表面上看kafka就是一个简单的消息存储和传递工具。不过因为其特殊分布式的消息发布、存储、读取处理机制,使其成为一种高吞吐量、高可用性、安全稳定的分布式消息处理工具。从应用角度来讲,kafka应用包括三个方面,kafka本身,就叫kafka引擎吧,发布终端、订阅终端,即:kafka,writer,reader三部分,其中:所有复杂的功能实现是包嵌在kafka内部的,writer,reader应该整合到用户应用里。kafka的作业是围绕着消息的发布订阅/读写进行的。所谓消息即CQRS模式里的事件。那么kafka的工作原理直白点就是writer向kafka写事件,kafka把事件按发生时间顺序保存,reader再按顺序从kafka读取事件并进行处理以产生新的业务状态,如在某个库位的一个商品数量得到了更新。当然原理看似简单,但具体的实现才是真正复杂的地方。

首先,writer和reader是以事件关联的,即:write发布某种类型的事件,而reader则是订阅相同类型的事件。 这里的事件也就是topic,或一项业务,如:图书类当前库存。为了提高数据吞吐量,每个topic又可以细分为多个partition。每个partition分担所属topic消息类型下的一些指定的细分类消息或者事件,如"图书库房101"。如果把这些partition再分布到一个集群的节点上,就可以实现高吞吐量的分布式读写,然后通过集群partition的复本同步又可以达到数据安全及系统高可用性的目的。这些集群节点就是所谓的broker了。发布消息内容由topic,key,value所组成。其中key值指定该消息应该写入那个partition,即通过对key进行hash计算得出partition id。hash算法可以保证相同的key值永远指定同一个partition。值得注意的是kafka保证每个partition上的事件肯定按照发生时间排序,所以要保证一种事件只能写入同一个partition。当然,一个partition可以承载多种事件。要注意的是创建topic和partition都是严格的管理工作admin,不是在某些程序中任意进行增减的。一般来讲,在创建一个新topic时就要确定它下面的partition数量了。这个partition数量要按照对数据吞吐量需求设定。但一般是集群节点的倍数,这样partition可以均匀分布在各broker上。

好了,该到reader这头了:reader作业从订阅某个topic开始。上面提过:一个topic下面可能有多个partition,但每个partition都会包含topic的其中几个子业务的全部事件,而且这些事件是严格按发生时间排序的。kafka有个reader group这么个概念:针对同一个topic,容许有一组多个reader对这个topic下的partition进行读取。但每个partition只容许组内一个reader读取。至于goup内reader是如何分配partition的完全由kafka内部解决。如果发现新partition或者组内reader有增减变化,kafka会自动进行再分配rebalance。所以总的来说订阅某个topic的一个组内reader应该负责那个partition是不确定的,加上随时可能发生动态再分配的情况,比如组内某个reader出问题倒了。换言之组内所有reader都必须具备处理整个topic所有类型业务的能力,如此才能解决组内reader-partition关系不确定的难题。kafka最重要的特点就是可以容许不同的应用通过不同的reader-group对同一个partition上的事件进行任意读取,本意应该是不同的应用可以利用同一个业务事件序列进行不同的业务处理。具体实现方式应该是每个组对某个partition上事件最后读取的位置分别进行了登记,offset-commit。这样,即使发生了重新分配rebalance组内任何一个reader对分配到的partition应从那个位置开始读还是确定的。这个offset-commit方式描述了几种事件读取模式:

1、at-most-once, 最多一次:如果刚读取事件,在进行业务处理之前就登记位置commit-offset,那么commit-offset后位置已经登记,即使业务处理失败也再也不可能二次读取了。

2、at-least-once,最少一次:读取事件、完成业务处理后才commit-offset。如果处理业务中系统故障,只能从上次登记的位置重新读取了,那么就会出现重复读取的情况。

3、exactly-once, 保证只一次:控制commit-offset的时间节点是取得at-most-once, at-least-once之间安全系数的一种方式。但exactly-once不容许有模糊地带。具体做法是把业务处理和commit-offset作为一个完整事物单元来处理(atomic-transaction)。两样操作同时成功或失败。

我觉着kafka的exactly-once能力最值得推介。因为在akka或者其它消息队列工具里不容易得到保证。而在一个消息驱动的实时交易系统里,保证事件重演能正确反映当时状态是关键。任何事件遗失或重复都会造成不可逆转的误差。那么下面的一系列讨论我就会尝试用alpakka-kafka来构建一个基于CQRS模式的实时交易系统,并和大家进行交流分享。

kakafka - 为CQRS而生fka - 为CQRS而生的更多相关文章

  1. CQRS+ES项目解析-Diary.CQRS

    在<当我们在讨论CQRS时,我们在讨论些神马>中,我们讨论了当使用CQRS的过程中,需要关心的一些问题.其中与CQRS关联最为紧密的模式莫过于Event Sourcing了,CQRS与ES ...

  2. .net架构设计读书笔记--第三章 第10节 命令职责分离(CQRS)简介(Introducing CQRS)

    一.分离查询命令 Separating commands from queries     早期的面向DDD设计方法的难点是如何设计一个类,这个类要包含域的方方面面.通常来说,任务软件系统方法调用可以 ...

  3. Web API与OAuth:既生access token,何生refresh token

    在前一篇博文中,我们基于 ASP.NET Web API 与 OWIN OAuth 以 Resource Owner Password Credentials Grant 的授权方式( grant_t ...

  4. CQRS学习——最小单元的Cqrs(CommandEvent)[其一]

    [说明:博主采用边写边思考的方式完成这一系列的博客,所以代码以附件为准,文中代码仅为了说明.] 结构 在学习和实现CQRS的过程中,首要参考的项目是这个[http://www.cnblogs.com/ ...

  5. CQRS:When to use CQRS

    Now that we are at the end of our journey, we can suggest some of the criteria you should evaluate t ...

  6. 后端开发实践系列之四——简单可用的CQRS编码实践

    本文只讲了一件事情:软件模型中存在读模型和写模型之分,CQRS便为此而生. 20多年前,Bertrand Meyer在他的<Object-Oriented Software Constructi ...

  7. CQRS项目

    CQRS+ES项目解析-Diary.CQRS   在<当我们在讨论CQRS时,我们在讨论些神马>中,我们讨论了当使用CQRS的过程中,需要关心的一些问题.其中与CQRS关联最为紧密的模式莫 ...

  8. .NET 5 源代码生成器——MediatR——CQRS

    在这篇文章中,我们将探索如何使用.NET 5中的新source generator特性,使用MediatR库和CQRS模式自动为系统生成API. 中介者模式 中介模式是在应用程序中解耦模块的一种方式. ...

  9. DDD CQRS架构和传统架构的优缺点比较

    明天就是大年三十了,今天在家有空,想集中整理一下CQRS架构的特点以及相比传统架构的优缺点分析.先提前祝大家猴年新春快乐.万事如意.身体健康! 最近几年,在DDD的领域,我们经常会看到CQRS架构的概 ...

随机推荐

  1. ScheduledExecutor定时器

    为了弥补Timer 的上述缺陷,在Java 5的时候推出了基于线程池设计的 ScheduledExecutor.其设计思想是:每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互 ...

  2. android自带下拉刷新SwipeRefreshLayout

    也是一个布局容器,只有一个子组件,类似scrollView <?xml version="1.0" encoding="utf-8"?> <a ...

  3. 《JavaScript高级程序设计》——第三章 基本概念

    这章讲了JavaScript的语法.数据类型.流控制语句和函数.理解还是挺好理解的,但有很多和C.C++.Java不同的地方需要记忆.比如, JavaScript标识符可以由Unicode字符字符组成 ...

  4. mysql-connector-java各种版本下载地址

    mysql-connector-java下载地址: http://mvnrepository.com/artifact/mysql/mysql-connector-java 目录 1.进去后选择自己的 ...

  5. 晚间测试13 A. Dove 打扑克 vector +模拟

    题目描述 分析 这道题比较关键的一点就是要看出最终牌数的种类数不会超过 \(\sqrt{n}\) 种 知道了这个性质我们就可以用 \(vector\) 维护一个有序的序列 \(vector\) 中存放 ...

  6. 你不知道的那些js调试命令

    通常情况下,我们在调试js程序的时候一般都使用console.log()来进行程序的调试,打印自己所需要的内容什么的. 那么js的调试命令可不止一个console.log() 分类输出 console ...

  7. 基于flask的python注册到eureka

    Eureka架构中的三个核心角色: 服务注册中心 Eureka的服务端应用,提供服务注册和发现功能,就是刚刚我们建立的eureka-demo 服务提供者 提供服务的应用,可以是SpringBoot应用 ...

  8. 【USACO】New Years Party

    题意描述 New Years Party \(N(3\leq N\leq 200)\) 头奶牛举办新年聚会.每头奶牛会做几种不同的佳肴(以"碟"记数). 一共有 \(D(5\leq ...

  9. Java的类加载器有几种?什么是双亲委派机制?

    一.JAVA类加载器包括几种? 启动类加载器 bootstrap class loader 启动类加载器主要加载的是JVM自身需要的类,这个类加载是用C++语言实现的,是虚拟机自身的一部分,它负责将 ...

  10. windows编译openssl(64位)一游

    编译openssl,一套标准流程: (环境:  win10 64位os, vs2019) 需要的工具:perl     nasm   openssl源码包 1  安装perl 2  下载nasm,将n ...