Fabric 1.4源码分析 kafka共识机制

本文档主要介绍kafka共识机制流程。在查看文档之前可以先阅览raft共识流程以及orderer服务启动流程。

1. kafka 简介

Kafka是最初由Linkedin公司开发,是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式日志系统,一种高吞吐量的分布式发布订阅消息系统。kafka详细介绍可以参考这一篇博客。kafka介绍

2. kafka共识

kafka共识当中,每个orderer节点即是生产者Producer也是消费者Consumer,在具体设计当中,每个channel对应一个topic,并且为了保证顺序性,只设置了一个patition。(参见orderer启动初始化kafka共识代码afka.New(conf, metricsProvider, healthChecker, registrar)),关于kafka共识,这里推荐一篇博客,可以看看设计思路以及实现流程。The ABCs of Kafka in Hyperledger Fabric

实现共识算法需要实现的接口。

type Consenter interface {
    // 处理普通交易
    Order(env *cb.Envelope, configSeq uint64) error
    // 处理配置交易
    Configure(config *cb.Envelope, configSeq uint64) error
    WaitReady() error
}

而接口chain在Consenter接口基础上增加来部分接口

type Chain interface {
    Order(env *cb.Envelope, configSeq uint64) error
    Configure(config *cb.Envelope, configSeq uint64) error
    WaitReady() error
    Errored() <-chan struct{}
    // 分配资源
    Start()
    // 释放资源
    Halt()
    MigrationStatus() migration.Status
}

kafka共识实现代码路径为:orderer/consensus/kafka/chain.go;首先,在创建chain时会调用start()方法分配资源,在kafka共识中,会初始化生产者producer、消费者Consumer以及一些配置。后续重点通过源码来介绍producer和consumer模块实现以及kafka共识整个交易的流程,即主要介绍交易排序整个流程。在此基础上,解决个人的一些疑问。

3. 交易排序处理

3.1 orderer作为生产者

首先,当发送一个交易给orderer时,会调用orderer模块的broadcast()服务,其中会调用bh.ProcessMessage(msg, addr)方法根据交易类型调用不同的方法处理。

其中无论是配置交易还是普通交易都会调用chain.enqueue()方法,通过chain.producer.SendMessage(message)方法将交易写入kafka。从而orderer作为生产者角色功能就是将客户端发过来的交易写入kafka。再次强调一下,每个通道对应一个topic,每个topic只有一个patition。

func (chain *chainImpl) enqueue(kafkaMsg *ab.KafkaMessage) bool {
    logger.Debugf("[channel: %s] Enqueueing envelope...", chain.ChainID())
    select {
    case <-chain.startChan: // The Start phase has completed
        select {
        case <-chain.haltChan: // The chain has been halted, stop here
            logger.Warningf("[channel: %s] consenter for this channel has been halted", chain.ChainID())
            return false
        default: // The post path
            payload, err := utils.Marshal(kafkaMsg)
            if err != nil {
                logger.Errorf("[channel: %s] unable to marshal Kafka message because = %s", chain.ChainID(), err)
                return false
            }
            message := newProducerMessage(chain.channel, payload)
            if _, _, err = chain.producer.SendMessage(message); err != nil {
                logger.Errorf("[channel: %s] cannot enqueue envelope because = %s", chain.ChainID(), err)
                return false
            }
            logger.Debugf("[channel: %s] Envelope enqueued successfully", chain.ChainID())
            return true
        }
    default: // Not ready yet
        logger.Warningf("[channel: %s] Will not enqueue, consenter for this channel hasn't started yet", chain.ChainID())
        return false
    }
}

3.2 orderer作为消费者

orderer作为消费者的功能为:将kafka对应topic里面的交易打包成区块,并写入账本。

其中,在orderer创建对应chain的时候调用chain.start()。

func (chain *chainImpl) Start() {
    go startThread(chain)
}

kafka会开启协程go startThread(chain),其中会对kafka进行一系列初始化工作。最后会调用chain.processMessagesToBlocks()方法,生成对应区块。

func (chain *chainImpl) processMessagesToBlocks() ([]uint64, error) {
    ...
    for {
        select {
        ...
        case in, ok := <-chain.channelConsumer.Messages():
            ...
            switch msg.Type.(type) {
            ...
            case *ab.KafkaMessage_Regular:
                if err := chain.processRegular(msg.GetRegular(), in.Offset); err != nil {
                    logger.Warningf("[channel: %s] Error when processing incoming message of type REGULAR = %s", chain.ChainID(), err)
                    counts[indexProcessRegularError]++
                } else {
                    counts[indexProcessRegularPass]++
                }
            }
            ...
    }
}

其中,会对chain.processRegular(msg.GetRegular(), in.Offset)消息进行处理。

其中,会针对配置交易和普通交易进行分别处理。普通交易会调用chain.BlockCutter().Ordered(message)生成对应的batchs,配置交易会一个交易一个区块,直接调用chain.BlockCutter().Cut()生成batch。然后再生成区块、写入账本。

4. 问题思考

  1. kafka共识模式下动态更新系统通道配置添加orderer,是否就可提供排序服务。
    经查看代码,在orderer启动过程中,只有raft共识会判断该orderer(raft节点)是否在对应对consenter集群中。如果不在则会创建inactivechain,无法提供排序服务(必须更新consenter才行)。但是kafka不存在上述过程,在orderer启动后,会从kafka同步系统通道区块,当区块包括创建通道交易时,会创建应用通道,同步应用通道区块(该流程类似raft共识写账本流程)。因此,该orderer可以提供服务,但是如果是每个组织提供orderer的场景、由于没有更新应用通道排序组织,从而导致无法通过服务发现获取该orderer信息。

菜鸟学习Fabric源码学习 — kafka共识机制的更多相关文章

  1. 菜鸟系列Fabric源码学习—orderer服务启动

    Fabric 1.4 orderer 服务启动流程 1.提要 orderer提供broadcast和deliver两个服务接口.orderer节点与各个peer节点通过grpc连接,orderer将所 ...

  2. 菜鸟系列Fabric源码学习 — 区块同步

    Fabric 1.4 源码分析 区块同步 本文主要从源码层面介绍fabric peer同步区块过程,peer同步区块主要有2个过程: 1)peer组织的leader与orderer同步区块 2)pee ...

  3. 菜鸟系列Fabric源码学习 — peer节点启动

    Fabric 1.4 源码分析peer节点启动 peer模块采用cobra库来实现cli命令. Cobra提供简单的接口来创建强大的现代化CLI接口,比如git与go工具.Cobra同时也是一个程序, ...

  4. 菜鸟系列Fabric源码学习—创建通道

    通道创建源码解析 1. 与通道创建相关配置及操作命令 主要是configtx.yaml.通过应用通道的profile生成创建通道的配置文件. TwoOrgsChannel: Consortium: S ...

  5. 菜鸟系列Fabric源码学习 — committer记账节点

    Fabric 1.4 源码分析 committer记账节点 本文档主要介绍committer记账节点如何初始化的以及committer记账节点的功能及其实现. 1. 简介 记账节点负责验证交易和提交账 ...

  6. 菜鸟系列Fabric源码学习 — MVCC验证

    Fabric 1.4 源码分析 MVCC验证 读本节文档之前建议先查看[Fabric 1.4 源码分析 committer记账节点]章节. 1. MVCC简介 Multi-Version Concur ...

  7. 菜鸟学习Fabric源码学习 — Endorser背书节点

    Fabric 1.4 源码分析 Endorser背书节点 本文档主要介绍fabric背书节点的主要功能及其实现. 1. 简介 Endorser节点是peer节点所扮演的一种角色,在peer启动时会创建 ...

  8. 菜鸟学习Fabric源码学习 — 背书节点和链码容器交互

    Fabric 1.4 源码分析 背书节点和链码容器交互 本文档主要介绍背书节点和链码容器交互流程,在Endorser背书节点章节中,无论是deploy.upgrade或者调用链码,最后都会调用Chai ...

  9. 菜鸟的jQuery源码学习笔记(前言)

    前言 相信任何一名前端开发人员或者是前端爱好者都对jQuery不陌生.jQuery简单易用,功能强大,特别是拥有良好的浏览器兼容性,大大降低了前端开发的难度,使得前端开发变得“平易近人起来”.自从本人 ...

随机推荐

  1. win10 uwp 使用 Azure DevOps 自动构建

    通过 Azure DevOps 可以做到自动构建程序,覆盖计划.创建.编程.测试.部署.发布.托管.共享等各个环节,适用于大多数的语言.平台. 本文继续使用图床为例告诉大家如何使用 Azure Dev ...

  2. UPC 2019年第二阶段我要变强个人训练赛第六场

    传送门 A.上学路线 题目描述 小D从家到学校的道路结构是这样的:由n条东西走向和m条南北走向的道路构成了一个n*m的网格,每条道路都是单向通行的(只能从北向南,从西向东走). 已知小D的家在网格的左 ...

  3. linux 安装一个共享的处理者

    共享中断通过 request_irq 来安装就像不共享的一样, 但是有 2 个不同: SA_SHIRQ 位必须在 flags 参数中指定, 当请求中断时. dev_id 参数必须是独特的. 任何模块地 ...

  4. PHP判断类型

    is_bool();//判断是否为布尔型   is_float(); //判断是否为浮点型   is_int(); //判断是否为整型   is_numeric(); //判断是否为数值型   is_ ...

  5. vue中 js获取图片尺寸 设置不同样式

    1.JS: 请求到后端数据后 判断图片尺寸 2.HTML代码 根据设置的类型,给图片添加不同的样式 3.CSS代码 添加不同尺寸的样式

  6. Linux USB 的 Urbs

    linux 内核中的 USB 代码和所有的 USB 设备通讯使用称为 urb 的东西( USB request block). 这个请求块用 struct urb 结构描述并且可在 include/l ...

  7. How to parse version range

    Now we are making a solution that has to get the package reference. But the version of package refer ...

  8. Visual Studio Team Services and Team Foundation Server官方资料入口

    Team Foundation Server msdn 中文文档入口 Visual Studio Team Services or Team Foundation Server www.visuals ...

  9. HDU1166 敌兵布阵 BZOJ1012 最大数[树状数组]

    一.前置知识-树状数组 树状数组(binary indexed tree)是一种简洁的代码量很小的数据结构,能够高效的处理前缀区间上的问题.在很多情况下能写树状数组解决的就不用码半天线段树了. 树状数 ...

  10. 9. SOFAJRaft源码分析— Follower如何通过Snapshot快速追上Leader日志?

    前言 引入快照机制主要是为了解决两个问题: JRaft新节点加入后,如何快速追上最新的数据 Raft 节点出现故障重新启动后如何高效恢复到最新的数据 Snapshot 源码分析 生成 Raft 节点的 ...