Hyperledger Fabric定制联盟链网络工程实践
前言
总体来看,网络上成体系的可用的 Fabric 教程极少——不是直接在 Fabric 官网复制内容大谈基础理论就是在描述一个几乎无法复现的项目实践,以至于学习 Fabric 的效率极低,印象最深刻的就是我曾经花费几天时间尝试按照官方教程 CA Deployment steps 搭建自己的 CA 服务,却始终无法成功也找不到原因。因此,为了提高生产效率,本项目虚拟了一个工作室联盟链需求并将逐步实现,致力于提供一个易理解、可复现的Fabric学习项目(尽管它比较简单),其中项目部署步骤的各个环节都清晰可见,并且将所有过程打包为脚本使之能够被快速复现在任何一台主机上。
工程介绍
组织架构
有一启明星工作室,其中包含三大组织:软件组、WEB组、硬件组、理事会,不同组织间相互独立,偶尔有业务往来。现理事会决定搭建一个启明星工作室的联盟链网络,使不同组织间加强合作,期望最终实现以下工程架构:
- 组织说明
- council:理事会,负责工作室各组间协调管理,由三组抽调人员共同组成
- soft:软件组,专注软件开发
- hard:硬件组,专注硬件开发
- web:WEB组,专注网站开发
- orderer:过渡排序组织,为联盟链网络提供排序服务,后期会舍弃
 
- 成员说明
- council:一个Orderer节点、三个Admin账号,每组拥有一个Admin账号权限
- soft:一个Orderer节点、一个Peer节点、一个Admin账号、一个User账号
- hard:一个Orderer节点、一个Peer节点、一个Admin账号、一个User账号
- web:一个Orderer节点、一个Peer节点、一个Admin账号、一个User账号
- orderer:一个Orderer节点、一个Admin账号
 
- 根CA服务器(域名)
- council.fantasy.com:提供/管理组织间的- TLS证书,又叫TLS CA服务器
- soft.fantasy.com:提供/管理组织内- TLS证书
- hard.fantasy.com:提供/管理组织内- TLS证书
- web.fantasy.com:提供/管理组织内- TLS证书
- orderer.fantasy.com:提供/管理组织内- TLS证书
 
实验准备
在开始前,如果你对 Fabric 命令知之甚少,可以先学习fabric的test-network启动过程Bash源码详解;此外应准备好 Fabric 的开发环境,具体环境搭建和软件版本可参考基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例。为了方便区分各组织和节点,本工程使用域名的方式进行各节点间的通信,以 web 组织为例,域名分配规范如下:
| 域名 | 说明 | 
|---|---|
| peer1.web.ifantasy.net | web组第一个 peer 节点地址 | 
| peer2.web.ifantasy.net | web组第二个 peer 节点地址 | 
| orderer1.web.ifantasy.net | web组第一个 orderer 节点地址 | 
此外,还需要在 \etc\hosts 文件添加 DNS 地址:
echo "127.0.0.1       council.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       orderer.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       soft.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       web.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       hard.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       orderer1.soft.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       orderer1.web.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       orderer1.hard.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       orderer1.orderer.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       orderer2.orderer.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       orderer3.orderer.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       peer1.soft.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       peer1.web.ifantasy.net" >> /etc/hosts
echo "127.0.0.1       peer1.hard.ifantasy.net" >> /etc/hosts
本文工作
本项目主要以学习为主,所以并未期望一次实现所有架构和功能。本文所实现的具体内容为,搭建一个简单的工作室联盟链网络,包含 council 、 orderer 、 soft 、 web 四个组织,并将测试链码部署在通道 mychannel ,网络结构为(实验代码已上传至:https://github.com/wefantasy/FabricLearn 的 1_3Org2Peer1Orderer1TLS 目录下):
| 项 | 运行端口 | 说明 | 
|---|---|---|
| council.ifantasy.net | 7050 | council 组织的 CA 服务, 为联盟链网络提供 TLS-CA 服务 | 
| orderer.ifantasy.net | 7150 | orderer 组织的 CA 服务, 为联盟链网络提供排序服务 | 
| orderer1.orderer.ifantasy.net | 7151 | orderer 组织的 orderer1 成员节点 | 
| soft.ifantasy.net | 7250 | soft 组织的 CA 服务, 包含成员: peer1 、 admin1 | 
| peer1.soft.ifantasy.net | 7251 | soft 组织的 peer1 成员节点 | 
| web.ifantasy.net | 7350 | web 组织的 CA 服务, 包含成员: peer1 、 admin1 | 
| peer1.web.ifantasy.net | 7351 | web 组织的 peer1 成员节点 | 
其它说明
个人觉得 Fabric 官方示例的证书结构过于冗余,为了便于自己理解,本工程证书结构跟一般 Fabric 有所出入,先将本工程各文件目录说明如下:
1_3Org2Peer1Orderer1TLS
├── 0_Restart.sh           # 启动基本 CA 网络脚本
├── 1_RegisterUser.sh      # 注册账户脚本
├── 2_EnrollUser.sh        # 登录账户脚本
├── 3_Configtxgen.sh       # 生成创世区块脚本
├── 4_TestChaincode.sh     # 链码测试脚本
├── asset-transfer-basic   # 测试链码目录
├── basic.tar.gz           # 打包后的链码包
├── compose                # Docker配置目录
│   ├── docker-base.yaml      # 基础通用配置
│   └── docker-compose.yaml   # 具体 Docker 配置
├── config                 # Fabric 公共配置目录
│   ├── config-msp.yaml    # 节点组织单元配置文件
│   ├── configtx.yaml      # 初始通道配置
│   ├── orderer.yaml      # orderer 节点配置,osnadmin 的配置文件
│   └── core.yaml          # peer 配置
├── data                   # 临时数据目录
├── envpeer1soft           # soft 组织的 peer1 cli环境变量
├── envpeer1web            # web 组织的peer1 cli环境变量
├── orgs                   # 组织成员证书目录
│   ├── council.ifantasy.net  # council 组织目录
│   ├── orderer.ifantasy.net  # orderer 组织目录
│   ├── web.ifantasy.net      # web组织目录
│   └── soft.ifantasy.net     # soft 组织目录
│       ├── assets            # 组织公共材料目录
│       │   ├── ca-cert.pem      # 本组织根证书
│       │   ├── mychannel.block  # mychannel 通道创世区块
│       │   └── tls-ca-cert.pem  # TLS-CA 服务根证书
│       ├── ca             # 本组织 CA 服务目录
│       │   ├── admin      # 本组织 CA 服务引导管理员 msp 目录
│       │   └── crypto     # 本组织 CA 服务默认证书目录
│       ├── msp               # 组织 MSP 目录
│       │   ├── admincerts    # 组织管理员签名证书目录
│       │   ├── cacerts       # 组织 CA 服务根证书目录
│       │   ├── config.yaml   # 组织节点单元配置文件
│       │   ├── tlscacerts    # TLS-CA 服务根证书目录
│       │   └── users         # 空目录,msp 规范所需
│       └── registers         # 本组织注册的账户目录
│           ├── admin1        # 管理员账户
│           └── peer1         # 节点账户
└── README.md
实验步骤
实验准备
首先将基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例中的/usr/local/fabric/config目录复制到根目录下。如无特殊说明,环境变量FABRIC_CFG_PATH总是默认指向根目录的config目录(建议直接将本案例仓库 FabricLearn 下的 1_3Org2Peer1Orderer1TLS 目录拷贝到本地运行)。
fabric 提供一个 fabric-tools 镜像用于提供操作 peer 节点的命令行,其实现方式是在启动 fabric-tools 时指定 peer 节点的身份证书等环境变量,此外我们也可以直接将这些环境变量写入一个文件中然后通过 source 命令激活。在根目录下创建 envpeer1soft 文件,用于保存 soft 组织的环境变量,写入以下内容:
export LOCAL_ROOT_PATH=$PWD
export LOCAL_CA_PATH=$LOCAL_ROOT_PATH/orgs
export DOCKER_CA_PATH=/tmp
export COMPOSE_PROJECT_NAME=fabriclearn
export DOCKER_NETWORKS=network
export FABRIC_BASE_VERSION=2.4
export FABRIC_CA_VERSION=1.5
配置TLS服务
- 在根目录下创建 compose文件夹,用于储存docker-compose配置文件。
- 在 compose下创建docker-base.yaml文件,用于写入公共服务配置,先写入以下内容:
version: "2"
services:
  ca-base:
    image: hyperledger/fabric-ca:${FABRIC_CA_VERSION}
    environment:
      - FABRIC_CA_SERVER_HOME=${DOCKER_CA_PATH}/ca/crypto
      - FABRIC_CA_SERVER_TLS_ENABLED=true
      - FABRIC_CA_SERVER_DEBUG=true
    networks:
      - ${DOCKER_NETWORKS}
- 在 compose下创建docker-compose.yaml文件,用于配置工程 docker 容器,写入council、orderer、soft、web的 TLS 服务配置:
version: '2'
networks:
  network:
services:
  council.ifantasy.net:
    container_name: council.ifantasy.net
    extends:
      file: docker-base.yaml
      service: ca-base
    command: sh -c 'fabric-ca-server start -d -b ca-admin:ca-adminpw --port 7050'
    environment:
      - FABRIC_CA_SERVER_CSR_CN=council.ifantasy.net
      - FABRIC_CA_SERVER_CSR_HOSTS=council.ifantasy.net
    volumes:
      - ${LOCAL_CA_PATH}/council.ifantasy.net/ca:${DOCKER_CA_PATH}/ca
    ports:
      - 7050:7050
  orderer.ifantasy.net:
    container_name: orderer.ifantasy.net
    extends:
      file: docker-base.yaml
      service: ca-base
    command: sh -c 'fabric-ca-server start -d -b ca-admin:ca-adminpw --port 7050'
    environment:
      - FABRIC_CA_SERVER_CSR_CN=orderer.ifantasy.net
      - FABRIC_CA_SERVER_CSR_HOSTS=orderer.ifantasy.net
    volumes:
      - ${LOCAL_CA_PATH}/orderer.ifantasy.net/ca:${DOCKER_CA_PATH}/ca
    ports:
      - 7150:7050
  soft.ifantasy.net:
    container_name: soft.ifantasy.net
    extends:
      file: docker-base.yaml
      service: ca-base
    command: sh -c 'fabric-ca-server start -d -b ca-admin:ca-adminpw --port 7050'
    environment:
      - FABRIC_CA_SERVER_CSR_CN=soft.ifantasy.net
      - FABRIC_CA_SERVER_CSR_HOSTS=soft.ifantasy.net
    volumes:
      - ${LOCAL_CA_PATH}/soft.ifantasy.net/ca:${DOCKER_CA_PATH}/ca
    ports:
      - 7250:7050
  web.ifantasy.net:
    container_name: web.ifantasy.net
    extends:
      file: docker-base.yaml
      service: ca-base
    command: sh -c 'fabric-ca-server start -d -b ca-admin:ca-adminpw --port 7050'
    environment:
      - FABRIC_CA_SERVER_CSR_CN=web.ifantasy.net
      - FABRIC_CA_SERVER_CSR_HOSTS=web.ifantasy.net
    volumes:
      - ${LOCAL_CA_PATH}/web.ifantasy.net/ca:${DOCKER_CA_PATH}/ca
    ports:
      - 7350:7050
- 启动各组织的 TLS 服务:
source envpeer1soft
docker-compose -f $LOCAL_ROOT_PATH/compose/docker-compose.yaml up -d council.ifantasy.net orderer.ifantasy.net soft.ifantasy.net web.ifantasy.net
注册账户
- 注册 - council组织账户。
 首先设置- council的环境变量:- export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem
 export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/council.ifantasy.net/ca/admin
 - 然后使用 - enroll登录引导账户, 它会以- FABRIC_CA_CLIENT_TLS_CERTFILES指向的 CA 服务器根证书加密通信,并将生成的身份证书保存在- FABRIC_CA_CLIENT_HOME指向的工作目录下[1]:- fabric-ca-client enroll -d -u https://ca-admin:ca-adminpw@council.ifantasy.net:7050
 - 注意: - enroll操作结果是保存账号的身份证书至指定目录下,以后就可以直接根据该目录下的证书来使用对应身份,跟传统 web 系统的登录操作类似所以被我称为登录,但实际上有所区别。- 然后便可以 - ca-admin身份进行注册其它用户的操作:- fabric-ca-client register -d --id.name orderer1 --id.secret orderer1 --id.type orderer -u https://council.ifantasy.net:7050
 fabric-ca-client register -d --id.name peer1soft --id.secret peer1soft --id.type peer -u https://council.ifantasy.net:7050
 fabric-ca-client register -d --id.name peer1web --id.secret peer1web --id.type peer -u https://council.ifantasy.net:7050
 - council为其它组织提供 TLS-CA 服务的具体实现就是为其它组织提供- council可验证的合法账户,其他组织使用这些账户进行通信就是可信的。后面注册步骤与上面类似,故不再赘述。
- 注册 - orderer组织账户:- export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/orderer.ifantasy.net/ca/crypto/ca-cert.pem
 export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/orderer.ifantasy.net/ca/admin
 fabric-ca-client enroll -d -u https://ca-admin:ca-adminpw@orderer.ifantasy.net:7150
 fabric-ca-client register -d --id.name orderer1 --id.secret orderer1 --id.type orderer -u https://orderer.ifantasy.net:7150
 fabric-ca-client register -d --id.name admin1 --id.secret admin1 --id.type admin -u https://orderer.ifantasy.net:7150
 
- 注册 - soft组织账户:- export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/soft.ifantasy.net/ca/crypto/ca-cert.pem
 export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/soft.ifantasy.net/ca/admin
 fabric-ca-client enroll -d -u https://ca-admin:ca-adminpw@soft.ifantasy.net:7250
 fabric-ca-client register -d --id.name peer1 --id.secret peer1 --id.type peer -u https://soft.ifantasy.net:7250
 fabric-ca-client register -d --id.name admin1 --id.secret admin1 --id.type admin -u https://soft.ifantasy.net:7250
 
- 注册 - web组织账户:- export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/web.ifantasy.net/ca/crypto/ca-cert.pem
 export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/web.ifantasy.net/ca/admin
 fabric-ca-client enroll -d -u https://ca-admin:ca-adminpw@web.ifantasy.net:7350
 fabric-ca-client register -d --id.name peer1 --id.secret peer1 --id.type peer -u https://web.ifantasy.net:7350
 fabric-ca-client register -d --id.name admin1 --id.secret admin1 --id.type admin -u https://web.ifantasy.net:7350
 
构造组织成员证书
- 在各组织下创建 - assets目录,用于储存本组织根证书和用于组间通信的 LTS-CA 根证书:- mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/assets
 cp $LOCAL_CA_PATH/orderer.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/assets/ca-cert.pem
 cp $LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/assets/tls-ca-cert.pem mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/assets
 cp $LOCAL_CA_PATH/soft.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/assets/ca-cert.pem
 cp $LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/assets/tls-ca-cert.pem mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/assets
 cp $LOCAL_CA_PATH/web.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/web.ifantasy.net/assets/ca-cert.pem
 cp $LOCAL_CA_PATH/council.ifantasy.net/ca/crypto/ca-cert.pem $LOCAL_CA_PATH/web.ifantasy.net/assets/tls-ca-cert.pem
 
- 构造 - orderer组织成员证书。
 登录- orderer管理员账户- admin1:- export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/orderer.ifantasy.net/registers/admin1
 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/orderer.ifantasy.net/assets/ca-cert.pem
 export FABRIC_CA_CLIENT_MSPDIR=msp
 fabric-ca-client enroll -d -u https://admin1:admin1@orderer.ifantasy.net:7150
 - 注意:这里是登录上节我们注册的管理员账户而非启动 - CA服务时的引导账户,引导账户跟管理员账户的区别也是我至今难以理解的地方- 以上命令成功后便可以看到 - FABRIC_CA_CLIENT_HOME/FABRIC_CA_CLIENT_MSPDIR目录下生成的证书文件。然后需要构造- admin1的- msp目录:- mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/registers/admin1/msp/admincerts
 cp $LOCAL_CA_PATH/orderer.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/registers/admin1/msp/admincerts/cert.pem
 - 这里的操作仅仅是将 - admin1的签名证书复制到新建的- admincerts文件夹下,这样做的原因是 Fabric 的 MSP 规范要求其下需有- admincerts目录,否则后面操作组织- peer节点时会报错,因此建议在所有联盟链网络服务节点的 msp 目录下添加 admincerts 证书。然后登录- orderer的- orderer1的组织内账户:- export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1
 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/orderer.ifantasy.net/assets/ca-cert.pem
 export FABRIC_CA_CLIENT_MSPDIR=msp
 fabric-ca-client enroll -d -u https://orderer1:orderer1@orderer.ifantasy.net:7150
 mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1/msp/admincerts
 cp $LOCAL_CA_PATH/orderer.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1/msp/admincerts/cert.pem
 - 然后登录 - orderer的- orderer1的组织间 TLS-CA 账户:- export FABRIC_CA_CLIENT_MSPDIR=tls-msp
 export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/orderer.ifantasy.net/assets/tls-ca-cert.pem
 fabric-ca-client enroll -d -u https://orderer1:orderer1@council.ifantasy.net:7050 --enrollment.profile tls --csr.hosts orderer1.orderer.ifantasy.net
 cp $LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1/tls-msp/keystore/*_sk $LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1/tls-msp/keystore/key.pem
 - 最后一步便是构造 - orderer的组织 MSP 目录[2](MSP 目录说明可参考 MSP结构):- mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/msp/admincerts
 mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/msp/cacerts
 mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/msp/tlscacerts
 mkdir -p $LOCAL_CA_PATH/orderer.ifantasy.net/msp/users
 cp $LOCAL_CA_PATH/orderer.ifantasy.net/assets/ca-cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/msp/cacerts/
 cp $LOCAL_CA_PATH/orderer.ifantasy.net/assets/tls-ca-cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/msp/tlscacerts/
 cp $LOCAL_CA_PATH/orderer.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/orderer.ifantasy.net/msp/admincerts/cert.pem
 cp $LOCAL_ROOT_PATH/config/config-msp.yaml $LOCAL_CA_PATH/orderer.ifantasy.net/msp/config.yaml
 - 上面命令最后一行会在组织 - msp目录下添加节点组织单元配置文件- config.yaml,其原理可以参考 节点组织单元和MSP ,如果缺少该文件或者文件内容错误,会报以下错误:- loadLocalMSP -> Failed to setup local msp with config: administrators must be declared when no admin ou classification is set
 - 后面的流程跟这里类似,因此不再赘述。 
- 构造 - soft组织成员证书:
echo "Start Soft============================="
echo "Enroll Admin"
export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1
export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/soft.ifantasy.net/assets/ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp
fabric-ca-client enroll -d -u https://admin1:admin1@soft.ifantasy.net:7250
mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/admincerts
cp $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/admincerts/cert.pem
echo "Enroll Peer1"
export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1
export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/soft.ifantasy.net/assets/ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp
fabric-ca-client enroll -d -u https://peer1:peer1@soft.ifantasy.net:7250
# for TLS
export FABRIC_CA_CLIENT_MSPDIR=tls-msp
export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/soft.ifantasy.net/assets/tls-ca-cert.pem
fabric-ca-client enroll -d -u https://peer1soft:peer1soft@council.ifantasy.net:7050 --enrollment.profile tls --csr.hosts peer1.soft.ifantasy.net
cp $LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1/tls-msp/keystore/*_sk $LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1/tls-msp/keystore/key.pem
mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1/msp/admincerts
cp $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/registers/peer1/msp/admincerts/cert.pem
mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/msp/admincerts
mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/msp/cacerts
mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/msp/tlscacerts
mkdir -p $LOCAL_CA_PATH/soft.ifantasy.net/msp/users
cp $LOCAL_CA_PATH/soft.ifantasy.net/assets/ca-cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/msp/cacerts/
cp $LOCAL_CA_PATH/soft.ifantasy.net/assets/tls-ca-cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/msp/tlscacerts/
cp $LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/soft.ifantasy.net/msp/admincerts/cert.pem
cp $LOCAL_ROOT_PATH/config/config-msp.yaml $LOCAL_CA_PATH/soft.ifantasy.net/msp/config.yaml
echo "End Soft============================="
- 构造 web组织成员证书:
echo "Start Web============================="
echo "Enroll Admin"
export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/web.ifantasy.net/registers/admin1
export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/web.ifantasy.net/assets/ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp
fabric-ca-client enroll -d -u https://admin1:admin1@web.ifantasy.net:7350
mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/admincerts
cp $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/admincerts/cert.pem
echo "Enroll Peer1"
# for identity
export FABRIC_CA_CLIENT_HOME=$LOCAL_CA_PATH/web.ifantasy.net/registers/peer1
export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/web.ifantasy.net/assets/ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp
fabric-ca-client enroll -d -u https://peer1:peer1@web.ifantasy.net:7350
# for TLS
export FABRIC_CA_CLIENT_MSPDIR=tls-msp
export FABRIC_CA_CLIENT_TLS_CERTFILES=$LOCAL_CA_PATH/web.ifantasy.net/assets/tls-ca-cert.pem
fabric-ca-client enroll -d -u https://peer1web:peer1web@council.ifantasy.net:7050 --enrollment.profile tls --csr.hosts peer1.web.ifantasy.net
cp $LOCAL_CA_PATH/web.ifantasy.net/registers/peer1/tls-msp/keystore/*_sk $LOCAL_CA_PATH/web.ifantasy.net/registers/peer1/tls-msp/keystore/key.pem
mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/registers/peer1/msp/admincerts
cp $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/web.ifantasy.net/registers/peer1/msp/admincerts/cert.pem
mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/msp/admincerts
mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/msp/cacerts
mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/msp/tlscacerts
mkdir -p $LOCAL_CA_PATH/web.ifantasy.net/msp/users
cp $LOCAL_CA_PATH/web.ifantasy.net/assets/ca-cert.pem $LOCAL_CA_PATH/web.ifantasy.net/msp/cacerts/
cp $LOCAL_CA_PATH/web.ifantasy.net/assets/tls-ca-cert.pem $LOCAL_CA_PATH/web.ifantasy.net/msp/tlscacerts/
cp $LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp/signcerts/cert.pem $LOCAL_CA_PATH/web.ifantasy.net/msp/admincerts/cert.pem
cp $LOCAL_ROOT_PATH/config/config-msp.yaml $LOCAL_CA_PATH/web.ifantasy.net/msp/config.yaml
echo "End Web============================="
配置系统通道及测试通道
- 在 config目录下创建configtx.yaml配置文件,文件太长在此不做展示,可以在 FabricLearn 中查看,其中各项已加说明注释[^3]。
- 通过 configtxgen生成创世区块和测试通道:configtxgen -profile OrgsOrdererGenesis -outputBlock $LOCAL_ROOT_PATH/data/genesis.block -channelID syschannel
 configtxgen -profile OrgsChannel -outputCreateChannelTx $LOCAL_ROOT_PATH/data/mychannel.tx -channelID mychannel
 
- 在 compose/docker-compose.yaml文件中添加peer和orderer服务相关配置:peer1.soft.ifantasy.net:
 container_name: peer1.soft.ifantasy.net
 extends:
 file: docker-base.yaml
 service: peer-base
 environment:
 - CORE_PEER_ID=peer1.soft.ifantasy.net
 - CORE_PEER_ADDRESS=peer1.soft.ifantasy.net:7051
 - CORE_PEER_LOCALMSPID=softMSP
 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.soft.ifantasy.net:7051
 volumes:
 - ${LOCAL_CA_PATH}/soft.ifantasy.net/registers/peer1:${DOCKER_CA_PATH}/peer
 ports:
 - 7251:7051
 peer1.web.ifantasy.net:
 container_name: peer1.web.ifantasy.net
 extends:
 file: docker-base.yaml
 service: peer-base
 environment:
 - CORE_PEER_ID=peer1.web.ifantasy.net
 - CORE_PEER_ADDRESS=peer1.web.ifantasy.net:7051
 - CORE_PEER_LOCALMSPID=webMSP
 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.web.ifantasy.net:7051
 volumes:
 - ${LOCAL_CA_PATH}/web.ifantasy.net/registers/peer1:${DOCKER_CA_PATH}/peer
 ports:
 - 7351:7051
 orderer1.orderer.ifantasy.net:
 container_name: orderer1.orderer.ifantasy.net
 extends:
 file: docker-base.yaml
 service: orderer-base
 environment:
 - ORDERER_HOST=orderer1.orderer.ifantasy.net
 - ORDERER_GENERAL_LOCALMSPID=ordererMSP
 volumes:
 - ${LOCAL_CA_PATH}/orderer.ifantasy.net/registers/orderer1:${DOCKER_CA_PATH}/orderer
 - ${LOCAL_ROOT_PATH}/data/genesis.block:${DOCKER_CA_PATH}/orderer/genesis.block
 ports:
 - 7151:7777
 
- 启动 peer和orderer服务:docker-compose -f $LOCAL_ROOT_PATH/compose/docker-compose.yaml up -d peer1.soft.ifantasy.net peer1.web.ifantasy.net orderer1.orderer.ifantasy.net
 此时我们已经启动了所有联盟链网络所需的容器如下: (base) root@DebianA:1_3Org2Peer1Orderer1TLS# docker ps
 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
 1c59b88fa847 hyperledger/fabric-peer:2.4 "peer node start" 8 seconds ago Up 6 seconds 0.0.0.0:7251->7051/tcp peer1.soft.ifantasy.net
 3906338f6861 hyperledger/fabric-peer:2.4 "peer node start" 8 seconds ago Up 6 seconds 0.0.0.0:7351->7051/tcp peer1.web.ifantasy.net
 9f127a054343 hyperledger/fabric-orderer:2.4 "orderer" 8 seconds ago Up 6 seconds 7050/tcp, 0.0.0.0:7151->7777/tcp orderer1.orderer.ifantasy.net
 949abd8f7070 hyperledger/fabric-ca:1.5 "sh -c 'fabric-ca-se…" About an hour ago Up About an hour 7054/tcp, 0.0.0.0:7150->7050/tcp orderer.ifantasy.net
 011fe2b36c01 hyperledger/fabric-ca:1.5 "sh -c 'fabric-ca-se…" About an hour ago Up About an hour 0.0.0.0:7050->7050/tcp, 7054/tcp council.ifantasy.net
 207879f5bb33 hyperledger/fabric-ca:1.5 "sh -c 'fabric-ca-se…" About an hour ago Up About an hour 7054/tcp, 0.0.0.0:7350->7050/tcp web.ifantasy.net
 d1850c86e096 hyperledger/fabric-ca:1.5 "sh -c 'fabric-ca-se…" About an hour ago Up About an hour 7054/tcp, 0.0.0.0:7250->7050/tcp soft.ifantasy.net
 
- 补全根目录中 envpeer1soft的环境变量:export LOCAL_ROOT_PATH=$PWD
 export LOCAL_CA_PATH=$LOCAL_ROOT_PATH/orgs
 export DOCKER_CA_PATH=/tmp
 export COMPOSE_PROJECT_NAME=fabriclearn
 export DOCKER_NETWORKS=network
 export FABRIC_BASE_VERSION=2.4
 export FABRIC_CA_VERSION=1.5
 echo "init terminal soft"
 export FABRIC_CFG_PATH=$LOCAL_ROOT_PATH/config
 export CORE_PEER_TLS_ENABLED=true
 export CORE_PEER_LOCALMSPID="softMSP"
 export CORE_PEER_ADDRESS=peer1.soft.ifantasy.net:7251
 export CORE_PEER_TLS_ROOTCERT_FILE=$LOCAL_CA_PATH/soft.ifantasy.net/assets/tls-ca-cert.pem
 export CORE_PEER_MSPCONFIGPATH=$LOCAL_CA_PATH/soft.ifantasy.net/registers/admin1/msp
 export ORDERER_CA=$LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1/tls-msp/tlscacerts/tls-council-ifantasy-net-7050.pem
 
- 复制 envpeer1soft为envpeer1web作为 web 组织的环境变量:export LOCAL_ROOT_PATH=$PWD
 export LOCAL_CA_PATH=$LOCAL_ROOT_PATH/orgs
 export DOCKER_CA_PATH=/tmp
 export COMPOSE_PROJECT_NAME=fabriclearn
 export DOCKER_NETWORKS=network
 export FABRIC_BASE_VERSION=2.4
 export FABRIC_CA_VERSION=1.5
 echo "init terminal web"
 export FABRIC_CFG_PATH=$LOCAL_ROOT_PATH/config
 export CORE_PEER_TLS_ENABLED=true
 export CORE_PEER_LOCALMSPID="webMSP"
 export CORE_PEER_ADDRESS=peer1.web.ifantasy.net:7351
 export CORE_PEER_TLS_ROOTCERT_FILE=$LOCAL_CA_PATH/web.ifantasy.net/assets/tls-ca-cert.pem
 export CORE_PEER_MSPCONFIGPATH=$LOCAL_CA_PATH/web.ifantasy.net/registers/admin1/msp
 export ORDERER_CA=$LOCAL_CA_PATH/orderer.ifantasy.net/registers/orderer1/tls-msp/tlscacerts/tls-council-ifantasy-net-7050.pem
 
- 通过 soft创建mychannel测试通道的创世区块:source envpeer1soft
 peer channel create -c mychannel -f $LOCAL_ROOT_PATH/data/mychannel.tx -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --outputBlock $LOCAL_ROOT_PATH/data/mychannel.block
 如果出现以下错误,请检查环境变量 FABRIC_CFG_PATH所指目录是否包含core.yaml配置文件:InitCmd -> ERRO 001 Fatal error when initializing core config : Could not find config file. Please make sure that FABRIC_CFG_PATH is set to a path which contains core.yaml
 如果出现以下错误,请检查环境变量 CORE_PEER_TLS_ROOTCERT_FILE是否只想TLS-CA根证书、 环境变量ORDERER_CA是否指向orderer1的TLS-CA根证书:ERRO 002 Client TLS handshake failed after 1.116738ms with error: x509: certificate is not valid for any names, but wanted to match localhost remoteaddress=127.0.0.1:7151
 
- 将 mychannel创世区块复制到其成员组织目录:cp $LOCAL_ROOT_PATH/data/mychannel.block $LOCAL_CA_PATH/soft.ifantasy.net/assets/
 cp $LOCAL_ROOT_PATH/data/mychannel.block $LOCAL_CA_PATH/web.ifantasy.net/assets/
 
- 分别通过成员组织的 cli 加入通道:
source envpeer1soft
 peer channel join -b $LOCAL_CA_PATH/soft.ifantasy.net/assets/mychannel.block
 source envpeer1web
 peer channel join -b $LOCAL_CA_PATH/web.ifantasy.net/assets/mychannel.block
 如果出现以下错误,请检查环境变量 CORE_PEER_ADDRESS是否与对应组织的docker配置中的peer地址和端口是否一致:Client TLS handshake failed after 1.554615ms with error: x509: certificate is valid for peer1soft, peer1.soft.ifantasy.net, not soft.ifantasy.net remoteaddress=127.0.0.1:7251
 成功后,便可通过 peer channel getinfo -c mychannel查看已加入通道:
  
安装/测试链码
- soft打包并安装链码:- source envpeer1soft
 peer lifecycle chaincode package basic.tar.gz --path asset-transfer-basic/chaincode-go --label basic_1
 peer lifecycle chaincode install basic.tar.gz
 - 安装成功后,可使用 - peer lifecycle chaincode queryinstalled命令查询已安装链码信息(其中- Package ID需要记下来):- (base) root@DebianA:1_3Org2Peer1Orderer1TLS# peer lifecycle chaincode queryinstalled
 Installed chaincodes on peer:
 Package ID: basic_1:06613e463ef6694805dd896ca79634a2de36fdf019fa7976467e6e632104d718, Label: basic_1
 
- web安装链码:- source envpeer1web
 peer lifecycle chaincode install basic.tar.gz
 
- 设置链码 ID环境变量:export CHAINCODE_ID=basic_1:06613e463ef6694805dd896ca79634a2de36fdf019fa7976467e6e632104d718
 
- soft和- web批准链码:- source envpeer1soft
 peer lifecycle chaincode approveformyorg -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --channelID mychannel --name basic --version 1.0 --sequence 1 --waitForEvent --init-required --package-id $CHAINCODE_ID
 source envpeer1web
 peer lifecycle chaincode approveformyorg -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --channelID mychannel --name basic --version 1.0 --sequence 1 --waitForEvent --init-required --package-id $CHAINCODE_ID
 - 批准后,可使用以下命令查看本组织的链码批准情况: - (base) root@DebianA:1_3Org2Peer1Orderer1TLS# peer lifecycle chaincode queryapproved -C mychannel -n basic --sequence 1
 Approved chaincode definition for chaincode 'basic' on channel 'mychannel':
 sequence: 1, version: 1.0, init-required: true, package-id: basic_1:06613e463ef6694805dd896ca79634a2de36fdf019fa7976467e6e632104d718, endorsement plugin: escc, validation plugin: vscc
 - 也可使用以下命令查看指定链码是否已准备好被提交: - (base) root@DebianA:1_3Org2Peer1Orderer1TLS# peer lifecycle chaincode checkcommitreadiness -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --channelID mychannel --name basic --version 1.0 --sequence 1 --init-required
 Chaincode definition for chaincode 'basic', version '1.0', sequence '1' on channel 'mychannel' approval status by org:
 softMSP: true
 webMSP: true
 
- 使用任意合法组织提交链码:
source envpeer1soft
 peer lifecycle chaincode commit -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --channelID mychannel --name basic --init-required --version 1.0 --sequence 1 --peerAddresses peer1.soft.ifantasy.net:7251 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE --peerAddresses peer1.web.ifantasy.net:7351 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE
 可使用以下命令查看链码提交情况: peer lifecycle chaincode querycommitted --channelID mychannel --name basic -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --peerAddresses peer1.soft.ifantasy.net:7251 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE
 
- 初始化链码(非必须):
peer chaincode invoke --isInit -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --channelID mychannel --name basic --peerAddresses peer1.soft.ifantasy.net:7251 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE --peerAddresses peer1.web.ifantasy.net:7351 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE -c '{"Args":["InitLedger"]}'
 其中带 --isInit 参数表示当前调用为链码初始化调用,在不需要初始化的链码中可以省略此步骤。如果出现下列错误,请检查: - 整个 docker内的networks的值必须为${DOCKER_NETWORKS}
- 环境变量中 COMPOSE_PROJECT_NAME和DOCKER_NETWORKS是否被赋值、
- docker-base.yaml中- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE的值必须是- ${COMPOSE_PROJECT_NAME}_${DOCKER_NETWORKS}
 error starting container: error starting container: API error (404): network hyperledger_fabric-ca not found"
 
- 整个 
- 调用链码:
peer chaincode invoke -o orderer1.orderer.ifantasy.net:7151 --tls --cafile $ORDERER_CA --channelID mychannel --name basic --peerAddresses peer1.soft.ifantasy.net:7251 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE --peerAddresses peer1.web.ifantasy.net:7351 --tlsRootCertFiles $CORE_PEER_TLS_ROOTCERT_FILE -c '{"Args":["GetAllAssets"]}'
 如果出现下列错误,请检查 approveformyorg的链码包ID与install的链码包ID必须一致:endorsement failure during invoke. response: status:500 message:"make sure the chaincode fabcar has been successfully defined on channel mychannel and try again: chaincode definition for 'basic' exists, but chaincode is not installed"
 调用成功后可在控制台查看链码输出: 2022-04-05 14:25:16.529 CST 0001 INFO [chaincodeCmd] chaincodeInvokeOrQuery -> Chaincode invoke successful. result: status:200 payload:"[{\"ID\":\"asset1\",\"color\":\"blue\",\"size\":5,\"owner\":\"Tomoko\",\"appraisedValue\":300},{\"ID\":\"asset2\",\"color\":\"red\",\"size\":5,\"owner\":\"Brad\",\"appraisedValue\":400},{\"ID\":\"asset3\",\"color\":\"green\",\"size\":10,\"owner\":\"Jin Soo\",\"appraisedValue\":500},{\"ID\":\"asset4\",\"color\":\"yellow\",\"size\":10,\"owner\":\"Max\",\"appraisedValue\":600},{\"ID\":\"asset5\",\"color\":\"black\",\"size\":15,\"owner\":\"Adriana\",\"appraisedValue\":700},{\"ID\":\"asset6\",\"color\":\"white\",\"size\":15,\"owner\":\"Michel\",\"appraisedValue\":800}]"
 
参考
- Nisen. Fabric账号、cryptogen和fabirc-ca. github.io. [2018-06-19] ︎ 
- Hyperledger. 成员服务提供者 (MSP). hyperledger-fabric.readthedocs.io. [2021-05-22] ︎ 
Hyperledger Fabric定制联盟链网络工程实践的更多相关文章
- HyperLedger Fabric Introduction——区块链超级账本介绍
		介绍 HyperLedger Fabric是一个基于模块化架构的分布式账本解决方案平台,它拥有深度加密.便捷扩展.部署灵活及可插拔等特性.它设计之初的目的是支持不同组件的可插拔实现,并适应整个经济生态 ... 
- 搭建基于hyperledger fabric的联盟社区(五) --启动Fabric网络
		现在所有的文件都已经准备完毕,我们可以启动fabric网络了. 一.启动orderer节点 在orderer服务器上运行: cd ~/go/src/github.com/hyperledger/fab ... 
- 搭建基于hyperledger fabric的联盟社区(六) --搭建node.js服务器
		接下来我要做的是用fabric sdk来做出应用程序,代替CLI与整个区块链网络交互.并且实现一个http API,向社区提供一个简单的接口,使社区轻松的与区块链交互. 官方虽然提供了Node.JS, ... 
- 搭建基于hyperledger fabric的联盟社区(四) --chaincode开发
		前几章已经分别把三台虚拟机环境和配置文件准备好了,在启动fabric网络之前我们要准备好写好的chaincode.chaincode的开发一般是使用GO或者JAVA,而我选择的是GO语言.先分析一下官 ... 
- 搭建基于hyperledger fabric的联盟社区(一) --前言
		三个月前上面发了一个关于智群汇聚和问题求解研究的项目,我们公司做其中的一个子项目,就是基于区块链的科技信息联盟构建.利用区块链的去中心化特性,构建一个基于区块链的科技社区,以提供科技群智汇聚采集的基础 ... 
- Hyperledger Fabric 建立一个简单网络
		Building you first network 网络结构: 2个Orgnizations(每个Org包含2个peer节点)+1个solo ordering service 打开fabric-sa ... 
- 搭建基于hyperledger fabric的联盟社区(二) --环境配置
		接下来讲一下在本地测试区块链网络的过程.我要部署的是2peer+1orderer架构,所以需要准备三台虚拟机,为了方便起见可以先把一台配置好,然后复制出剩余两台即可.搭建虚拟机我用的是virtualb ... 
- Hyperledger Fabric【区块链学习一】
		Hyperledger Fabric 学习 什么是区块链 什么是区块链在我们没有接触的时候,只知道它是一个去中心化的存储方式.当我们发生交易,或者动作的时候我们会将记录通知给所有参与者共同维护,达到去 ... 
- 搭建基于hyperledger fabric的联盟社区(七) --升级chaincode
		上个版本的chaincode有很多功能不完备,所以要部署新版本的chaincode.Fabric支持在保留现有状态的前提对chaincode进行升级. 一.新版chaincode 新版本的chainc ... 
随机推荐
- rodert教你学FFmpeg实战这一篇就够了
			rodert教你学FFmpeg实战这一篇就够了 建议收藏,以备查阅 pdf阅读版: 链接:https://pan.baidu.com/s/11kIaq5V6A_pFX3yVoTUvzA 提取码:jav ... 
- centos7升级openssh8.7&openssl1.1.1l脚本
			脚本下载地址或首页联系本人获取 https://files.cnblogs.com/files/blogs/705493/update_ssh.sh 需搭配openssh8.7和openssl1.1. ... 
- 远程调用NFS超时,服务卡死
			远程调用NFS超时,服务卡死 如何查看进程中使用了哪些文件句柄? 
- windows server 2008r2 在vmware里自动关机
			虚拟机没有激活所以导致自动关机,试试激活它.<wiz_tmp_tag id="wiz-table-range-border" contenteditable="fa ... 
- 配置文件 /etc/profile出错导致ls,vi不能用
			配置文件 /etc/profile出错导致ls,vi不能用 关于 Linux 的配置文件 /etc/profile 路径出错后相关的命令失效解决方式(如:ls,vi不能用) 一般我记得vi是在 ... 
- 什么是BGP
			BGP概述 边界网关协议(BGP)是运行于TCP协议上的一种自治系统的路由协议. 是一种外部路由协议. AS概述 自治系统(AS),指的是同一个使用相同策略的设备的集合. 每个AS有自己位移的编号,不 ... 
- KestrelServer详解[2]: 网络链接的创建
			<注册监听终结点(Endpoint)>已经详细讲述了如何使用KestrelServer,现在我们来简单聊聊这种处理器的总体设计和实现原理.当KestrelServer启动的时候,注册的每个 ... 
- Notion-douan:搭建自己的阅读清单
			前言 交完论文盲审稿,终于从接近一年的实习.秋招和论文的忙碌中闲下来. 在复盘秋招的时候发现自己虽然看过不少书,但缺少整理和思考,所以想趁这个机会梳理一下自己的阅读习惯,希望以后再读新的东西可以更系统 ... 
- kafka 如何不消费重复数据?比如扣款,我们不能重复的扣?
			其实还是得结合业务来思考,我这里给几个思路: 比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入 了,update 一下好吧. 比如你是写 Redis,那没问题了,反正每次都是 s ... 
- 什么是redis的缓存雪崩与缓存穿透?如何解决?
			一.缓存雪崩 1.1 什么是缓存雪崩? 首先我们先来回答一下我们为什么要用缓存(Redis): 1.提高性能能:缓存查询是纯内存访问,而硬盘是磁盘访问,因此缓存查询速度比数据库查询速度快 2.提高并发 ... 
