区块链技术和Apache Kafka具有共同的特征,这暗示了自然的亲和力。 例如,两者共享“不可变的仅追加日志”的概念。 如果是Kafka分区:
每个分区都是有序的,不可变的记录序列,这些记录连续地附加到结构化的提交日志中。 分区中的每个记录均分配有一个顺序ID号,称为偏移量,该ID唯一地标识分区中的每个记录[ Apache Kafka ]
而区块链可以描述为:
不断增长的记录列表(称为块),这些记录使用密码进行链接和保护。 每个块通常包含一个哈希指针(作为指向前一个块的链接),时间戳和交易数据[ Wikipedia ]
显然,这些技术共享不可变顺序结构的并行概念,其中Kafka特别针对高吞吐量和水平可伸缩性进行了优化,而区块链在保证序列的顺序和结构方面表现出色。
通过集成这些技术,我们可以创建一个用于试验区块链概念的平台。
Kafka为分布式对等通信提供了方便的框架,具有一些特别适合于区块链应用程序的特征。 尽管此方法在不信任的公共环境中可能不可行,但在私有或联盟网络中可能会有实际用途。 有关如何实现此功能的更多想法,请参见使用Apache Kafka扩展区块链 。
此外,通过一些试验,我们也许能够利用已经在Kafka中实现的概念(例如,按分区分片)来探索解决公共网络中的区块链挑战(例如,可伸缩性问题)的解决方案。
因此,本实验的目的是采用简单的区块链实现并将其移植到Kafka平台。 我们将采用Kafka的顺序日志的概念,并通过将条目与哈希值链接在一起来确保不变性。 卡夫卡上的blockchain
主题将成为我们的分布式账本。 在图形上,它将如下所示:
卡夫卡简介
Kafka是用于高吞吐量,实时消息传递的流媒体平台,即,它可以发布和订阅记录流。 在这方面,它类似于消息队列或传统的企业消息传递系统。 一些特征是:
- 高吞吐量:Kafka代理可以每秒吸收千兆字节的数据,每秒可以转换成数百万条消息。 您可以在基准化Apache Kafka:每秒200万次写入中了解有关可伸缩性特征的更多信息。
- 竞争的消费者:向多个消费者同时传递消息(通常在传统消息传递系统中价格昂贵)并不比单个消费者复杂。 这意味着我们可以为竞争的消费者设计产品,确保每个消费者仅接收一条消息,并实现高度的水平可扩展性。
- 容错能力:通过在群集中的多个节点之间复制数据,可以将单个节点故障的影响降至最低。
- 消息保留和重播:Kafka经纪人保留消费者抵销记录-消费者在消息流中的位置。 使用此功能,即使消息已经传递,消费者也可以倒退到流中的先前位置,从而允许他们在某个时间点重新创建系统的状态。 可以将代理配置为无限期保留消息,这对于区块链应用程序是必需的。
在Kafka中,每个主题都分为多个分区,每个分区都是一系列记录,这些记录不断地附加到该记录中。 这类似于文本日志文件,其中在末尾添加了新行。 分区中的每个条目均分配有一个顺序ID,称为偏移量,用于唯一标识记录。
可以通过偏移量查询Kafka代理,即,使用者可以将其偏移量重置为日志中的任意点,以从该点开始检索记录。
讲解
完整的源代码在这里 。
先决条件
- 对区块链概念有一些了解:以下教程基于Daniel van Flymen和Gerald Nash的实现 ,它们都是出色的实用介绍。 下面的教程在将Kafka用作消息传输的同时,也以这些概念为基础。 实际上,我们将在保持大多数当前实现的同时将Python区块链移植到Kafka。
- Python的基本知识:该代码是为Python 3.6编写的。
- Docker :docker-compose用于运行Kafka代理。
- kafkacat :这是与Kafka进行交互的有用工具(例如,将消息发布到主题)
在启动时,我们的Kafka消费者将尝试做三件事:如果尚未创建一个新的区块链,则对其进行初始化; 建立区块链主题当前状态的内部表示; 然后开始循环读取事务:
初始化步骤如下所示:
首先,我们在区块链主题上找到最高的可用偏移量。 如果尚未对该主题发布任何东西,则区块链是新的,因此我们首先创建并发布创世块:
在read_and_validate_chain()
,我们首先创建一个消费者以读取read_and_validate_chain()
blockchain
主题:
关于我们使用以下方法创建此使用者的参数的一些说明:
- 将消费者组设置为
blockchain
组可允许经纪人针对给定的分区和主题保留消费者已达到的偏移量的参考 -
auto_offset_reset=OffsetType.EARLIEST
表示我们将从主题的开头开始下载消息。 -
auto_commit_enable=True
定期通知经纪人我们刚刚消耗的偏移量(与手动提交相对) -
reset_offset_on_start=True
是一个为使用者激活auto_offset_reset
的开关 -
consumer_timeout_ms=5000
如果没有新消息被阅读(我们已经到达链的末尾),则五秒钟后将触发使用者返回方法。
然后,我们开始从区块blockchain
主题中读取阻止消息:
对于每条消息,我们收到:
- 如果它是链中的第一个块,请跳过验证并添加到我们的内部副本中(这是创世块)
- 否则,检查该块相对于前一个块是否有效,并将其附加到我们的副本中
- 记下我们刚刚消耗的块的偏移量
在此过程结束时,我们将下载整个链,丢弃所有无效的块,并且将引用最新块的偏移量。
至此,我们准备在transactions
主题上创建使用者:
我们的示例主题创建了两个分区,以演示分区在Kafka中的工作方式。 分区在docker-compose.yml
文件中设置,行如下:
KAFKA_CREATE_TOPICS=transactions:2:1,blockchain:1:1
transactions:2:1
指定分区数和复制因子(即,有多少代理将在此分区上维护数据副本)。
这次,我们的使用者将从OffsetType.LATEST
开始,因此我们只从当前时间开始发布交易。
通过将消费者固定在transactions
主题的特定分区上,我们可以增加该主题上所有消费者的总吞吐量。 Kafka代理将在事务主题的两个分区之间平均分配传入消息,除非在发布到该主题时指定一个分区。 这意味着每个使用者将负责处理50%的消息,使单个使用者的潜在吞吐量增加一倍。
现在我们可以开始使用交易了:
收到交易后,我们会将其添加到内部列表中。 每三笔交易,我们将创建一个新块并调用mine()
:
- 首先,我们将检查我们的区块链是否是网络中最长的区块链; 我们保存的偏移量是最新的,还是其他节点已经发布了更高版本的区块链? 这是我们的共识步骤。
- 如果已经添加了新的块,那么我们将使用以前的
read_and_validate_chain
,这次提供我们最新的已知偏移量以仅检索较新的块。 - 在这一点上,我们可以尝试根据最新区块的证明来计算工作证明。
- 为了奖励自己解决工作量证明的方法,我们可以在交易中插入一笔交易,并向自己支付一小笔奖励。
- 最后,我们将区块发布到区块链主题上。 publish方法看起来像这样:
行动中
- 首先启动代理:
docker-compose up -d
2.在分区0上运行使用者:
python kafka_blockchain.py 0
3.直接将3个事务发布到分区0:
4.检查将交易添加到关于区块blockchain
的区块:
kafkacat -C -b kafka:9092 -t blockchain
您应该看到如下输出:
要在两个使用者之间平衡事务,请在分区1上启动另一个使用者,然后从上面的发布脚本中删除-p 0
。
结论
Kafka可以为区块链实验的简单框架提供基础。 我们可以利用平台内置的功能以及诸如kafkacat之类的相关工具来试验分布式对等事务。
虽然在公共场所扩展事务会带来一系列问题,但在已经建立了真实世界信任的专用网络或财团内部,可以通过利用Kafka概念的实现来实现事务扩展。
From: https://hackernoon.com/a-blockchain-experiment-with-apache-kafka-97ee0ab6aefc