Orderer 节点启动通过 orderer 包下的 main() 方法实现,会进一步调用到 orderer/common/server 包中的 Main() 方法。

核心代码如下所示。

  1. // Main is the entry point of orderer process
  2. func Main() {
  3. fullCmd := kingpin.MustParse(app.Parse(os.Args[1:]))
  4.  
  5. // "version" command
  6. if fullCmd == version.FullCommand() {
  7. fmt.Println(metadata.GetVersionInfo())
  8. return
  9. }
  10.  
  11. conf := config.Load()
  12. initializeLoggingLevel(conf)
  13. initializeLocalMsp(conf)
  14.  
  15. Start(fullCmd, conf)
  16. }

包括配置初始化过程和核心启动过程两个部分:

  • config.Load():从本地配置文件和环境变量中读取配置信息,构建配置树结构。
  • initializeLoggingLevel(conf):配置日志级别。
  • initializeLocalMsp(conf):配置 MSP 结构。
  • Start():完成启动后的核心工作。

整体过程

核心启动过程都在 orderer/common/server包中的 Start() 方法,如下图所示。

Start() 方法会初始化 gRPC 服务需要的结构,然后启动服务。

核心代码如下所示。

  1. func Start(cmd string, conf *config.TopLevel) {
  2. logger.Debugf("Start()")
  3. signer := localmsp.NewSigner()
  4. manager := initializeMultichannelRegistrar(conf, signer)
  5. server := NewServer(manager, signer, &conf.Debug)
  6.  
  7. switch cmd {
  8. case start.FullCommand(): // "start" command
  9. logger.Infof("Starting %s", metadata.GetVersionInfo())
  10. initializeProfilingService(conf)
  11. grpcServer := initializeGrpcServer(conf)
  12. ab.RegisterAtomicBroadcastServer(grpcServer.Server(), server)
  13. logger.Info("Beginning to serve requests")
  14. grpcServer.Start()
  15. case benchmark.FullCommand(): // "benchmark" command
  16. logger.Info("Starting orderer in benchmark mode")
  17. benchmarkServer := performance.GetBenchmarkServer()
  18. benchmarkServer.RegisterService(server)
  19. benchmarkServer.Start()
  20. }
  21. }

包括两大部分:

  • gRPC 服务结构初始化;
  • gRPC 服务启动。

gRPC 服务结构初始化

包括创建新的 MSP 签名结构,初始化 Registrar 结构来管理各个账本结构,启动共识过程,以及创建 gRPC 服务端结构。

核心步骤包括:

  1. signer := localmsp.NewSigner() // 初始化签名结构
  2. manager := initializeMultichannelRegistrar(conf, signer, tlsCallback) // 初始化账本管理器(Registrar)结构

其中,initializeMultichannelRegistrar(conf, signer) 方法最为关键,核心代码如下:

  1. func initializeMultichannelRegistrar(conf *config.TopLevel, signer crypto.LocalSigner, callbacks ...func(bundle *channelconfig.Bundle)) *multichannel.Registrar {
  2. // 创建操作账本的工厂结构
  3. lf, _ := createLedgerFactory(conf)
  4.  
  5. // 如果是首次启动情况,默认先创建系统通道的本地账本结构
  6. if len(lf.ChainIDs()) == 0 {
  7. logger.Debugf("There is no chain, hence we must be in bootstrapping")
  8. initializeBootstrapChannel(conf, lf)
  9. } else {
  10. logger.Info("Not bootstrapping because of existing chains")
  11. }
  12. //初始化共识插件,共识插件负责跟后台的队列打交道
  13. consenters := make(map[string]consensus.Consenter)
  14. consenters["solo"] = solo.New()
  15. consenters["kafka"] = kafka.New(conf.Kafka.TLS, conf.Kafka.Retry, conf.Kafka.Version, conf.Kafka.Verbose)
  16.  
  17. // 创建各个账本的管理器(Registrar)结构,并启动共识过程
  18. return multichannel.NewRegistrar(lf, consenters, signer, callbacks...)
  19. }

利用传入的配置信息和签名信息完成如下步骤:

  • 创建账本操作的工厂结构;
  • 如果是新启动情况,利用给定的系统初始区块文件初始化系统通道的相关结构;
  • 完成共识插件(包括 solo 和 kafka 两种)的初始化;
  • multichannel.NewRegistrar(lf, consenters, signer) 方法会扫描本地账本数据(此时至少已存在系统通道),创建 Registrar 结构,并为每个账本都启动共识(如 Kafka 排序)过程。

说明:Registrar 结构(位于 orderer.common.multichannel 包)是 Orderer 组件中最核心的结构,管理了 Orderer 中所有的账本、共识插件等数据结构。

创建 Registrar 结构并启动共识过程

NewRegistrar(lf, consenters, signer) 方法位于 orderer.common.multichannel 包,负责初始化链支持、消息处理器等重要数据结构,并为各个账本启动共识过程。

核心代码如下:

  1. existingChains := ledgerFactory.ChainIDs()
  2. for _, chainID := range existingChains { // 启动本地所有的账本结构的共识过程
  3. if _, ok := ledgerResources.ConsortiumsConfig(); ok { // 如果是系统账本(默认在首次启动时会自动创建)
  4. chain := newChainSupport(r, ledgerResources, consenters, signer)
  5. chain.Processor = msgprocessor.NewSystemChannel(chain, r.templator, msgprocessor.CreateSystemChannelFilters(r, chain))
  6. r.chains[chainID] = chain
  7. r.systemChannelID = chainID
  8. r.systemChannel = chain
  9. defer chain.start() // 启动共识过程
  10. else // 如果是应用账本
  11. chain := newChainSupport(r, ledgerResources, consenters, signer)
  12. r.chains[chainID] = chain
  13. chain.start() // 启动共识过程
  14. }

chain.start() 方法负责启动共识过程。以 Kafka 共识插件为例,最终以协程方式调用到 orderer.consensus.kafka 包中的 startThread() 方法,将在后台持续运行。

  1. func (chain *chainImpl) Start() {
  2. go startThread(chain)
  3. }

startThread() 方法将为指定的账本结构配置共识服务,并将其启动,核心代码包括:

  1. // 创建 Producer 结构
  2. chain.producer, err = setupProducerForChannel(chain.consenter.retryOptions(), chain.haltChan, chain.SharedConfig().KafkaBrokers(), chain.consenter.brokerConfig(), chain.channel)
  3. // 发送 CONNECT 消息给 Kafka,如果失败,则退出
  4. sendConnectMessage(chain.consenter.retryOptions(), chain.haltChan, chain.producer, chain.channel)
  5.  
  6. // 创建处理对应 Kafka topic 的 Consumer 结构
  7. chain.parentConsumer, err = setupParentConsumerForChannel(chain.consenter.retryOptions(), chain.haltChan, chain.SharedConfig().KafkaBrokers(), chain.consenter.brokerConfig(), chain.channel)
  8. // 配置从指定 partition 读取消息的 PartitionConsumer 结构
  9. chain.channelConsumer, err = setupChannelConsumerForChannel(chain.consenter.retryOptions(), chain.haltChan, chain.parentConsumer, chain.channel, chain.lastOffsetPersisted+1)
  10.  
  11. // 从该链对应的 Kafka 分区不断读取消息,并进行处理过程
  12. chain.processMessagesToBlocks()

主要包括如下步骤:

  • 创建到 Kafka 集群的 Producer 结构并发送 CONNECT 消息;
  • 为对应的 topic 创建 Consumer 结构,并配置从指定分区读取消息的 PartitionConsumer 结构;
  • 对链对应的 Kafka 分区中消息的进行循环处理。这部分更详细内容可以参考 Orderer 节点对排序后消息的处理过程

gRPC 服务启动

初始化 gRPC 服务结构,完成绑定并启动监听。

  1. // 初始化 gRPC 服务端结构
  2. server := NewServer(manager, signer, &conf.Debug)
  3.  
  4. // 创建 gRPC 服务连接
  5. grpcServer := initializeGrpcServer(conf)
  6.  
  7. // 绑定 gRPC 服务并启动
  8. ab.RegisterAtomicBroadcastServer(grpcServer.Server(), server)
  9. grpcServer.Start()

其中,NewServer(manager, signer, &conf.Debug) 方法(位于 orderer.common.server 包)最为核心,将 gRPC 相关的服务结构进行初始化,并绑定到 gRPC 请求上。分别响应 Deliver() 和 Broadcast() 两个 gRPC 调用。

  1. // NewServer creates an ab.AtomicBroadcastServer based on the broadcast target and ledger Reader
  2. func NewServer(r *multichannel.Registrar, _ crypto.LocalSigner, debug *localconfig.Debug) ab.AtomicBroadcastServer {
  3. s := &server{
  4. dh: deliver.NewHandlerImpl(deliverSupport{Registrar: r}),
  5. bh: broadcast.NewHandlerImpl(broadcastSupport{Registrar: r}),
  6. debug: debug,
  7. }
  8. return s
  9. }
  10.  
  11. 来源:https://github.com/yeasy/hyperledger_code_fabric/blob/master/process/orderer_start.md

Hyperledger Fabric Orderer节点启动的更多相关文章

  1. hyperledger fabric各类节点及其故障分析 摘自https://www.cnblogs.com/preminem/p/8729781.html

    hyperledger fabric各类节点及其故障分析   1.Client节点 client代表由最终用户操作的实体,它必须连接到某一个peer节点或者orderer节点上与区块链网络通信.客户端 ...

  2. hyperledger fabric各类节点及其故障分析

    1.Client节点 client代表由最终用户操作的实体,它必须连接到某一个peer节点或者orderer节点上与区块链网络通信.客户端向endorser提交交易提案,当收集到足够背书后,向排序服务 ...

  3. 7.搭建hyperledger fabric环境及启动——2019年12月12日

    2019年12月12日13:05:16 声明:从网络中学习整理实践而来. 1.介绍fabric Fabric 是一个面向企业应用的区块链框架,基于 Fabric 的开发可以粗略分为几个层面: 1. 参 ...

  4. Hyperledger Fabric的test-network启动过程Bash源码详解

    前言 在基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例中,我们已经完成了Fabric 2.4的环境搭建及fabric-samples/test-network官 ...

  5. Hyperledger Fabric网络节点架构

    Fabric区块链网络的组成  区块链网络结构图 区块链网络组成 组成区块链网络相关的节点 节点是区块链的通信主体,和区块链网络相关的节点有多种类型:客户端(应用).Peer节点.排序服务(Orde ...

  6. 死磕hyperledger fabric源码|Order节点概述

    死磕hyperledger fabric源码|Order节点概述 文章及代码:https://github.com/blockchainGuide/ 分支:v1.1.0 前言及源码目录 Orderer ...

  7. 基于docker的 Hyperledger Fabric 多机环境搭建(上)

    环境:ubuntu 16.04 Docker  17.04.0-ce go 1.7.4 consoul v0.8.0.4 ======================================= ...

  8. Centos7 HyperLedger Fabric 1.4 生产环境部署

    Kafka生产环境部署案例采用三个排序(orderer)服务.四个kafka.三个zookeeper和四个节点(peer)组成,共准备八台服务器,每台服务器对应的服务如下所示: kafka案例网络拓扑 ...

  9. Hyperledger Fabric 入门 first-network 搭建

    1.准备环境: 安装git.docker.curl.go [root@test_vonedao_83 fabric]# git --version git version 1.8.3.1 [root@ ...

随机推荐

  1. python库之threading

    This module constructs higher-level threading interfaces on top of the lower level python库之_threadmo ...

  2. bzoj 2282 消防

    Written with StackEdit. Description 某个国家有\(n\)个城市,这\(n\)个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为\(z_i(z_i ...

  3. net core集成CAP

    net core集成CAP https://www.cnblogs.com/guolianyu/p/9756941.html 一.前言 感谢杨晓东大佬为社区贡献的CAP开源项目,传送门在此:.NET ...

  4. JVM年轻代(young generation)老年代(old generation tenured)持久代(permanent generation)GC

    关于jvm内存代,看到这篇文章,转发下 链接地址 ---多谢 虚拟机中的共划分为三个代:年轻代(Young Generation).老年代(Old Generation)和持久代(Permanent ...

  5. 【HDU】4632 Palindrome subsequence(回文子串的个数)

    思路:设dp[i][j] 为i到j内回文子串的个数.先枚举所有字符串区间.再依据容斥原理. 那么状态转移方程为   dp[i][j] = dp[i][j-1] + dp[i+1][j] - dp[i+ ...

  6. homebrew的安装与使用

    homebrew的安装:http://jingyan.baidu.com/article/fec7a1e5ec30341190b4e7e5.html 引用segfaultment上面的回答 没这个说法 ...

  7. linux 使用asciinema 进行命令行屏幕录制共享

    1. 安装 yum install asciinema 2. 使用 录制 asciinema rec filename(可选,方便进行后期的回放play) 同时生成一个url 地址方便传递 https ...

  8. 7 函数——《Swift3.0从入门到出家

    6 函数 函数就是对某个功能的封装,一个swift程序可能由多个函数组成 swift中定义函数的格式: func 函数名称(参数列表) —>函数返回值类型{ 函数体 return } 函数定义要 ...

  9. Linux环境安装nginx

    安装需要以下工具: yum -y install gcc gcc-c++ autoconf automake 模块依赖: yum -y install zlib zlib-devel openssl ...

  10. ODBC、OLEDB、ADO、SQL的关系

    对于一个刚接触数据库的菜鸟来说(比如我),总是搞不清SQL.ADO.OLE DB.ODBC,大脑中一片混乱,好像懂了,又好像没懂,非常的苦恼,今天下了点功夫研究了一下,贴出来,其中肯定有好多错误,希望 ...