阅历笔记

阅历笔记 查看完整档案

北京编辑华北水利水电大学  |  软件技术 编辑北京启迪区块链科技发展有限公司  |  软件工程师 编辑 segmentfault.com/u/yuelicn 编辑
编辑

喷泉之所以漂亮是因为她有了压力;
瀑布之所以壮观是因为她没有了退路;
水之所以能穿石是因为永远在坚持。

个人动态

阅历笔记 发布了文章 · 2020-08-14

进阶篇(一)Fabric 2.0 手动生成CA证书搭建Fabric网络-Raft协议-多orderer节点

本文不会在从0开始搭建Fabric网络,我们会在<<Hyperledger Fabric 2.0 手动生成CA证书搭建Fabric网络-Raft协议>>的基础上来改进,将上文中单orderer节点改成多节点共识。

本次将orderer改为三个节点, 自己需要更多节点的可以自己根据实际况进行增加,步骤和方法相同。

一、orderer节点用户注册(TLS)

在向TLS注册用户时,有以前注册单用户改成注册多用户(三个节点、orderer1-org0,orderer2-org0,orderer3-org0)
https://0.0.0.0:7052为TLS CA 地址,

fabric-ca-client register -d --id.name orderer1-org0 --id.secret ordererPW --id.type orderer
-u https://0.0.0.0:7052 --tls.certfiles /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem

fabric-ca-client register -d --id.name orderer2-org0 --id.secret ordererPW --id.type orderer -u https://0.0.0.0:7052 --tls.certfiles /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem

fabric-ca-client register -d --id.name orderer3-org0 --id.secret ordererPW --id.type orderer -u https://0.0.0.0:7052 --tls.certfiles /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem

二、org0注册用户

同样需要注册三个节点用户

export FABRIC_CA_CLIENT_TLS_CERTFILES=/data/hyperledger/org0/ca/crypto/ca-cert.pem
export FABRIC_CA_CLIENT_HOME=/data/hyperledger/org0/ca/admin
fabric-ca-client enroll -d -u https://org0-admin:org0-adminpw@0.0.0.0:7053 --tls.certfiles /tmp/hyperledger/org0/ca/crypto/ca-cert.pem

#注册order1用户
fabric-ca-client register -d --id.name orderer1-org0 --id.secret ordererpw --id.type orderer --id.attrs '"hf.Registrar.Roles=orderer"' -u https://0.0.0.0:7053  --tls.certfiles /tmp/hyperledger/org0/ca/crypto/ca-cert.pem

#注册order2用户
fabric-ca-client register -d --id.name orderer2-org0 --id.secret ordererpw --id.type orderer --id.attrs '"hf.Registrar.Roles=orderer"' -u https://0.0.0.0:7053  --tls.certfiles /tmp/hyperledger/org0/ca/crypto/ca-cert.pem

#注册order3用户
fabric-ca-client register -d --id.name orderer3-org0 --id.secret ordererpw --id.type orderer --id.attrs '"hf.Registrar.Roles=orderer"' -u https://0.0.0.0:7053  --tls.certfiles /tmp/hyperledger/org0/ca/crypto/ca-cert.pem

fabric-ca-client register -d --id.name admin-org0 --id.secret org0adminpw --id.type admin --id.attrs "hf.Registrar.Roles=client,hf.Registrar.Attributes=*,hf.Revoker=true,hf.GenCRL=true,admin=true:ecert,abac.init=true:ecert" -u https://0.0.0.0:7053 --tls.certfiles /tmp/hyperledger/org0/ca/crypto/ca-cert.pem

三、生成oerders MSP证书


mkdir -p /tmp/hyperledger/org0/orderers/assets/ca/
cp /tmp/hyperledger/org0/ca/crypto/ca-cert.pem /tmp/hyperledger/org0/orderers/assets/ca/org0-ca-cert.pem
export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org0/orderers/orderer1-org0

#orderer1 msp证书
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org0/orderers/assets/ca/org0-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp
fabric-ca-client enroll -u https://orderer1-org0:ordererpw@0.0.0.0:7053 -M /tmp/hyperledger/org0/orderers/orderer1-org0/msp --csr.hosts orderer1-org0 --tls.certfiles /tmp/hyperledger/org0/ca/crypto/ca-cert.pem

#orderer2 msp证书
export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org0/orderers/orderer2-org0
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org0/orderers/assets/ca/org0-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp
fabric-ca-client enroll -u https://orderer2-org0:ordererpw@0.0.0.0:7053 -M /tmp/hyperledger/org0/orderers/orderer2-org0/msp --csr.hosts orderer2-org0 --tls.certfiles /tmp/hyperledger/org0/ca/crypto/ca-cert.pem

#orderer3 msp证书
export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org0/orderers/orderer3-org0
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org0/orderers/assets/ca/org0-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp
fabric-ca-client enroll -u https://orderer3-org0:ordererpw@0.0.0.0:7053 -M /tmp/hyperledger/org0/orderers/orderer3-org0/msp --csr.hosts orderer3-org0 --tls.certfiles /tmp/hyperledger/org0/ca/crypto/ca-cert.pem


#admin msp证书
export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org0/admin
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org0/orderers/assets/ca/org0-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp
fabric-ca-client enroll -d -u https://admin-org0:org0adminpw@0.0.0.0:7053 --tls.certfiles /tmp/hyperledger/org0/orderers/assets/ca/org0-ca-cert.pem

四、生成oerders tls-ca证书

mkdir /tmp/hyperledger/org0/orderers/assets/tls-ca/
cp /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem /tmp/hyperledger/org0/orderers/assets/tls-ca/tls-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=tls-msp
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org0/orderers/assets/tls-ca/tls-ca-cert.pem

fabric-ca-client enroll -u https://orderer1-org0:ordererPW@0.0.0.0:7052  -M /tmp/hyperledger/org0/orderers/orderer1-org0/tls-msp --enrollment.profile tls --csr.hosts orderer1-org0 --tls.certfiles /data/hyperledger/org0/orderers/tls-ca-cert.pem

fabric-ca-client enroll -u https://orderer2-org0:ordererPW@0.0.0.0:7052  -M /tmp/hyperledger/org0/orderers/orderer2-org0/tls-msp --enrollment.profile tls --csr.hosts orderer2-org0 --tls.certfiles /data/hyperledger/org0/orderers/tls-ca-cert.pem

fabric-ca-client enroll -u https://orderer3-org0:ordererPW@0.0.0.0:7052  -M /tmp/hyperledger/org0/orderers/orderer3-org0/tls-msp --enrollment.profile tls --csr.hosts orderer3-org0 --tls.certfiles /data/hyperledger/org0/orderers/tls-ca-cert.pem


#修改keystore名称
mv /tmp/hyperledger/org0/orderers/orderer1-org0/tls-msp/keystore/*_sk /tmp/hyperledger/org0/orderers/orderer1-org0/tls-msp/keystore/key.pem
mv /tmp/hyperledger/org0/orderers/orderer2-org0/tls-msp/keystore/*_sk /tmp/hyperledger/org0/orderers/orderer2-org0/tls-msp/keystore/key.pem
mv /tmp/hyperledger/org0/orderers/orderer3-org0/tls-msp/keystore/*_sk /tmp/hyperledger/org0/orderers/orderer3-org0/tls-msp/keystore/key.pem


#生成admincerts目录

mkdir /tmp/hyperledger/org0/orderers/orderer1-org0/msp/admincerts
cp /tmp/hyperledger/org0/admin/msp/signcerts/cert.pem /data/hyperledger/org0/orderers/orderer1-org0/msp/admincerts/orderer-admin-cert.pem


mkdir /tmp/hyperledger/org0/orderers/orderer2-org0/msp/admincerts
cp /tmp/hyperledger/org0/admin/msp/signcerts/cert.pem /data/hyperledger/org0/orderers/orderer2-org0/msp/admincerts/orderer-admin-cert.pem

mkdir /tmp/hyperledger/org0/orderers/orderer3-org0/msp/admincerts
cp /tmp/hyperledger/org0/admin/msp/signcerts/cert.pem /data/hyperledger/org0/orderers/orderer3-org0/msp/admincerts/orderer-admin-cert.pem

⚠️: 同理在每个orderer节点msp下面添加config.yaml文件

五、修改configtx.yaml共识策略

configtx.yaml 文件内容比较长,我在这就不贴全部,只贴出需要修改的地方, 完整文件请参照上一篇文章,

Orderer: &OrdererDefaults

    # Orderer Type: The orderer implementation to start
    OrdererType: etcdraft

    EtcdRaft:
        Consenters:
        - Host: orderer1-org0
          Port: 7050
          ClientTLSCert: /tmp/hyperledger/org0/orderers/orderer1-org0/tls-msp/signcerts/cert..
pem
          ServerTLSCert: /tmp/hyperledger/org0/orderers/orderer1-org0/tls-msp/signcerts/cert..
pem
        - Host: orderer2-org0
          Port: 7050
          ClientTLSCert: /tmp/hyperledger/org0/orderers/orderer2-org0/tls-msp/signcerts/cert..
pem
          ServerTLSCert: /tmp/hyperledger/org0/orderers/orderer2-org0/tls-msp/signcerts/cert..
pem

        - Host: orderer3-org0
          Port: 7050
          ClientTLSCert: /tmp/hyperledger/org0/orderers/orderer3-org0/tls-msp/signcerts/cert..
pem
          ServerTLSCert: /tmp/hyperledger/org0/orderers/orderer3-org0/tls-msp/signcerts/cert..
pem
    Addresses:
        - orderer1-org0:7050
        - orderer2-org0:7050
        - orderer3-org0:7050

只需要修改orderer共识策略这块就可以了,其它按照原流程不需要变。

六、启动所有orderer节点

6.1 orderer1启动


version: '2'

networks:
  fabric-ca:
services: 
  orderer1-org0:
    container_name: orderer1-org0
    image: hyperledger/fabric-orderer:2.1.0
    environment:
      - ORDERER_HOME=/tmp/hyperledger/orderer
      - ORDERER_HOST=orderer1-org0
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_GENESISMETHOD=file
      - ORDERER_GENERAL_GENESISFILE=/tmp/hyperledger/genesis.block
      - ORDERER_GENERAL_LOCALMSPID=org0MSP
      - ORDERER_GENERAL_LOCALMSPDIR=/tmp/hyperledger/org0/orderer/msp
      - ORDERER_GENERAL_TLS_ENABLED=true
      - ORDERER_GENERAL_TLS_CERTIFICATE=/tmp/hyperledger/org0/orderer/tls-msp/signcerts/cert.pem
      - ORDERER_GENERAL_TLS_PRIVATEKEY=/tmp/hyperledger/org0/orderer/tls-msp/keystore/key.pem
      - ORDERER_GENERAL_TLS_ROOTCAS=[/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem]
      - ORDERER_GENERAL_LOGLEVEL=debug
      - ORDERER_DEBUG_BROADCASTTRACEDIR=data/logs
    volumes:
      - /tmp/hyperledger/org0/fabric-ca-client/orderers/orderer1-org0:/tmp/hyperledger/org0/orderer/
      - /tmp/hyperledger/block:/tmp/hyperledger/
    networks:
      - fabric-ca

6.2 orderer2启动


version: '2'

networks:
  fabric-ca:
services: 
  orderer2-org0:
    container_name: orderer2-org0
    image: hyperledger/fabric-orderer:2.1.0
    environment:
      - ORDERER_HOME=/tmp/hyperledger/orderer
      - ORDERER_HOST=orderer2-org0
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_GENESISMETHOD=file
      - ORDERER_GENERAL_GENESISFILE=/tmp/hyperledger/genesis.block
      - ORDERER_GENERAL_LOCALMSPID=org0MSP
      - ORDERER_GENERAL_LOCALMSPDIR=/tmp/hyperledger/org0/orderer/msp
      - ORDERER_GENERAL_TLS_ENABLED=true
      - ORDERER_GENERAL_TLS_CERTIFICATE=/tmp/hyperledger/org0/orderer/tls-msp/signcerts/cert.pem
      - ORDERER_GENERAL_TLS_PRIVATEKEY=/tmp/hyperledger/org0/orderer/tls-msp/keystore/key.pem
      - ORDERER_GENERAL_TLS_ROOTCAS=[/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem]
      - ORDERER_GENERAL_LOGLEVEL=debug
      - ORDERER_DEBUG_BROADCASTTRACEDIR=data/logs
    volumes:
      - /tmp/hyperledger/org0/fabric-ca-client/orderers/orderer2-org0:/tmp/hyperledger/org0/orderer/
      - /tmp/hyperledger/block:/tmp/hyperledger/
    networks:
      - fabric-ca

6.3 orderer3启动


version: '2'

networks:
  fabric-ca:
services: 
  orderer3-org0:
    container_name: orderer3-org0
    image: hyperledger/fabric-orderer:2.0.0
    environment:
      - ORDERER_HOME=/tmp/hyperledger/orderer
      - ORDERER_HOST=orderer2-org0
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_GENESISMETHOD=file
      - ORDERER_GENERAL_GENESISFILE=/tmp/hyperledger/genesis.block
      - ORDERER_GENERAL_LOCALMSPID=org0MSP
      - ORDERER_GENERAL_LOCALMSPDIR=/tmp/hyperledger/org0/orderer/msp
      - ORDERER_GENERAL_TLS_ENABLED=true
      - ORDERER_GENERAL_TLS_CERTIFICATE=/tmp/hyperledger/org0/orderer/tls-msp/signcerts/cert.pem
      - ORDERER_GENERAL_TLS_PRIVATEKEY=/tmp/hyperledger/org0/orderer/tls-msp/keystore/key.pem
      - ORDERER_GENERAL_TLS_ROOTCAS=[/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem]
      - ORDERER_GENERAL_LOGLEVEL=debug
      - ORDERER_DEBUG_BROADCASTTRACEDIR=data/logs
    volumes:
      - /tmp/hyperledger/org0/fabric-ca-client/orderers/orderer3-org0:/tmp/hyperledger/org0/orderer/
      - /tmp/hyperledger/block:/tmp/hyperledger/
    networks:
      - fabric-ca

到这多节点改动已经完成, 上述在<<Hyperledger Fabric 2.0 手动生成CA证书搭建Fabric网络-Raft协议>>基础上来修改ordderer共识节点流程,其它流程不变。再次申明这个篇文章不是一个完整顺序的流程。

结合这两篇文章,Hyperledger Fabric 2.0 手动生成CA证书搭建Fabric网络-Raft协议-多orderer节点部署因该不会有任何问题, 可以直接用于生产环境。

如有错误,请指教。谢谢!

查看原文

赞 1 收藏 0 评论 0

阅历笔记 发布了文章 · 2020-07-22

Hyperledger Fabric 2.0 手动生成CA证书(TLS)搭建Fabric网络-Raft协议

1、总体架构

fabric-ca-arch.jpg
官方采用的是多机部署环境、这里就简化下下,所有操作就简化下都在一台机器上。多机环境后面在验证。

下面介绍下本文所采用的整体架构
三个组织

  • Org0 ---> 组织0
  • Org1 ---> 组织1
  • Org2 ---> 组织2

组织中的成员

  • Org0: 一个orderer节点,一个Org0的Admin节点
  • Org1: 两个Peer节点,一个Org1的Admin节点,一个Org1的User节点
  • Org2: 两个Peer节点,一个Org2的Admin节点,一个Org2的User节点

四台CA服务器

  • TLS服务器:为网络中所有节点颁发TLS证书,用于通信的加密
  • Org1的CA服务器:为组织1中所有用户颁发证书
  • Org2的Ca服务器:为组织2中所有用户颁发证书
  • Org0的CA服务器:为组织0中所有用户颁发证书

这里的四台CA服务器都是根服务器。彼此之间都是独立的存在,没有任何关系。,也就是说每一个CA服务器生成的证书在其他CA服务器都是不能用的。
介绍完之后,可以进入正题了。

2、Fabric、Fabric-CA环境搭建

Fabric、Fabric-CA的基础环境搭建就不再这里说了,不明白的可以去看官网。

完成环境搭建以后我们还需要一个 HOME 目录用于存放我们生成的证书文件以及Fabric配置文件,本文设置的HOME路径为:

/tmp/hyperledger

这个自行创建,一般不要用太复杂的路径,也不要用中文路径,会为之后的操作带来很多麻烦。在下文中简单称HOME文件夹为工作目录,除非特殊说明,一般命令的执行都是在工作目录进行。

注:因所有服务启动均使用docker-compose为了使其在同一个docker network 我们需要设置export COMPOSE_PROJECT_NAME=net 或者将所有的docker-compose 文件存放在一个目录下。

3、CA服务器的配置

3.1启动TLS CA服务器

前期工作准备好之后,我们开始启动第一台CA服务器。本文中使用Docker容器启动。

3.1.1 创建docker-compose.yaml文件
mkdir -p /tmp/hyperledger/docker-compose/fabric-ca-tls && cd /tmp/hyperledger/docker-compose/fabric-ca-tls

touch docker-compose.yaml

并在文件内添加以下内容(tips:内容格式不要乱掉):

version: '2'

networks:
  fabric-ca:
services:
   ca-tls:
     container_name: ca-tls
     image: hyperledger/fabric-ca
     command: sh -c 'fabric-ca-server start -d -b tls-ca-admin:tls-ca-adminpw --port 7052'
     environment:
       - FABRIC_CA_SERVER_HOME=/tmp/hyperledger/fabric-ca/crypto
       - FABRIC_CA_SERVER_TLS_ENABLED=true
       - FABRIC_CA_SERVER_CSR_CN=ca-tls
       - FABRIC_CA_SERVER_CSR_HOSTS=0.0.0.0
       - FABRIC_CA_SERVER_PORT=7052
       - FABRIC_CA_SERVER_DEBUG=true
     volumes:
       - /tmp/hyperledger/fabric-ca-tls:/tmp/hyperledger/fabric-ca
     networks:
       - fabric-ca
     ports:
       - 7052:7052

启动docker容器
docker-compose up -d
如果命令行出现以下内容则说明启动成功:
[INFO] Listening on https://0.0.0.0:7052

同时工作目录/tmp/hyperledger/fabric-ca/ 下面会出现crypto文件夹,里面的具体内容不在这解释,想了解的可以去官网查看。不过有个一文件需要解释下,应为之后会频繁的使用到。

在/tmp/hyperledger/fabric-ca/crypto/路径下的ca-cert.pem文件。这是TLS CA服务器的签名根证书,目的是用来对CA的TLS证书进行验证,同时也需要持有这个证书才可以进行证书的颁发。

多环境下我们需要将它复制到每一台机器上。
3.1.2 TLS CA 服务器注册用户

第一步是在TLS CA服务器中注册用户,经过注册的用户才拥有TLS证书。

设置环境变量&登陆

#设置环境变量指定根证书的路径(如果工作目录不同的话记得指定自己的工作目录,以下不再重复说明)
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem
#设置环境变量指定CA客户端的HOME文件夹
export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/fabric-ca-tls/admin
#登录管理员用户用于之后的节点身份注册
fabric-ca-client enroll -d -u https://tls-ca-admin:tls-ca-adminpw@0.0.0.0:7052 --tls.certfiles /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem

登陆成功后会在/tmp/hyperledger/fabric-ca-tls/目录下生车给你admin文件夹,这里面是 admin相关的证书文件,并且只有登陆了admin,才具有权限进行用户注册,因为该用户具有CA的全部权限,相当于CA服务的root用户。

接下来对各个节点和用户进行注册

fabric-ca-client register -d --id.name peer1-org1 --id.secret peer1PW --id.type peer -u https://0.0.0.0:7052 --tls.certfiles /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem

fabric-ca-client register -d --id.name peer2-org1 --id.secret peer2PW --id.type peer -u https://0.0.0.0:7052 --tls.certfiles /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem

fabric-ca-client register -d --id.name peer1-org2 --id.secret peer1PW --id.type peer -u https://0.0.0.0:7052 --tls.certfiles /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem

fabric-ca-client register -d --id.name peer2-org2 --id.secret peer2PW --id.type peer -u https://0.0.0.0:7052 --tls.certfiles /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem

fabric-ca-client register -d --id.name orderer1-org0 --id.secret ordererPW --id.type orderer -u https://0.0.0.0:7052 --tls.certfiles /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem

fabric-ca-client register -d --id.name admin-org1 --id.secret org1AdminPW --id.type admin -u https://0.0.0.0:7052 --tls.certfiles /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem

fabric-ca-client register -d --id.name admin-org2 --id.secret org2AdminPW --id.type admin -u https://0.0.0.0:7052 --tls.certfiles /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem

这里我们为各个节点注册TLS证书,之后Fabric网络的通信则需要通过这一步骤注册过的用户的TLS证书来进行TLS加密通信。
到这里我们只是注册了各个节点的身份,还没有获取到他们的证书。证书可以通过登录获取,不过暂时不着急获取他们的TLS证书。
接下来,我们对其他几个CA服务器进行配置。

3.2配置Org0的CA服务

再强调一下,本文中的几个CA服务器都是根服务器,彼此之间没有任何关系,所以上一步骤的TLS CA服务器在这一部分并没有用到。

同样,本文使用Docker容器启动CA服务器。

mkdir -p /tmp/hyperledger/org0/ca

mkdir -p /tmp/hyperledger/docker-compose/org0/ca && cd /tmp/hyperledger/docker-compose/org0/ca

touch docker-copose.yaml

并在文件内添加以下内容(tips:内容格式不要乱掉):

version: '2'

networks:
  fabric-ca:

services:

  org0:
    container_name: org0
    image: hyperledger/fabric-ca:latest
    command: sh -c 'fabric-ca-server start -d -b org0-admin:org0-adminpw --port 7053'
    environment:
      - FABRIC_CA_SERVER_HOME=/tmp/hyperledger/fabric-ca/crypto
      - FABRIC_CA_SERVER_TLS_ENABLED=true
      - FABRIC_CA_SERVER_CSR_CN=org0
      - FABRIC_CA_SERVER_CSR_HOSTS=0.0.0.0
      - FABRIC_CA_SERVER_PORT=7053
      - FABRIC_CA_SERVER_DEBUG=true
    volumes:
      - /tmp/hyperledger/org0/ca:/tmp/hyperledger/fabric-ca  ##重要!!!记得修改这里的路径为自己的工作目录
    networks:
      - fabric-ca
    ports:
      - 7053:7053

启动容器
docker-compose up -d
注册org0的用户
设置环境变量&登陆

export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org0/ca/crypto/ca-cert.pem

export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org0/ca/admin

fabric-ca-client enroll -d -u https://org0-admin:org0-adminpw@0.0.0.0:7053 --tls.certfiles /tmp/hyperledger/org0/ca/crypto/ca-cert.pem

在本组织中共有两个用户:orderer节点和admin用户(这里的admin和管理员是不同的。)
将他们注册到org0的CA服务器

fabric-ca-client register -d --id.name orderer1-org0 --id.secret ordererpw --id.type orderer -u https://0.0.0.0:7053 --tls.certfiles /tmp/hyperledger/org0/ca/crypto/ca-cert.pem

fabric-ca-client register -d --id.name admin-org0 --id.secret org0adminpw --id.type admin --id.attrs "hf.Registrar.Roles=client,hf.Registrar.Attributes=*,hf.Revoker=true,hf.GenCRL=true,admin=true:ecert,abac.init=true:ecert" -u https://0.0.0.0:7053 --tls.certfiles /tmp/hyperledger/org0/ca/crypto/ca-cert.pem

命令执行完之后,将会注册一个Orderer节点的身份和一个Admin的身份。同时在工作目录下的org0子文件夹中会有两个文件夹:crypto和admin。crypto中是CA服务器的配置信息,admin是服务器管理员的身份信息。

3.3配置Org1的CA服务

mkdir -p /tmp/hyperledger/org1/ca

mkdir -p /tmp/hyperledger/docker-compose/org1/ca && cd /tmp/hyperledger/docker-compose/org1/ca

touch docker-compose.yaml

并在文件内添加以下内容(tips:内容格式不要乱掉):

version: '2'

networks:
  fabric-ca:

services:

  org1:
    container_name: org1
    image: hyperledger/fabric-ca:latest
    command: sh -c 'fabric-ca-server start -d -b org1-admin:org1-adminpw --port 7054'
    environment:
      - FABRIC_CA_SERVER_HOME=/tmp/hyperledger/fabric-ca/crypto
      - FABRIC_CA_SERVER_TLS_ENABLED=true
      - FABRIC_CA_SERVER_CSR_CN=org1
      - FABRIC_CA_SERVER_CSR_HOSTS=0.0.0.0
      - FABRIC_CA_SERVER_PORT=7054
      - FABRIC_CA_SERVER_DEBUG=true
    volumes:
      - /tmp/hyperledger/org1/ca:/tmp/hyperledger/fabric-ca  ##重要!!!记得修改这里的路径为自己的工作目录
    networks:
      - fabric-ca
    ports:
      - 7054:7054

启动容器
docker-compose up -d

注册org1的用户
设置环境变量&登陆

export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org1/ca/crypto/ca-cert.pem

export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org1/ca/admin

fabric-ca-client enroll -d -u https://org1-admin:org1-adminpw@0.0.0.0:7054 --tls.certfiles /tmp/hyperledger/org1/ca/crypto/ca-cert.pem

组织一种共有四个用户:peer1,peer2,admin,user,分别注册他们

fabric-ca-client register -d --id.name peer1-org1 --id.secret peer1PW --id.type peer -u https://0.0.0.0:7054 --tls.certfiles /tmp/hyperledger/org1/ca/crypto/ca-cert.pem

fabric-ca-client register -d --id.name peer2-org1 --id.secret peer2PW --id.type peer -u https://0.0.0.0:7054 --tls.certfiles /tmp/hyperledger/org1/ca/crypto/ca-cert.pem

fabric-ca-client register -d --id.name admin-org1 --id.secret org1AdminPW --id.type admin -u https://0.0.0.0:7054 --tls.certfiles /tmp/hyperledger/org1/ca/crypto/ca-cert.pem

fabric-ca-client register -d --id.name user-org1 --id.secret org1UserPW --id.type client -u https://0.0.0.0:7054 --tls.certfiles /tmp/hyperledger/org1/ca/crypto/ca-cert.pem

3.4配置Org2的CA服务

mkdir -p /tmp/hyperledger/org2/ca

mkdir -p /tmp/hyperledger/docker-compose/org2/ca && cd /tmp/hyperledger/docker-compose/org2/ca

touch docker-compose.yaml

并在文件内添加以下内容(tips:内容格式不要乱掉):

version: '2'

networks:
  fabric-ca:

services:

  org2:
    container_name: org2
    image: hyperledger/fabric-ca:latest
    command: sh -c 'fabric-ca-server start -d -b org2-admin:org2-adminpw --port 7055'
    environment:
      - FABRIC_CA_SERVER_HOME=/tmp/hyperledger/fabric-ca/crypto
      - FABRIC_CA_SERVER_TLS_ENABLED=true
      - FABRIC_CA_SERVER_CSR_CN=org2
      - FABRIC_CA_SERVER_CSR_HOSTS=0.0.0.0
      - FABRIC_CA_SERVER_PORT=7055
      - FABRIC_CA_SERVER_DEBUG=true
    volumes:
      - /tmp/hyperledger/org2/ca:/tmp/hyperledger/fabric-ca  ##重要!!!记得修改这里的路径为自己的工作目录
    networks:
      - fabric-ca
    ports:
      - 7055:7055

启动容器
docker-compose up -d

注册org1的用户
设置环境变量&登陆

export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org2/ca/crypto/ca-cert.pem

export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org2/ca/admin

fabric-ca-client enroll -d -u https://org2-admin:org2-adminpw@0.0.0.0:7055 --tls.certfiles /tmp/hyperledger/org2/ca/crypto/ca-cert.pem

组织一种共有四个用户:peer1,peer2,admin,user,分别注册他们

fabric-ca-client register -d --id.name peer1-org2 --id.secret peer1PW --id.type peer -u https://0.0.0.0:7055 --tls.certfiles /tmp/hyperledger/org2/ca/crypto/ca-cert.pem

fabric-ca-client register -d --id.name peer2-org2 --id.secret peer2PW --id.type peer -u https://0.0.0.0:7055 --tls.certfiles /tmp/hyperledger/org2/ca/crypto/ca-cert.pem

fabric-ca-client register -d --id.name admin-org2 --id.secret org2AdminPW --id.type admin -u https://0.0.0.0:7055 --tls.certfiles /tmp/hyperledger/org2/ca/crypto/ca-cert.pem

fabric-ca-client register -d --id.name user-org2 --id.secret org2UserPW --id.type client -u https://0.0.0.0:7055 --tls.certfiles /tmp/hyperledger/org2/ca/crypto/ca-cert.pem

4、组织一节点配置

4.1 peer1
mkdir -p /tmp/hyperledger/org1/peer1/assets/ca/

cp /tmp/hyperledger/org1/ca/crypto/ca-cert.pem /tmp/hyperledger/org1/peer1/assets/ca/org1-ca-cert.pem

首先是本组织的MSP证书:
配置环境变量

export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org1/peer1
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org1/peer1/assets/ca/org1-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp

登陆peer1节点到org1 CA 服务器上

fabric-ca-client enroll -d -u https://peer1-org1:peer1PW@0.0.0.0:7054 --tls.certfiles /tmp/hyperledger/org1/ca/crypto/ca-cert.pem

这一步完成后在/tmp/hyperledger/org1/peer1下出现一个msp文件夹,这是peer1节点的msp证书。

接下来是TLS证书

mkdir -p /tmp/hyperledger/org1/peer1/assets/tls-ca
cp /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem  /tmp/hyperledger/org1/peer1/assets/tls-ca/tls-ca-cert.pem

配置环境变量

export FABRIC_CA_CLIENT_MSPDIR=tls-msp

export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org1/peer1/assets/tls-ca/tls-ca-cert.pem

登录peer1节点的TLS CA服务器上

fabric-ca-client enroll -d -u https://peer1-org1:peer1PW@0.0.0.0:7052 --enrollment.profile tls --csr.hosts peer1-org1 --tls.certfiles /tmp/hyperledger/org1/peer1/assets/tls-ca/tls-ca-cert.pem

这一步完成后,在/tmp/hyperledger/org1/peer1下会出现一个tls-msp文件夹,这是peer1节点的TLS证书。

修改秘钥文件名
为什么要修改呢,进入这个文件夹看一下就知道了,由服务器生成的秘钥文件名是一长串无规则的字符串,后期我们使用的时候难道要一个字符一个字符地输入?

mv /tmp/hyperledger/org1/peer1/tls-msp/keystore/*_sk /tmp/hyperledger/org1/peer1/tls-msp/keystore/key.pem
4.2 peer2
mkdir -p /tmp/hyperledger/org1/peer2/assets/ca/

cp /tmp/hyperledger/org1/ca/crypto/ca-cert.pem /tmp/hyperledger/org1/peer2/assets/ca/org1-ca-cert.pem

首先是本组织的MSP证书:
配置环境变量

export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org1/peer2
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org1/peer2/assets/ca/org1-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp

登陆peer1节点到org1 CA 服务器上

fabric-ca-client enroll -d -u https://peer2-org1:peer2PW@0.0.0.0:7054 --tls.certfiles /tmp/hyperledger/org1/ca/crypto/ca-cert.pem

这一步完成后在/tmp/hyperledger/org1/peer2下出现一个msp文件夹,这是peer2节点的msp证书。

接下来是TLS证书

mkdir -p /tmp/hyperledger/org1/peer2/assets/tls-ca/
cp /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem  /tmp/hyperledger/org1/peer2/assets/tls-ca/tls-ca-cert.pem

配置环境变量

export FABRIC_CA_CLIENT_MSPDIR=tls-msp
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org1/peer2/assets/tls-ca/tls-ca-cert.pem

登录peer2节点的TLS CA服务器上

fabric-ca-client enroll -d -u https://peer2-org1:peer2PW@0.0.0.0:7052 --enrollment.profile tls --csr.hosts peer2-org1 --tls.certfiles /tmp/hyperledger/org1/peer2/assets/tls-ca/tls-ca-cert.pem

这一步完成后,在/tmp/hyperledger/org1/peer2下会出现一个tls-msp文件夹,这是peer2节点的TLS证书。

修改秘钥文件名
为什么要修改呢,进入这个文件夹看一下就知道了,由服务器生成的秘钥文件名是一长串无规则的字符串,后期我们使用的时候难道要一个字符一个字符地输入?

mv /tmp/hyperledger/org1/peer2/tls-msp/keystore/*_sk /tmp/hyperledger/org1/peer2/tls-msp/keystore/key.pem

4.3 admin

首先是本组织的MSP证书:
配置环境变量

export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org1/admin
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org1/peer1/assets/ca/org1-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp

登录admin节点的org1 CA 服务器上

fabric-ca-client enroll -d -u https://admin-org1:org1AdminPW@0.0.0.0:7054 --tls.certfiles /tmp/hyperledger/org1/peer1/assets/ca/org1-ca-cert.pem

接下来是TLS证书
配置环境变量

export FABRIC_CA_CLIENT_MSPDIR=tls-msp
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org1/peer1/assets/tls-ca/tls-ca-cert.pem

登录peer2节点的TLS CA服务器上

fabric-ca-client enroll -d -u https://admin-org1:org1AdminPW@0.0.0.0:7052 --enrollment.profile tls --csr.hosts admin-org1 --tls.certfiles /tmp/hyperledger/org1/peer1/assets/tls-ca/tls-ca-cert.pem

复制证书到admincerts文件夹:
去看Fabric官方的例子,每一个peer节点的MSP文件夹下都有admincerts这个子文件夹的,而且是需要我们手动创建的。

mkdir /tmp/hyperledger/org1/peer1/msp/admincerts
cp /tmp/hyperledger/org1/admin/msp/signcerts/cert.pem /tmp/hyperledger/org1/peer1/msp/admincerts/org1-admin-cert.pem


mkdir /tmp/hyperledger/org1/peer2/msp/admincerts
cp /tmp/hyperledger/org1/admin/msp/signcerts/cert.pem /tmp/hyperledger/org1/peer2/msp/admincerts/org1-admin-cert.pem

4.4启动peer节点

到这里,已经配置好了一个节点,所以我们就可以启动这个节点了,当然在之后和orderer节点一起启动也可以,不过忙活了这么多,还是应该提前看到一下所做的工作的成果的!
附上peer1节点的容器配置信息:

peer1节点配置启动

mkdir -p /tmp/hyperledger/docker-compose/org1/peer1 && cd /tmp/hyperledger/docker-compose/org1/peer1
touch docker-compose.yaml

并在文件内添加以下内容(tips:内容格式不要乱掉):

version: '2'

networks:
  fabric-ca:

services:
  peer1-org1:
    container_name: peer1-org1
    image: hyperledger/fabric-peer:2.0.0
    environment:
      - CORE_PEER_ID=peer1-org1
      - CORE_PEER_ADDRESS=peer1-org1:7051
      - CORE_PEER_LISTENADDRESS=0.0.0.0:7051
      - CORE_PEER_CHAINCODEADDRESS=peer1-org1:7052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1-org1:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1-org1:7051
      - CORE_PEER_LOCALMSPID=org1MSP
      - CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org1/peer1/msp
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_fabric-ca
      - FABRIC_LOGGING_SPEC=debug
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/tmp/hyperledger/org1/peer1/tls-msp/signcerts/cert.pem
      - CORE_PEER_TLS_KEY_FILE=/tmp/hyperledger/org1/peer1/tls-msp/keystore/key.pem
      - CORE_PEER_TLS_ROOTCERT_FILE=/tmp/hyperledger/org1/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
      - CORE_PEER_GOSSIP_USELEADERELECTION=true
      - CORE_PEER_GOSSIP_ORGLEADER=false
      - CORE_PEER_PROFILE_ENABLED=true
      - CORE_PEER_GOSSIP_SKIPHANDSHAKE=true
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/org1/peer1
    volumes:
      - /var/run:/host/var/run
      - /tmp/hyperledger/org1/peer1:/tmp/hyperledger/org1/peer1
    networks:
      - fabric-ca

启动容器
docker-compose up -d

如果没有报错的话,说明之前配置的没有什么问题,如果出错的话,则需要返回去检查一下了

peer2 节点配置启动

mkdir -p /tmp/hyperledger/docker-compose/org1/peer2 && cd /tmp/hyperledger/docker-compose/org1/peer2
touch docker-compose.yaml

并在文件内添加以下内容(tips:内容格式不要乱掉):

version: '2'

networks:
  fabric-ca:

services:
  peer2-org1:
    container_name: peer2-org1
    image: hyperledger/fabric-peer:2.0.0
    environment:
      - CORE_PEER_ID=peer2-org1
      - CORE_PEER_ADDRESS=peer2-org1:7051
      - CORE_PEER_LISTENADDRESS=0.0.0.0:7051
      - CORE_PEER_CHAINCODEADDRESS=peer2-org1:7052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1-org1:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer2-org1:7051
      - CORE_PEER_LOCALMSPID=org1MSP
      - CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org1/peer2/msp
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_fabric-ca
      - FABRIC_LOGGING_SPEC=debug
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/tmp/hyperledger/org1/peer2/tls-msp/signcerts/cert.pem
      - CORE_PEER_TLS_KEY_FILE=/tmp/hyperledger/org1/peer2/tls-msp/keystore/key.pem
      - CORE_PEER_TLS_ROOTCERT_FILE=/tmp/hyperledger/org1/peer2/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
      - CORE_PEER_GOSSIP_USELEADERELECTION=true
      - CORE_PEER_GOSSIP_ORGLEADER=false
      - CORE_PEER_PROFILE_ENABLED=true
      - CORE_PEER_GOSSIP_SKIPHANDSHAKE=true
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/org1/peer2
    volumes:
      - /var/run:/host/var/run
      - /tmp/hyperledger/org1/peer2:/tmp/hyperledger/org1/peer2
    networks:
      - fabric-ca

启动容器
docker-compose up -d

5、组织二节点配置

和组织一配置一样,这里就不做过多的解释了,直接上命令

5.1 peer1

mkdir -p /tmp/hyperledger/org2/peer1/assets/ca 
cp /tmp/hyperledger/org2/ca/crypto/ca-cert.pem /tmp/hyperledger/org2/peer1/assets/ca/org2-ca-cert.pem

配置环境变量

export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org2/peer1
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org2/peer1/assets/ca/org2-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp

登陆peer1节点到org2 CA服务器上

fabric-ca-client enroll -d -u https://peer1-org2:peer1PW@0.0.0.0:7055 --tls.certfiles /tmp/hyperledger/org2/peer1/assets/ca/org2-ca-cert.pem

接下来是TLS

mkdir /tmp/hyperledger/org2/peer1/assets/tls-ca
cp /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem  /tmp/hyperledger/org2/peer1/assets/tls-ca/tls-ca-cert.pem

配置环境变量

export FABRIC_CA_CLIENT_MSPDIR=tls-msp
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org2/peer1/assets/tls-ca/tls-ca-cert.pem

登录peer1节点到 TLS CA服务器上

fabric-ca-client enroll -d -u https://peer1-org2:peer1PW@0.0.0.0:7052 --enrollment.profile tls --csr.hosts peer1-org2 --tls.certfiles /tmp/hyperledger/org2/peer1/assets/tls-ca/tls-ca-cert.pem

修改密钥文件

mv /tmp/hyperledger/org2/peer1/tls-msp/keystore/*_sk /tmp/hyperledger/org2/peer1/tls-msp/keystore/key.pem

5.2 peer2

mkdir -p /tmp/hyperledger/org2/peer2/assets/ca 
cp /tmp/hyperledger/org2/ca/crypto/ca-cert.pem /tmp/hyperledger/org2/peer2/assets/ca/org2-ca-cert.pem

配置环境变量

export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org2/peer2
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org2/peer2/assets/ca/org2-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp

登陆peer2节点到org2 CA服务器上

fabric-ca-client enroll -d -u https://peer2-org2:peer2PW@0.0.0.0:7055 --tls.certfiles /tmp/hyperledger/org2/peer2/assets/ca/org2-ca-cert.pem

接下来是TLS

mkdir /tmp/hyperledger/org2/peer2/assets/tls-ca
cp /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem  /tmp/hyperledger/org2/peer2/assets/tls-ca/tls-ca-cert.pem

配置环境变量

export FABRIC_CA_CLIENT_MSPDIR=tls-msp
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org2/peer2/assets/tls-ca/tls-ca-cert.pem

登录peer2节点到 TLS CA服务器上

fabric-ca-client enroll -d -u https://peer2-org2:peer2PW@0.0.0.0:7052 --enrollment.profile tls --csr.hosts peer2-org2 --tls.certfiles /tmp/hyperledger/org2/peer2/assets/tls-ca/tls-ca-cert.pem

修改密钥文件

mv /tmp/hyperledger/org2/peer2/tls-msp/keystore/*_sk /tmp/hyperledger/org2/peer2/tls-msp/keystore/key.pem

5.3 admin

配置环境变量

export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org2/admin
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org2/peer1/assets/ca/org2-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp

登陆admin节点到org2 CA服务器上

fabric-ca-client enroll -d -u https://admin-org2:org2AdminPW@0.0.0.0:7055 --tls.certfiles /tmp/hyperledger/org2/peer1/assets/ca/org2-ca-cert.pem

接下来是TLS

配置环境变量

export FABRIC_CA_CLIENT_MSPDIR=tls-msp
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org2/peer1/assets/tls-ca/tls-ca-cert.pem

登录admin节点到 TLS CA服务器上

fabric-ca-client enroll -d -u https://admin-org2:org2AdminPW@0.0.0.0:7052 --enrollment.profile tls --csr.hosts admin-org2 --tls.certfiles /tmp/hyperledger/org2/peer1/assets/tls-ca/tls-ca-cert.pem

5.4 复制证书到admincerts文件夹:

mkdir /tmp/hyperledger/org2/peer1/msp/admincerts
cp /tmp/hyperledger/org2/admin/msp/signcerts/cert.pem /tmp/hyperledger/org2/peer1/msp/admincerts/org2-admin-cert.pem


mkdir /tmp/hyperledger/org2/peer2/msp/admincerts
cp /tmp/hyperledger/org2/admin/msp/signcerts/cert.pem /tmp/hyperledger/org2/peer2/msp/admincerts/org2-admin-cert.pem

5.5 启动peer节点

peer1节点配置

mkdir -p /tmp/hyperledger/docker-compose/org2/peer1 && cd /tmp/hyperledger/docker-compose/org2/peer1
touch docker-compose.yaml

并在文件内添加以下内容(tips:内容格式不要乱掉):

version: '2'

networks:
  fabric-ca:

services:
  peer1-org2:
    container_name: peer1-org2
    image: hyperledger/fabric-peer:2.0.0
    environment:
      - CORE_PEER_ID=peer1-org2
      - CORE_PEER_ADDRESS=peer1-org2:7051
      - CORE_PEER_LISTENADDRESS=0.0.0.0:7051
      - CORE_PEER_CHAINCODEADDRESS=peer1-org2:7052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1-org2:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1-org2:7051
      - CORE_PEER_LOCALMSPID=org2MSP
      - CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org2/peer1/msp
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_fabric-ca
      - FABRIC_LOGGING_SPEC=debug
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/tmp/hyperledger/org2/peer1/tls-msp/signcerts/cert.pem
      - CORE_PEER_TLS_KEY_FILE=/tmp/hyperledger/org2/peer1/tls-msp/keystore/key.pem
      - CORE_PEER_TLS_ROOTCERT_FILE=/tmp/hyperledger/org2/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
      - CORE_PEER_GOSSIP_USELEADERELECTION=true
      - CORE_PEER_GOSSIP_ORGLEADER=false
      - CORE_PEER_PROFILE_ENABLED=true
      - CORE_PEER_GOSSIP_SKIPHANDSHAKE=true
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/org2/peer1
    volumes:
      - /var/run:/host/var/run
      - /tmp/hyperledger/org2/peer1:/tmp/hyperledger/org2/peer1
    networks:
      - fabric-ca

启动容器
docker-compose up -d

peer2节点配置

mkdir -p /tmp/hyperledger/docker-compose/org2/peer2 && cd /tmp/hyperledger/docker-compose/org2/peer2
touch docker-compose.yaml

并在文件内添加以下内容(tips:内容格式不要乱掉):

version: '2'

networks:
  fabric-ca:

services:
  peer2-org2:
    container_name: peer2-org2
    image: hyperledger/fabric-peer:2.0.0
    environment:
      - CORE_PEER_ID=peer2-org2
      - CORE_PEER_ADDRESS=peer2-org2:7051
      - CORE_PEER_LISTENADDRESS=0.0.0.0:7051
      - CORE_PEER_CHAINCODEADDRESS=peer2-org2:7052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1-org2:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer2-org2:7051
      - CORE_PEER_LOCALMSPID=org2MSP
      - CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org2/peer2/msp
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_fabric-ca
      - FABRIC_LOGGING_SPEC=debug
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/tmp/hyperledger/org2/peer2/tls-msp/signcerts/cert.pem
      - CORE_PEER_TLS_KEY_FILE=/tmp/hyperledger/org2/peer2/tls-msp/keystore/key.pem
      - CORE_PEER_TLS_ROOTCERT_FILE=/tmp/hyperledger/org2/peer2/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
      - CORE_PEER_GOSSIP_USELEADERELECTION=true
      - CORE_PEER_GOSSIP_ORGLEADER=false
      - CORE_PEER_GOSSIP_SKIPHANDSHAKE=true
      - CORE_PEER_PROFILE_ENABLED=true
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/org2/peer2
    volumes:
      - /var/run:/host/var/run
      - /tmp/hyperledger/org2/peer2:/tmp/hyperledger/org2/peer2
    networks:
      - fabric-ca

启动容器
docker-compose up -d

6、 排序节点配置

接下来是排序节点的配置,为什么放在最后面呢,因为排序节点的启动需要提前生成创世区块,而创世区块的生成涉及到另一个配置文件,所以就先配置简单的peer节点

6.1 orderer

mkdir -p /tmp/hyperledger/org0/orderer/assets/ca/
cp /tmp/hyperledger/org0/ca/crypto/ca-cert.pem /tmp/hyperledger/org0/orderer/assets/ca/org0-ca-cert.pem

配置环境变量

export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org0/orderer
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org0/orderer/assets/ca/org0-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp

登录order节点到org0 CA服务器上

fabric-ca-client enroll -d -u https://orderer1-org0:ordererpw@0.0.0.0:7053 --tls.certfiles /tmp/hyperledger/org0/orderer/assets/ca/org0-ca-cert.pem

接下来是TLS证书

mkdir /tmp/hyperledger/org0/orderer/assets/tls-ca/
cp /tmp/hyperledger/fabric-ca-tls/crypto/ca-cert.pem  /tmp/hyperledger/org0/orderer/assets/tls-ca/tls-ca-cert.pem

配置环境变量

export FABRIC_CA_CLIENT_MSPDIR=tls-msp
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org0/orderer/assets/tls-ca/tls-ca-cert.pem

登录order节点到TLS CA服务器上

fabric-ca-client enroll -d -u https://orderer1-org0:ordererPW@0.0.0.0:7052 --enrollment.profile tls --csr.hosts orderer1-org0 --tls.certfiles /tmp/hyperledger/org0/orderer/assets/tls-ca/tls-ca-cert.pem

修改密钥

mv /tmp/hyperledger/org0/orderer/tls-msp/keystore/*_sk /tmp/hyperledger/org0/orderer/tls-msp/keystore/key.pem

6.2 admin

配置环境变量

export FABRIC_CA_CLIENT_HOME=/tmp/hyperledger/org0/admin
export FABRIC_CA_CLIENT_TLS_CERTFILES=/tmp/hyperledger/org0/orderer/assets/ca/org0-ca-cert.pem
export FABRIC_CA_CLIENT_MSPDIR=msp

登录admin 用户获取msp

fabric-ca-client enroll -d -u https://admin-org0:org0adminpw@0.0.0.0:7053 --tls.certfiles /tmp/hyperledger/org0/orderer/assets/ca/org0-ca-cert.pem

复制证书到admincerts文件夹:

mkdir /tmp/hyperledger/org0/orderer/msp/admincerts
cp /tmp/hyperledger/org0/admin/msp/signcerts/cert.pem /tmp/hyperledger/org0/orderer/msp/admincerts/orderer-admin-cert.pem

证书都准备好了之后我们还需要在每个msp文件下添加一个config.yaml

NodeOUs:
  Enable: true
  ClientOUIdentifier:
    #修改对应的证书名称
    Certificate: cacerts/0-0-0-0-7053.pem
    OrganizationalUnitIdentifier: client
  PeerOUIdentifier:
    Certificate: cacerts/0-0-0-0-7053.pem
    OrganizationalUnitIdentifier: peer
  AdminOUIdentifier:
    Certificate: cacerts/0-0-0-0-7053.pem
    OrganizationalUnitIdentifier: admin
  OrdererOUIdentifier:
    Certificate: cacerts/0-0-0-0-7053.pem
    OrganizationalUnitIdentifier: orderer

需要org0,org1, org2 下所有msp目录下都添加。

7、Fabric 网络

证书都生成好了,即将要启动网络了。不过在启动网络之前还是有很多准备工作需要做。

7.1 整理MSPDir文件

---------------org0--------------------
mkdir -p /tmp/hyperledger/configtx && cd /tmp/hyperledger/configtx

mkdir org0

cp -r ../org0/admin/msp org0/

cd  org0/msp

mkdir tlscacerts && cd tlscacerts

cp  /tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem ./

--------------------------------------
---------------org1--------------------
cd /tmp/hyperledger/configtx
mkdir org1 

cp -r ../org1/admin/msp org1/

cd org1/msp
mkdir tlscacerts && cd tlscacerts

cp /tmp/hyperledger/org1/admin/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem ./

--------------------------------------
---------------org2--------------------
cd /tmp/hyperledger/configtx
mkdir org2 

cp -r ../org2/admin/msp org2/

cd org2/msp
mkdir tlscacerts && cd tlscacerts

cp /tmp/hyperledger/org2/admin/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem ./

--------------------------------------

7.2 configtx.yaml文件配置

在下一个步骤的生成创世区块和通道配置信息需要一个文件:configtx.yaml文件。

cd /tmp/hyperledger/configtx
touch configtx.yaml

文件内容

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

---
################################################################################
#
#   Section: Organizations
#
#   - This section defines the different organizational identities which will
#   be referenced later in the configuration.
#
################################################################################
Organizations:

    # SampleOrg defines an MSP using the sampleconfig.  It should never be used
    # in production but may be used as a template for other definitions
    - &org0
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: org0MSP

        # ID to load the MSP definition as
        ID: org0MSP

        # MSPDir is the filesystem path which contains the MSP configuration
        MSPDir: ../configtx/org0/msp

        # Policies defines the set of policies at this level of the config tree
        # For organization policies, their canonical path is usually
        #   /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('org0MSP.member')"
            Writers:
                Type: Signature
                Rule: "OR('org0MSP.member')"
            Admins:
                Type: Signature
                Rule: "OR('org0MSP.admin')"

        OrdererEndpoints:
            - orderer1-org0:7050

    - &org1
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: org1MSP

        # ID to load the MSP definition as
        ID: org1MSP

        MSPDir: ../configtx/org1/msp

        # Policies defines the set of policies at this level of the config tree
        # For organization policies, their canonical path is usually
        #   /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('org1MSP.admin', 'org1MSP.peer', 'org1MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('org1MSP.admin', 'org1MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('org1MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('org1MSP.peer')"

        # leave this flag set to true.
        AnchorPeers:
            # AnchorPeers defines the location of peers which can be used
            # for cross org gossip communication.  Note, this value is only
            # encoded in the genesis block in the Application section context
            - Host: peer1-org1
              Port: 7051

    - &org2
        # DefaultOrg defines the organization which is used in the sampleconfig
        # of the fabric.git development environment
        Name: org2MSP

        # ID to load the MSP definition as
        ID: org2MSP

        MSPDir: ../configtx/org2/msp

        # Policies defines the set of policies at this level of the config tree
        # For organization policies, their canonical path is usually
        #   /Channel/<Application|Orderer>/<OrgName>/<PolicyName>
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('org2MSP.admin', 'org2MSP.peer', 'org2MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('org2MSP.admin', 'org2MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('org2MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('org2MSP.peer')"

        AnchorPeers:
            # AnchorPeers defines the location of peers which can be used
            # for cross org gossip communication.  Note, this value is only
            # encoded in the genesis block in the Application section context
            - Host: peer1-org2
              Port: 7051

################################################################################
#
#   SECTION: Capabilities
#
#   - This section defines the capabilities of fabric network. This is a new
#   concept as of v1.1.0 and should not be utilized in mixed networks with
#   v1.0.x peers and orderers.  Capabilities define features which must be
#   present in a fabric binary for that binary to safely participate in the
#   fabric network.  For instance, if a new MSP type is added, newer binaries
#   might recognize and validate the signatures from this type, while older
#   binaries without this support would be unable to validate those
#   transactions.  This could lead to different versions of the fabric binaries
#   having different world states.  Instead, defining a capability for a channel
#   informs those binaries without this capability that they must cease
#   processing transactions until they have been upgraded.  For v1.0.x if any
#   capabilities are defined (including a map with all capabilities turned off)
#   then the v1.0.x peer will deliberately crash.
#
################################################################################
Capabilities:
    # Channel capabilities apply to both the orderers and the peers and must be
    # supported by both.
    # Set the value of the capability to true to require it.
    Channel: &ChannelCapabilities
        # V2_0 capability ensures that orderers and peers behave according
        # to v2.0 channel capabilities. Orderers and peers from
        # prior releases would behave in an incompatible way, and are therefore
        # not able to participate in channels at v2.0 capability.
        # Prior to enabling V2.0 channel capabilities, ensure that all
        # orderers and peers on a channel are at v2.0.0 or later.
        V2_0: true

    # Orderer capabilities apply only to the orderers, and may be safely
    # used with prior release peers.
    # Set the value of the capability to true to require it.
    Orderer: &OrdererCapabilities
        # V2_0 orderer capability ensures that orderers behave according
        # to v2.0 orderer capabilities. Orderers from
        # prior releases would behave in an incompatible way, and are therefore
        # not able to participate in channels at v2.0 orderer capability.
        # Prior to enabling V2.0 orderer capabilities, ensure that all
        # orderers on channel are at v2.0.0 or later.
        V2_0: true

    # Application capabilities apply only to the peer network, and may be safely
    # used with prior release orderers.
    # Set the value of the capability to true to require it.
    Application: &ApplicationCapabilities
        # V2_0 application capability ensures that peers behave according
        # to v2.0 application capabilities. Peers from
        # prior releases would behave in an incompatible way, and are therefore
        # not able to participate in channels at v2.0 application capability.
        # Prior to enabling V2.0 application capabilities, ensure that all
        # peers on channel are at v2.0.0 or later.
        V2_0: true

################################################################################
#
#   SECTION: Application
#
#   - This section defines the values to encode into a config transaction or
#   genesis block for application related parameters
#
################################################################################
Application: &ApplicationDefaults

    # Organizations is the list of orgs which are defined as participants on
    # the application side of the network
    Organizations:

    # Policies defines the set of policies at this level of the config tree
    # For Application policies, their canonical path is
    #   /Channel/Application/<PolicyName>
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        LifecycleEndorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"
        Endorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"

    Capabilities:
        <<: *ApplicationCapabilities
################################################################################
#
#   SECTION: Orderer
#
#   - This section defines the values to encode into a config transaction or
#   genesis block for orderer related parameters
#
################################################################################
Orderer: &OrdererDefaults

    # Orderer Type: The orderer implementation to start
    OrdererType: etcdraft

    EtcdRaft:
        Consenters:
        - Host: orderer1-org0
          Port: 7050
          ClientTLSCert: /tmp/hyperledger/org0/orderer/tls-msp/signcerts/cert.pem
          ServerTLSCert: /tmp/hyperledger/org0/orderer/tls-msp/signcerts/cert.pem

    # Batch Timeout: The amount of time to wait before creating a batch
    BatchTimeout: 2s

    # Batch Size: Controls the number of messages batched into a block
    BatchSize:

        # Max Message Count: The maximum number of messages to permit in a batch
        MaxMessageCount: 10

        # Absolute Max Bytes: The absolute maximum number of bytes allowed for
        # the serialized messages in a batch.
        AbsoluteMaxBytes: 99 MB

        # Preferred Max Bytes: The preferred maximum number of bytes allowed for
        # the serialized messages in a batch. A message larger than the preferred
        # max bytes will result in a batch larger than preferred max bytes.
        PreferredMaxBytes: 512 KB

    # Organizations is the list of orgs which are defined as participants on
    # the orderer side of the network
    Organizations:

    # Policies defines the set of policies at this level of the config tree
    # For Orderer policies, their canonical path is
    #   /Channel/Orderer/<PolicyName>
    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        # BlockValidation specifies what signatures must be included in the block
        # from the orderer for the peer to validate it.
        BlockValidation:
            Type: ImplicitMeta
            Rule: "ANY Writers"

################################################################################
#
#   CHANNEL
#
#   This section defines the values to encode into a config transaction or
#   genesis block for channel related parameters.
#
################################################################################
Channel: &ChannelDefaults
    # Policies defines the set of policies at this level of the config tree
    # For Channel policies, their canonical path is
    #   /Channel/<PolicyName>
    Policies:
        # Who may invoke the 'Deliver' API
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        # Who may invoke the 'Broadcast' API
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        # By default, who may modify elements at this config level
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"

    # Capabilities describes the channel level capabilities, see the
    # dedicated Capabilities section elsewhere in this file for a full
    # description
    Capabilities:
        <<: *ChannelCapabilities

################################################################################
#
#   Profile
#
#   - Different configuration profiles may be encoded here to be specified
#   as parameters to the configtxgen tool
#
################################################################################
Profiles:

    TwoOrgsOrdererGenesis:
        <<: *ChannelDefaults
        Orderer:
            <<: *OrdererDefaults
            Organizations:
                - *org0
            Capabilities:
                <<: *OrdererCapabilities
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *org1
                    - *org2
    TwoOrgsChannel:
        Consortium: SampleConsortium
        <<: *ChannelDefaults
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *org1
                - *org2
            Capabilities:
                <<: *ApplicationCapabilities
注:根据情况修改MSP的路径

7.3 生成创世区块和通道信息

cd /tmp/hyperledger/configtx
mkdir system-genesis-block 
mkdir channel-artifacts

生成创世区块文件
configtxgen -profile TwoOrgsOrdererGenesis -channelID system-channel -outputBlock ./system-genesis-block/genesis.block

生成通道
export CHANNEL_NAME=mychannel
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/${CHANNEL_NAME}.tx -channelID ${CHANNEL_NAME}

锚节点更新配置
export orgmsp=org1MSP
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/${orgmsp}anchors.tx -channelID ${CHANNEL_NAME} -asOrg ${orgmsp}

锚节点更新配置
export orgmsp=org2MSP
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/${orgmsp}anchors.tx -channelID ${CHANNEL_NAME} -asOrg ${orgmsp}

创世区块文件通&道信息生成后启动orderer节

mkdir -p /tmp/hyperledger/docker-compose/org0/orderer cd /tmp/hyperledger/docker-compose/org0/orderer
touch docker-compose.yaml

并在文件内添加以下内容(tips:内容格式不要乱掉):

version: '2'

networks:
  fabric-ca:
services:
  orderer1-org0:
    container_name: orderer1-org0
    image: hyperledger/fabric-orderer:2.0.0
    environment:
      - ORDERER_HOME=/tmp/hyperledger/orderer
      - ORDERER_HOST=orderer1-org0
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_LISTENPORT=7050
      - ORDERER_GENERAL_GENESISMETHOD=file
      - ORDERER_GENERAL_GENESISFILE=/tmp/hyperledger/orderer/orderer.genesis.block
      - ORDERER_GENERAL_LOCALMSPID=org0MSP
      - ORDERER_GENERAL_LOCALMSPDIR=/tmp/hyperledger/org0/orderer/msp
      - ORDERER_GENERAL_TLS_ENABLED=true

      - ORDERER_GENERAL_TLS_PRIVATEKEY=/tmp/hyperledger/org0/orderer/tls-msp/keystore/key.pem
      - ORDERER_GENERAL_TLS_CERTIFICATE=/tmp/hyperledger/org0/orderer/tls-msp/signcerts/cert.pem
      - ORDERER_GENERAL_TLS_ROOTCAS=[/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem]

      - ORDERER_KAFKA_TOPIC_REPLICATIONFACTOR=1
      - ORDERER_KAFKA_VERBOSE=true
      - ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/tmp/hyperledger/org0/orderer/tls-msp/signcerts/cert.pem
      - ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/tmp/hyperledger/org0/orderer/tls-msp/keystore/key.pem
      - ORDERER_GENERAL_CLUSTER_ROOTCAS=[/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem]

      - ORDERER_GENERAL_LOGLEVEL=debug
      - ORDERER_DEBUG_BROADCASTTRACEDIR=data/logs
    volumes:
      - /tmp/hyperledger/org0/orderer:/tmp/hyperledger/org0/orderer/
      - /tmp/hyperledger/configtx/system-genesis-block/genesis.block:/tmp/hyperledger/orderer/orderer.genesis.block

    networks:
      - fabric-ca

启动容器
docker-compose up -d

启动组织一的cli

cli容器内容,我们需要这个容器对组织1进行链码的交互

mkdir -p /tmp/hyperledger/docker-compose/org1/cli
touch docker-compose.yaml

并在文件内添加以下内容(tips:内容格式不要乱掉):

version: '2'

networks:
  fabric-ca:
services:
    cli-org1:
      container_name: cli-org1
      image: hyperledger/fabric-tools:2.0.0
      tty: true
      stdin_open: true
      environment:
        - SYS_CHANNEL=testchainid
        - GOPATH=/opt/gopath
        - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
        - FABRIC_LOGGING_SPEC=DEBUG
        - CORE_PEER_ID=cli-org1
        - CORE_PEER_ADDRESS=peer1-org1:7051
        - CORE_PEER_LOCALMSPID=org1MSP
        - CORE_PEER_TLS_ENABLED=true
        - CORE_PEER_TLS_ROOTCERT_FILE=/tmp/hyperledger/org1/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
        - CORE_PEER_TLS_CERT_FILE=/tmp/hyperledger/org1/peer1/tls-msp/signcerts/cert.pem
        - CORE_PEER_TLS_KEY_FILE=/tmp/hyperledger/org1/peer1/tls-msp/keystore/key.pem
        - CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org1/peer1/msp
      working_dir: /opt/gopath/src/github.com/hyperledger/fabric/org1
      command: /bin/bash
      volumes:
        - /tmp/hyperledger/org1:/tmp/hyperledger/org1/
        - /tmp/hyperledger/org2:/tmp/hyperledger/org2/
        - /tmp/hyperledger/org1/peer1/assets/chaincode:/opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode
        - /tmp/hyperledger/org1/admin:/tmp/hyperledger/org1/admin
        - /tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem:/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
        - /tmp/hyperledger/org1/peer1/tls-msp/tlscacerts:/tmp/hyperledger/org1/admin/msp/tlscacerts
        - /tmp/hyperledger/configtx/channel-artifacts:/tmp/hyperledger/configtx/channel-artifacts
      networks:
        - fabric-ca

启动组织二的cli

cli容器内容,我们需要这个容器对组织1进行链码的交互

mkdir -p /tmp/hyperledger/docker-compose/org2/cli
touch docker-compose.yaml

并在文件内添加以下内容(tips:内容格式不要乱掉):

version: '2'

networks:
  fabric-ca:
services:
    cli-org2:
      container_name: cli-org2
      image: hyperledger/fabric-tools:2.0.0
      tty: true
      stdin_open: true
      environment:
        - SYS_CHANNEL=testchainid
        - GOPATH=/opt/gopath
        - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
        - FABRIC_LOGGING_SPEC=DEBUG
        - CORE_PEER_ID=cli-org2
        - CORE_PEER_ADDRESS=peer1-org2:7051
        - CORE_PEER_LOCALMSPID=org2MSP
        - CORE_PEER_TLS_ENABLED=true
        - CORE_PEER_TLS_ROOTCERT_FILE=/tmp/hyperledger/org2/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
        - CORE_PEER_TLS_CERT_FILE=/tmp/hyperledger/org2/peer1/tls-msp/signcerts/cert.pem
        - CORE_PEER_TLS_KEY_FILE=/tmp/hyperledger/org2/peer1/tls-msp/keystore/key.pem
        - CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org2/peer1/msp
      working_dir: /opt/gopath/src/github.com/hyperledger/fabric/org2
      command: /bin/bash
      volumes:
        - /tmp/hyperledger/org1:/tmp/hyperledger/org1/
        - /tmp/hyperledger/org2:/tmp/hyperledger/org2/
        - /tmp/hyperledger/org2/peer1:/tmp/hyperledger/org2/peer1
        - /tmp/hyperledger/org2/peer1/assets/chaincode:/opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode
        - /tmp/hyperledger/org2/admin:/tmp/hyperledger/org2/admin
        - /tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem:/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
        - /tmp/hyperledger/org2/peer1/tls-msp/tlscacerts:/tmp/hyperledger/org2/peer1/msp/tlscacerts
        - /tmp/hyperledger/configtx/channel-artifacts:/tmp/hyperledger/configtx/channel-artifacts
      networks:
        - fabric-ca

8、创建&加入通道

-----------------------------cli-org1-------------------------------

docker exec -it cli-org1 bash

export CHANNEL_NAME=mychannel
export ORDERER_CA=/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
export CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org1/admin/msp

cd /tmp/hyperledger/configtx

peer channel create -o orderer1-org0:7050 -c ${CHANNEL_NAME} --ordererTLSHostnameOverride orderer1-org0 -f ./channel-artifacts/${CHANNEL_NAME}.tx --outputBlock ./channel-artifacts/${CHANNEL_NAME}.block --tls --cafile ${ORDERER_CA}


export CORE_PEER_ADDRESS=peer1-org1:7051
peer channel join -b ./channel-artifacts/mychannel.block

export CORE_PEER_ADDRESS=peer2-org1:7051
peer channel join -b ./channel-artifacts/mychannel.block


export CORE_PEER_LOCALMSPID=org1MSP
peer channel update -o orderer1-org0:7050 --ordererTLSHostnameOverride orderer1-org0 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx --tls --cafile $ORDERER_CA

-----------------------------cli-org1-end-------------------------------

-----------------------------cli-org2------------------------------------
docker exec -it cli-org2 bash

export CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org2/admin/msp

export CORE_PEER_ADDRESS=peer1-org2:7051
peer channel join -b ./channel-artifacts/mychannel.block

 export CORE_PEER_ADDRESS=peer2-org2:7051
 peer channel join -b ./channel-artifacts/mychannel.block

cd /tmp/hyperledger/configtx

export CHANNEL_NAME=mychannel
export ORDERER_CA=/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
export CORE_PEER_LOCALMSPID=org2MSP

peer channel update -o orderer1-org0:7050 --ordererTLSHostnameOverride orderer1-org0 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx --tls --cafile $ORDERER_CA

-----------------------------cli-org2-end-------------------------------

9 链码安装测试

链码安装

installChaincode
-----------------------------------------------
docker exec -it cli-org1 bash
cd /tmp/hyperledger/org1/peer1/assets/chaincode
export CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org1/admin/msp

peer lifecycle chaincode install fabcar.tar.gz


export CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org2/admin/msp
peer lifecycle chaincode install fabcar.tar.gz

cli-org2 的安装基本相同,自行登录cli-org2容器中安装


-----------------------------------------------

链码查询

queryInstalled()
-----------------------------------------------
peer lifecycle chaincode queryinstalled

packageid: fabcar_1:469a86090d7e3b537d6495abaae326fc5909d45692e4b19d43348a76e5fe4eb0


-----------------------------------------------

组织授权校验

docker exec -it cli-org1 bash

export VERSION=1
export PACKAGE_ID=fabcar_1:469a86090d7e3b537d6495abaae326fc5909d45692e4b19d43348a76e5fe4eb0
export ORDERER_CA=/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
export CHANNEL_NAME=mychannel

peer lifecycle chaincode approveformyorg -o orderer1-org0:7050 --ordererTLSHostnameOverride orderer1-org0 --tls --cafile ${ORDERER_CA} --channelID ${CHANNEL_NAME} --name fabcar --version ${VERSION} --init-required --package-id ${PACKAGE_ID} --sequence ${VERSION}

peer lifecycle chaincode checkcommitreadiness --channelID $CHANNEL_NAME --name fabcar --version ${VERSION} --sequence ${VERSION} --output json --init-required


同理cli-org2授权基本相同

提交链码定义

docker exec -it cli-org1 bash
export CHANNEL_NAME=mychannel
export VERSION=1
export ORDERER_CA=/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
export CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org1/admin/msp


peer lifecycle chaincode commit -o orderer1-org0:7050 --ordererTLSHostnameOverride orderer1-org0 --tls --cafile $ORDERER_CA --channelID $CHANNEL_NAME --name fabcar --peerAddresses peer1-org1:7051 --tlsRootCertFiles /tmp/hyperledger/org1/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem  --peerAddresses peer1-org2:7051 --tlsRootCertFiles /tmp/hyperledger/org2/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem --version ${VERSION} --sequence ${VERSION} --init-required


-----------------------------------cli-org2----------------------------------------
docker exec -it cli-org2 bash

export CHANNEL_NAME=mychannel
export VERSION=1
export ORDERER_CA=/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
export CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org2/admin/msp


peer lifecycle chaincode commit -o orderer1-org0:7050 --ordererTLSHostnameOverride orderer1-org0 --tls --cafile $ORDERER_CA --channelID $CHANNEL_NAME --name fabcar --peerAddresses peer1-org1:7051 --tlsRootCertFiles /tmp/hyperledger/org1/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem  --peerAddresses peer1-org2:7051 --tlsRootCertFiles /tmp/hyperledger/org2/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem --version ${VERSION} --sequence ${VERSION} --init-required

查询提交内容

export CHANNEL_NAME=mychannel
peer lifecycle chaincode querycommitted --channelID $CHANNEL_NAME --name fabcar

初始化链码

export CHANNEL_NAME=mychannel
export VERSION=1
export ORDERER_CA=/tmp/hyperledger/org0/orderer/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem
export CORE_PEER_MSPCONFIGPATH=/tmp/hyperledger/org1/admin/msp

peer chaincode invoke -o orderer1-org0:7050 --ordererTLSHostnameOverride orderer1-org0 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n fabcar --peerAddresses peer1-org1:7051 --tlsRootCertFiles /tmp/hyperledger/org1/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem  --peerAddresses peer1-org2:7051 --tlsRootCertFiles /tmp/hyperledger/org2/peer1/tls-msp/tlscacerts/tls-0-0-0-0-7052.pem --isInit -c '{"function":"initLedger","Args":[]}'

查询

peer chaincode query -C $CHANNEL_NAME -n fabcar -c '{"Args":["queryAllCars"]}'
查看原文

赞 0 收藏 0 评论 0

阅历笔记 发布了文章 · 2020-07-07

Redis的过期策略有哪些?

我们一般都用内存作为缓存,但是内存是无限的吗?当然不是,内存是很宝贵且有限的自然。

可能一台机器也就十几G的内存,但是却可以挂几个T,十几个T的硬盘空间,Reids主要是基于内存做高性能,高并发的读写操作的。

那么问题来了?既然内存时有限的,比如Redis就只给分配了10G的内存,你却要往里硬怼20G的数据,会咋办?毫无疑问,当然会被干掉10G的数据了,那问题又来了,干掉那些数据?保留那些数据?我们当然希望干掉那些不常用的,保留常用的数据了。

所以说,这是缓存的一种基本概念,数据是会过期的,要么你自己设置过期时间,要么在满足某些条件下Redis帮你干掉。

如果自己设置了过期时间,那你知道Redis是怎么给你弄过期的吗?什么时候被删除的?

比如我们在set key时可以给定一个expire time就是过期时间,比如指定这个key的过期时间为1小时?10分钟? 这个很有用的,我们自己控制缓存的存活时间。

假如你设置了一批key只能存活1小时,那么一小时后,Redis是如何对这一批key进行删除的尼?请往下看!

定期删除+惰性删除

所谓定期删除指的是Redis默认会每隔一定时间(默认100ms)就会抽取一批设置了过期时间的key来检测是否过期,过期就删除。假设你Redis存放了100万key都设置了过期时间,你每隔几百毫秒,就检查100万key,那Reids基本就挂了, cup负载会飙升,都消耗在你检测过期key上了。
注意⚠️!这里可不是每隔100ms就遍历所有的设置了过期的key,那样将是一场性能上的灾难。实际上Redis是每隔100ms随机的抽取一部分设置过期时间的key来检测和删除。

但是问题来了?? 定期删除可能会导致一部分过期了的key时间到了却并没有被删除,怎么办?别着急,这就该我们的惰性删除登场了。

惰性删除,就是你在获取某个Key时Redis会先检测一下,这个key是否设置了过期时间?如果设置了过期时间那么是否过期?过期就删除。

通过上述两种手段基本上可以保证过期的key一定会被干掉。

但是实际问题比这复杂多了,比喻定期删除漏掉了很多过期的key,然后也没及时的去查也就没有走惰性删除,此时会怎么样?大批的过期key躺在内存了,导致Redis内存很快别被耗尽,咋办?咋办?咋办?

别急! 这种情况会走内存淘汰机制

内存淘汰

如果Redis的内存占用过多的时候,此时Redis会进行内存淘汰,如何淘汰?会有如下几种淘汰策略。

  • noeviction: 当内存不足以容纳新写入的数据时,新写入数据时会报错。这个一般不会有人使用,感觉太🤢人了。
  • allkeys-lru:当内存不足以容纳新写入的数据时,在键空间中,移除最近最少使用的key.(这也是我们经常使用的策略)
  • allkes-random:当内存不足以容纳新写入的数据时,在键空间中,随机移除某个key。(这个正常人都不会使用吧,为啥要随机?肯定移除最近最少使用的key呀)
  • volatile-lru:当内存不足以容纳新写入的数据时,在设置了过期时间的键空间中,移除最近最少使用的key。(这个一般也不太合适)
  • volatile-random:当内存不足以容纳新写入的数据时,在设置了过期时间的键空间中,随机移除某个key。
  • volatile-ttl:当内存不足以容纳新写入的数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。(这个也不合理)

到这Redis的过期策略基本介绍完了。也就三把 🔪 🔪 🔪

🔪定期删除+🔪惰性删除+🔪内存淘汰(最常用的allkeys-lru)

查看原文

赞 0 收藏 0 评论 0

阅历笔记 发布了文章 · 2020-06-29

聊聊Redis和Memcached有啥区别?

要说redis和memcached有啥区别这事吧?说起来就比较多,随着redis的功能越来越完善和强大,现在使用memcached的公司基本没有了,这里我们就来聊聊redis作者给出的几点区别吧。

1、redis支持服务端的数据操作

redis相比memcached来说,拥有更多的数据结构并且支持丰富的数据操作。
通常在memcached里,你需要将数据拿到客户端来进行类似的修改在set回去。这就大大增加网络IO的次数和数据的体积。
在redis中,这些复杂的操作通常和一般的GET/SET一样高效。
所以如果需要缓存能够支持更复杂的结构和操作,那么redis会是一个不错的选择。

2、内存使用率对比

使用简单的key-value存储的话,memcached的内存使用率更高,而如果redis采用hash结构来做key-value存储的,由于某组合式的压缩,其内存使用率会高于memcached。

3、性能对比

由于redis只使用单核,而memcached可以使用多核,所以平均每个核上redis在存储小数据时性能上比memcached性能高,而在100k以上的数据中memcached的性能高。虽然redis也在存储大数据的性能上进行优化,但是比起memcached来说还是稍逊一筹。

4、集群模式

memcached没有原生的集群模式,需要依赖客户端来实现往集群中分片写入数据,而redis原生就支持claster模式的。

基本就这四点了,其实我觉得主要也就1、4比较重要点,其它的也就不是那么重要。

而且现在确实memcached慢慢淡出了人们的视野。

查看原文

赞 0 收藏 0 评论 0

阅历笔记 发布了文章 · 2020-06-24

如何保证消息队列(RabbitMQ)的高可用?

随着我们业务越来越复杂、系统中引入消息队列是必不可少的,引入消息队列的优缺点我就不在着多说了,今天来聊聊如何保证你引入的消息队列的高可用性。在这我们以RabbitMQ来简单分析下。

1、RabbitMQ的高可用

RabbitMQ是一个比较有代表性的消息中间件,因为是基于主从做的高可用架构、我们就以它为例子来聊下其高可用是如何实现的。

RabbitMQ有三种模式:单机模式、普通集群模式、镜像集群模式。

1.1 单机模式

单机模式就是处于一种demo模式、一般就是自己本地搞一个玩玩,生产环境没有那个哥们会使用单机模式的。

1.2 普通集群模式

RabbitMQ普通集群.jpg
如上图是普通集群模式
1、RabbitMQ在多台服务器启动实例、每台服务器一个实例、当你创建queue时、queue(元数据+具体数据)只会落在一台RabbitMQ实例上、但是集群中每个实例都会同步queue的元数据(元数据:真实数据的描述如具体位置等)。
2、当用户消费时如果连接的是另外一个实例,当前实例会根据同步的元数据找到具体的数据所在的实例从其上把具体数据拉过来消费。

这种方式的缺点很明显,没有做到所谓的分布式、只是一个普通的集群。这种方式在消费数据时要么随机选择一个实例拉去数据、要么固定连接那个queue所在的实例来拉取数据,前者导致一次实例见拉取数据的开销、而后在会导致单实例性能的瓶颈。

而且如果存放数据的queue的实例宕机了、会导致其它实例无法从该实例来拉取数据了,如果你开启了RabbitMQ的持久化功能,消息不一定会丢失,但是得等待这个实例重启后才能继续从该queue拉取数据。

所以总的来说这事就比较尴尬了,就完全没有所谓的高可用一说了,这个方案主要的目的是提高吞吐量的,就是说让集群中的多个节点来服务某个queue的读写操作。

1.3镜像集群模式

RabbitMQ镜像集群.jpg

这种集群模式真正达到了RabbitMQ高可用性,和普通集群不一样的是你创建的queue不管是元数据还是里面的具体消息都会存在于所有的实例上。每次写消息时都会把消息同步到每个节点的queue中去。

这种方式的优点在于,你任何一个节点宕机了、都没事儿,别的节点都还可以正常使用。

缺点:
1、性能开销太大,消息同步到所有的节点服务器会导致网络带宽压力和消耗很严重。
2、这种模式没有扩展性可言,如果你某个queue的负载很高,你加机器,新增的机器也包含了这个queue的所有数据,并没有办法线性扩展你的queue.

这里在多说下如何开启镜像集群模式?其实开启很简单在RabbitMQ的管理控制台,新增一条策略、这个策略就是开启开启镜像集群模式策略、指定的时候可以指定数据同步到所有的节点,也可以要求同步到指定的节点数量,之后你在创建queue时使用这个策略、就会在动降数据同步到其它节点上去了。
RabbitMQ开启镜像集群.jpg

查看原文

赞 2 收藏 2 评论 0

阅历笔记 发布了文章 · 2020-06-22

如何对消息中间件进行选型?

这里选择业界比较流行几种消息中间件、ActiveMQ、RabbitMQ、RocketMQ、Kafka等比较有名气的中间件,还有些比较偏门的MQ不在今天的讨论的范围内。

下面对以上几种MQ从几个不同维度来做下总结和对比,希望看完后对你们公司在引入MQ时可以帮助你们做技术选型。

特性ActiveMQRabbitMQRocketMQKafka
单机吞吐量万级,吞吐量要比RocketMQ和Kafka低一个量级万级,吞吐量要比RocketMQ和Kafka低一个量级10万级,是可以支撑高吞吐量的一种MQ10万级,Kafka最大的优点就是吞吐量高。一般配合大数据类系统来进行实时计算,日志采集等场景来使用
topic数量对吞吐量的影响topic可以达到几百,几千的级别,吞吐量会有较小幅度的下降,这也是RocketMQ的一大优势topic从几十到达几百时,吞吐量会大幅度下降,所以在同等机器下,kafka尽量保证topic的数量不要过多
时效性ms级别微秒级别,这是RabbitMQ的一大特点,延迟是最低的ms级别延迟在ms级别以内
可用性高,基于主从架构实现高可用高,基于主从架构实现高可用非常高,分布式架构非常高,kafka是分布式的,一个数据多个副本,少数机器宕机不会数据丢失,不会导致不可用
消息可靠性有较低的概率丢失数据经过参数优化陪配置可以做到0丢失经过参数优化配置,可以达到0丢失
核心特点MQ领域的功能及其完备基于erlang开发,所以并发性能及其突出,性能好,延迟低MQ功能基本完善,分布式的扩展性良好功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模的使用,是实时上的标准
功能支持MQ领域的功能及其完备基于erlang开发,所以并发性能及其突出,性能好,延迟地MQ功能基本完善,分布式的扩展性良好功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模的使用,是实时上的标准
优劣势总结非常成熟,功能强大,在业内大量的公司以及项目中都有应用, 偶尔会有低概率的消息丢失,现在社区以及国内公司使用的越来越少,官方现在对ACtiveMQ 高版本维护越来越少,主要是基于解耦和异步来使用,较少在大规模吞吐的场景使用erlang语言开发,性能极好,延迟低而且开源提供管理界面非常棒,用起来非常方便,国内一些互联网公司最近几年使用RabbitMQ的比较多。但是问题也是显而易见的,RabbitMQ确实会吞吐量低一些,这是因为其实现机制比较重,而且erlang开发,国内有几个有实力的公司做erlang源码级别的研究和定制??而且RabbitMQ集群动态扩展比较麻烦,不过这个问题不是太大。 其只要是erlang语言本身带来的问题,很难读源码,定制开发,掌控力度不大接口简单易用,在阿里经过大规模使用,有阿里的品牌保证。日处理消息上百亿之多,可以做到大规模吞吐,性能非常优秀,分布式扩展也很方便,社区维护还可以,可靠性和可用性都是没得说,还可以支撑大规模topic数量,支持复杂的MQ业务场景,而且一个很大的优势在于,阿里出品都是Java系列,我们可以自己读源码,定制自己公司的MQ,可以掌控,社区活跃度相对一般,不过也还可以,文档相对来说简单一些,接口这块不是按照标准的JMS规范走的,有些系统做迁移需要做较大的代码改动,还有就是阿里出台的技术你得做好技术万一别抛弃,社区黄掉的风险,如果公司有一定的技术实力,可以大胆是使用。kafka的特点的其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms级别的延迟,极高的可用性和可靠性,分布式架构可以任意扩展,同时kafka最好支撑较少的topic数量,保证其超高的吞吐量,二是kafka唯一的的劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志收集中,这点轻微的影响可以忽略不计。这个特性天然适合大数据实时计算以及日志收集

经过上面分析之后大家根据自己的业务都会找到自己合适的消息中间件。

一般在业务系统需要引入MQ时,早期大家都用ActiveMQ,但是现在确实使用的不多了,其没有经过大规模吞吐量场景的验证,社区活跃度也不高,所以大家想想还是算了吧,个人不建议使用。

现在越来越多的公司,都会去使用RocketMQ,这个确实不错,但是得提防社区万一突然黄掉的风险,对自己公司技术实力有绝对信心的,推荐使用RocketMQ,否则还是老老实实的去用RabbitMQ吧,人家是活跃的开源的社区,绝对不会死的。

所以中小型公司,技术实力一般,技术挑战不是特别高,RabbitMQ是一个不错选择,大型公司,基础架构研发实力强,用RocketMQ是很好的选择。

如果是大数据领域的实时计算,日志采集等场景,用kafka是业内标准,绝对没有问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的实时性规范。

查看原文

赞 0 收藏 0 评论 0

阅历笔记 发布了文章 · 2020-06-08

项目重构记录

前沿

本重构文档仅是本人在项目重构时的汇报文档,如有不当之处欢迎指正。后期还有个重构后性能对比有机会我也会贴出来。在此记录也是为了方便自己以后查证,温故,希望对有需要的朋友有帮助。

1、背景

A 项目现有系统架构继承于外包公司、导致整个系统架构比较落后、臃肿引入很多没必要模块、模块之间耦合度太大无法进行拆分和搽出无关的模块。导致开发、升级、发布比较痛苦。

项目管理后、APP医生端、APP患者端整个代码交织在一起,无法做到单独功能、模块的升级、部署。往往会出现解决一个Bug又引入更对的Bug。

2、原有架构

从系统架构图上看、此系统是一个类SOA服务的简化本、大家看着也比较熟悉
原架构.jpg
整理架构让看着也不是太落后但是代码实现让人看着非常怀旧、里面使用大量的使用落后技术分装的比较臃肿的类库。整个系统架构使用N年以前封装的一些臃肿的类库硬堆成SOA服务架构,里面还是MVC架构。

2.1、原架构的存在问题

2.1.1 DAO

DAO使用自己分装一个大而全的数据库访问操作。优势(对于外包)一个Jar解决所有的第三方ORM框架。缺点是项目变得臃肿、垃圾代码耦合度太大无法升级。

2.1.2 Service

业务逻辑为Controller层提供具体业务的实现。但在实现上、问题很多。如果是严格按照分层架构来实现、对业务逻辑层进行拆分、将本地调用变成远程调用、即可比较容易拆分、但实际中遇到如下问题。

业务层往往未实现单向依赖、部分业务逻辑层实现被注入了接口层的参数(request、response)或者直接在接口层来实现、使其和接口层的耦合的增加。

为了应为不但变更的需求、不少接口使用map作为输入输入参数、此类接口在维护时无法约束其参数。

Service层绝大部分操作使用PO对象来作为数据处理对象,未对业务实体建模。这个层的实现是不完整。这使的对业务实体的操作需要推迟到Controller层来实现、导致Controller臃肿。

当服务之间存在大量依赖关系时,开发人员往往会直接将Spring BeanFactory注入到各个服务中,或者简单封装一个FacadeService,通过这个Service可以访问到所有的业务逻辑对象。这个类的使用导致无法评估Controller层对Service业务对象的具体依赖。

2.1.3 Controller

Controller层承担了大量的业务逻辑使其臃肿、难以测试。

2.2功能问题

从整个系统上看、系统并没有区分、APP患者端、医生端、系统管理、使其代码完全耦合在一起、只是实现了功能、完全没有考虑可用性和扩张性。

3、实施问题

3.1可扩展性和性能提升困难

应用性能瓶颈基本都在数据库上。这个系统使用mysql作为数据库。三个应用对应一个数据库。读写都在一个库上操作。

3.2系统臃肿、学习周期长

500多个接口,全在一个项目中。项目最多有1000多个类,可用类大概在300左右、存在大量的僵尸类。Nginx前置路由。路由这个让人欣慰,它是整个重构工作的有力支撑。纯后端的项目,为移动端app,PC,WEB应用提供接口。
三个应用的的所有代码全部交杂在一个臃肿的系统中、业务逻辑混难导致开发人员不敢去碰现有的代码、修改一个小功能可能会导致整个系统的崩溃。

3.3合作成本

随着项目组人员增加,每次新版本开发都需要多人一起合作,修改同一个项目代码。虽然使用版本控制工具来对分支进行管理,但是不可避免的,大量的时间花费在代码冲突处理上。新增功能,增强功能,bug修复,支持各种客户端,都在一个项目上进行,需要建立不同的分支,高峰期五六个分支同时进行都是常见的。这种情况下,代码冲突的频率非常高。一个周的小版本开发,1天时间在解决冲突都是很正常的。

3.4测试难度

测试工作也逐步的恶化了。测试环境构建难度高。随着分支的增加,每个进入测试的分支,都需要准备独立的测试环境。环境构建成本高。刚测试完的功能,由于分支合并冲突处理,又得重新跑一遍。严重影响项目进度

3.5上线风险高

随着系统复杂度的增加,上线风险也越来也大。一个小功能的修改,打印一个日志,修复一个bug,都需要整体上线。一旦有一个地方修改错了,这个系统就崩溃了。上线时间长,一次上线,半个小时是必须的。

3.6引入新技术难度大

公司对新技术的追求和使用显得特别饥渴、这种生搬硬套的架构伪SOA架构降低了开发成本,但是对屏蔽了其它技术的导入。

很长一段时间这个系统都是由一位同事在维护和开发、对外接口全部混杂在一起,访问量也不大、开发人员完全是在本地开发、出现问题首先想到的是打补丁、而不会考虑是否结束这种混乱的架构而去从新构建系统。而当公司做业务调整,人员迅速增加后,原有的方式,就需要变更了。这就应了所谓的康威定律。

4、重构思路

根据现有系统的遇到问题,我们现在使用微服务架构来从新重构整个项目的架构。根据微服务的特性其可以解决上诉所有问题。

性能问题:对性能要求高的接口可以建立缓存来优化接口。

学习周期:一个项目仅包含少数紧耦合的接口、接口业务单一、开发人员1-2小时就可以同读代码、即可上手。

合作成本:每个项目相对独立,项目之间仅通过接口来交互。确定完接口后,开发、测试、上线,都是独立进行的,从而降低了沟通成本。

版本控制:由于项目之间是接口依赖而不是代码依赖,每个项目都可以建立独立的代码库。同时项目切分的比较细,每个项目开发时,仅会有一个开发人员对其做修改。这基本就不存在代码合并工作,也避免了代码合并过程中的各种问题。实际上,基于微服务架构的开发,我们并没有采用分支策略,而是直接用主干开发。

测试难度:每个项目独立部署、独立测试。由于消除了代码分支,没有代码合并的隐患,重复测试的工作量减少了。

上线风险:每个项目独立上线,就算出现问题了,也仅影响到少数接口。

新技术:在微服务改造进行中,各种新技术将被引入到系统中,开发不再局限于简单架构。集群、分布式、限流、降级、容错、Redis等缓存系统,都开始在项目中使用,并有效地解决的业务上存在的问题。

4.1现有业务拆分

根据现有业务进行梳理后、将整个系统进行拆分为:

API网关(gateway-server)

统一权限服务(auth-server)

医生聚合服务(doctor-consumer-server)

患者聚合服务(patient-consumer-server)

管理系统聚合服务(system-consumer-server)

用户基础服务(user-provider-server)、

医生基础服务(doctor-provider-server)、

资源基础服务(resource-provider-server)

患者基础服务(patient-provider-server)

消息基础服务(msg-provider-server)

注册中心(eureka-server)

4.2基础架构

重构后架构.jpg

4.3逻辑架构

逻辑架构.jpg

4.4 排期

……

查看原文

赞 1 收藏 0 评论 0

阅历笔记 发布了文章 · 2020-02-23

深入浅出设计模式-策略模式

策略模式属于对象的行为模式。其用意就是针对一组算法、将每一个算法封装到具有共同接口或者抽象类的独立类中,从而使它们可以相互替换。策略模式使的算法可以在不影响到客户端的情况下发生变化。

1、问题引入

现在有这么个场景、有一个售卖图书电子商务网站购物车系统。一个最简单的需求就是计算价格上。

1: 对有教材图书实行固定架构如每本一元。

2: 对有连环画提供7%的折扣、非教材计算机图书提供3%的折扣、其余图书没有折扣。

那么怎么解决这个问题尼??

解决方案

这里提供三种解决方案(当然方案还有很多)

  1. 所有业务逻辑都放到客户端里面、客户端利用条件选择语句来决定使用哪一个算法。这样以来客户端代码就会变的复杂和难以维护。
  2. 客户端可以使用继承的方式在子类中实现不同的行为。但是这样会使的行为和环境紧密的耦合在一起。强耦合使得两者不能单独演化。
  3. 使用策略模式。策略模式会把行为和环境分割开来。环境类负责维护和查询行为类。各种算法则在具体的策略类中是实现。由于算法和环境独立开、算法的增减和修改不会影响环境和客户端。

策略模式就是解决这个问题的系统化方法。当出现新的促销和折扣政策或者出现变化时。只需要新增策略类,并在客户端登记就可以了。策略模式可以看作是一个可插入算法。

下面我们就来看看策略模式是个什么鬼。

2、策略模式介绍

2.1、结构

策略模式是一个非常简单的模式、有多简单尼?看起来比单利还简单、但是要在工作中用好确实万难的。
策略模式结构图.jpg
如图有三个角色:

  1. Context(环境角色)
    持有一个Strategy类的引用
  2. Strategy(抽象角色)
    这是一个抽象角色,通常时由一个接口或者抽象类实现,此角色给出所有的具体策略类的所需要的接口。
  3. ConcreteStrategy(具体角色角色)
    包装了相关算法或行为。

2.2、代码实现

代码实现其实很简单如下
代码清单1: 环境类的源代码

package com.xman.common.mongo.strategy;  
/**  
 * @author yueli  
 * @date 2020-02-15 20:09  
 */
 public class Context {  
    private Strategy strategy;  

 public Context(Strategy strategy) {  
        this.strategy \= strategy;  
  }  

    public void algorithm(){  
        strategy.algorithm();  
  }  
}

代码清单2: 抽象策略类源代码

package com.xman.common.mongo.strategy;  

/**  
 * @author yueli  
 * @date 2020-02-15 20:05  
 */
 public interface Strategy {   
 \* 策略方法 */
 void algorithm();  
}

代码清单3: 具体角色类源代码

package com.xman.common.mongo.strategy;  

/**  
 * @author yueli  
 * @date 2020-02-15 20:08  
 */
 public class ConceteStrategy implements Strategy {  
    @Override  
  public void algorithm() {  
        // write you algorithm code hrer  
  }  
}

注: 具体角色可以有多个实现、我在这里就不多写了。

还是那句话看着简单运用却不是那么容易。下面我们再来分析下它的优缺点。

2.3、优点

  1. 策略模式提供了对‘开闭原则’的完美支持,用户可以在不修改原有系统的基础上选择算法或者行为,也可以灵活的新增新的算法和行为。
  2. 策略模式提供了管理算法族的办法。
  3. 策略模式提供了可以替换继承关系的办法。
  4. 策略模式可以避免使用多重条件转移语句。

2.4、缺点

  1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
  2. 策略模式造成产生很多策略类和对象,可以通过使用享元模式在一定程度上减少对象的数量。

2.4、使用场景

说完优缺点我们在来介绍下那些场景适合使用策略模式

  1. 一个系统类有很多个类,它们的却别仅在于它们的行为、这种情况使用策略模式可以动态的让一个对象在许多中行为中选择一种行为。
  2. 一个系统需要动态的在集中算法中选择一种。
  3. 一个系统算法使用的数据不可以让客户端知道、策略模式可以避免让客户端直接和算法数据接触。
  4. 一个对象有很多中行为,如果不恰当的使用模式、这些行为就只好使用多重条件选择语句来实现,说白了就是可以替换掉程序中大量的if{……}else if{……} ……。

3、总结

策略模式理解起来很简单,记住两点1、有三种角色。2、针对一组算法,管理一个算法族。

策略模式设计的原则有: 开闭原则、里氏代换原则。如有对设计模式设计的原则还不太了解的请移步到《设计模式六大原则、你还记得多少?》

好了!策略模式就介绍到这里,如有不正确的地方欢迎指正交流。

查看原文

赞 0 收藏 0 评论 0

阅历笔记 发布了文章 · 2020-02-16

【转载】一份完整的阿里云 Redis 开发规范,值得收藏!

本文主要介绍在使用阿里云 Redis 的开发规范,从下面几个方面进行说明。

  • 键值设计
  • 命令使用
  • 客户端使用
  • 相关工具

通过本文的介绍可以减少使用 Redis 过程带来的问题。

一、键值设计

1、key 名设计

可读性和可管理性

以业务名 (或数据库名) 为前缀(防止 key 冲突),用冒号分隔,比如业务名: 表名: id

ugc:video:1

简洁性

保证语义的前提下,控制 key 的长度,当 key 较多时,内存占用也不容忽视,例如:

user:{uid}:friends:messages:{mid}简化为u:{uid}:fr:m:{mid}。

不要包含特殊字符

反例:包含空格、换行、单双引号以及其他转义字符

2、value 设计

拒绝 bigkey

防止网卡流量、慢查询,string 类型控制在 10KB 以内,hash、list、set、zset 元素个数不要超过 5000。

反例:一个包含 200 万个元素的 list。

非字符串的 bigkey,不要使用 del 删除,使用 hscan、sscan、zscan 方式渐进式删除,同时要注意防止 bigkey 过期时间自动删除问题 (例如一个 200 万的 zset 设置 1 小时过期,会触发 del 操作,造成阻塞,而且该操作不会不出现在慢查询中 (latency 可查)),查找方法和删除方法

选择适合的数据类型

例如:实体类型 (要合理控制和使用数据结构内存编码优化配置, 例如 ziplist,但也要注意节省内存和性能之间的平衡)。

反例:

set user:1:name tom

set user:1:age 19

set user:1:favor football

正例:

hmset user:1 name tom age 19 favor football

控制 key 的生命周期

redis 不是垃圾桶,建议使用 expire 设置过期时间 (条件允许可以打散过期时间,防止集中过期),不过期的数据重点关注 idletime。

二、命令使用

1、O(N) 命令关注 N 的数量

例如 hgetall、lrange、smembers、zrange、sinter 等并非不能使用,但是需要明确 N 的值。有遍历的需求可以使用 hscan、sscan、zscan 代替。

2、禁用命令

禁止线上使用 keys、flushall、flushdb 等,通过 redis 的 rename 机制禁掉命令,或者使用 scan 的方式渐进式处理。

3、合理使用 select

redis 的多数据库较弱,使用数字进行区分,很多客户端支持较差,同时多业务用多数据库实际还是单线程处理,会有干扰。

4、使用批量操作提高效率
  1. 原生命令:例如 mget、mset。
  2. 非原生命令:可以使用 pipeline 提高效率。

但要注意控制一次批量操作的元素个数 (例如 500 以内,实际也和元素字节数有关)。

注意两者不同:

  1. 原生是原子操作,pipeline 是非原子操作。
  2. pipeline 可以打包不同的命令,原生做不到
  3. pipeline 需要客户端和服务端同时支持。
5、不建议过多使用 Redis 事务功能

Redis 的事务功能较弱 (不支持回滚),而且集群版本(自研和官方) 要求一次事务操作的 key 必须在一个 slot 上(可以使用 hashtag 功能解决)。

6、Redis 集群版本在使用 Lua 上有特殊要求

1、所有 key 都应该由 KEYS 数组来传递,redis.call/pcall 里面调用的 redis 命令,key 的位置,必须是 KEYS array, 否则直接返回 error,"-ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS arrayrn" 2、所有 key,必须在 1 个 slot 上,否则直接返回 error, "-ERR eval/evalsha command keys must in same slotrn"

7、monitor 命令

必要情况下使用 monitor 命令时,要注意不要长时间使用。

三、客户端使用

1、避免多个应用使用一个 Redis 实例

不相干的业务拆分,公共数据做服务化。

2、使用连接池

可以有效控制连接,同时提高效率,标准使用方式:

Jedis jedis = null;

try {

    jedis = jedisPool.getResource();

//具体的命令

    jedis.executeCommand()

} catch (Exception e) {

     logger.error("op key {} error: " + e.getMessage(), key, e);

} finally {

//注意这里不是关闭连接,在JedisPool模式下,Jedis会被归还给资源池。

if (jedis != null) 

        jedis.close();

}

3、熔断功能

高并发下建议客户端添加熔断功能 (例如 netflix hystrix)

4、合理的加密

设置合理的密码,如有必要可以使用 SSL 加密访问(阿里云 Redis 支持)

5、淘汰策略

根据自身业务类型,选好 maxmemory-policy(最大内存淘汰策略),设置好过期时间。

默认策略是 volatile-lru,即超过最大内存后,在过期键中使用 lru 算法进行 key 的剔除,保证不过期数据不被删除,但是可能会出现 OOM 问题。

其他策略如下:

  • allkeys-lru:根据 LRU 算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。
  • allkeys-random:随机删除所有键,直到腾出足够空间为止。
  • volatile-random: 随机删除过期键,直到腾出足够空间为止。
  • volatile-ttl:根据键值对象的 ttl 属性,删除最近将要过期数据。如果没有,回退到 noeviction 策略。
  • noeviction:不会剔除任何数据,拒绝所有写入操作并返回客户端错误信息 "(error) OOM command not allowed when used memory",此时 Redis 只响应读操作。

四、相关工具

1、数据同步

redis 间数据同步可以使用:redis-port

2、big key 搜索

redis 大 key 搜索工具

3、热点 key 寻找

内部实现使用 monitor,所以建议短时间使用 facebook 的 redis-faina 阿里云 Redis 已经在内核层面解决热点 key 问题

五、删除 bigkey

  1. 下面操作可以使用 pipeline 加速。
  2. redis 4.0 已经支持 key 的异步删除,欢迎使用。
1、Hash 删除: hscan + hdel
publicvoid delBigHash(String host, int port, String password, String bigHashKey) {

Jedis jedis = newJedis(host, port);

if (password != null && !"".equals(password)) {

        jedis.auth(password);

    }

ScanParams scanParams = newScanParams().count(100);`

String cursor = "0";

do {

ScanResult<Entry<String, String>> scanResult = jedis.hscan(bigHashKey, cursor, scanParams);

List<Entry<String, String>> entryList = scanResult.getResult();

if (entryList != null && !entryList.isEmpty()) {

for (Entry<String, String> entry : entryList) {

                jedis.hdel(bigHashKey, entry.getKey());

            }

        }

        cursor = scanResult.getStringCursor();

    } while (!"0".equals(cursor));

    

   //删除bigkey

    jedis.del(bigHashKey);

}

2、List 删除: ltrim
publicvoid delBigList(String host, int port, String password, String bigListKey) {

Jedis jedis = newJedis(host, port);

if (password != null && !"".equals(password)) {

       jedis.auth(password);

    }

long llen = jedis.llen(bigListKey);

int counter = 0;

int left = 100;

while (counter < llen) {

//每次从左侧截掉100个

        jedis.ltrim(bigListKey, left, llen);

        counter += left;

    }

//最终删除key

    jedis.del(bigListKey);

}

3、Set 删除: sscan + srem
publicvoid delBigSet(String host, int port, String password, String bigSetKey) {

Jedis jedis = newJedis(host, port);

if (password != null && !"".equals(password)) {

        jedis.auth(password);

    }

ScanParams scanParams = newScanParams().count(100);

String cursor = "0";

do {

ScanResult<String> scanResult = jedis.sscan(bigSetKey, cursor, scanParams);

List<String> memberList = scanResult.getResult();

if (memberList != null && !memberList.isEmpty()) {

for (String member : memberList) {

                jedis.srem(bigSetKey, member);

            }

        }

        cursor = scanResult.getStringCursor();

    } while (!"0".equals(cursor));

 

//删除bigkey

    jedis.del(bigSetKey);

}

4、SortedSet 删除: zscan + zrem
publicvoid delBigZset(String host, int port, String password, String bigZsetKey) {

Jedis jedis = newJedis(host, port);

if (password != null && !"".equals(password)) {`

        jedis.auth(password);

    }

ScanParams scanParams = newScanParams().count(100);

String cursor = "0";

do {

ScanResult<Tuple> scanResult = jedis.zscan(bigZsetKey, cursor, scanParams);

List<Tuple> tupleList = scanResult.getResult();

if (tupleList != null && !tupleList.isEmpty()) {

for (Tuple tuple : tupleList) {

               jedis.zrem(bigZsetKey, tuple.getElement());

            }

        }

        cursor = scanResult.getStringCursor();

    } while (!"0".equals(cursor));

    

//删除bigkey

    jedis.del(bigZsetKey);

}
查看原文

赞 0 收藏 0 评论 0

阅历笔记 发布了文章 · 2020-02-11

设计模式六大原则、你还记得多少?

1、写在前面

说起设计模式我想对每一个猿友来说都是一个油腻的话题、23中设计模式张口就来。然而对于这些模式的的设计原则大家还能记起多少?了解多少以及用到多少尼?下面就让我们来一起回顾下。

2、六大设计原则

设计模式六大设计原则分别为、开-闭原则里氏代换原则依赖倒转原则合成/聚合复用原则迪米特法则接口隔离原则等六大设计原则。

下面让我们一一介绍下他们吧!

2.1、“开-闭”原则 (ocp)

经典力学的基石是牛顿三大定义、而面向对象可复用设计的第一块基石,便是所谓的“开-闭”原则(open-closed-principle).

什么是“开-闭”原则??????

“开-闭”原则讲的是:一个软件实体应当对扩展开放、对修改关闭(膜拜下 Bertrand Meyer)。

就是说:设计一个模块时、应当使这个模块在不被修改的前提下被扩展。

程序猿语言:应当可以在不必修改源码的情况下改变这个模块的行为。

所有的软件系统有个一共同的特性、即对他的需求会随着时间的推移而改变(当然这不是程序猿大战产品的理由)。
在软件系统面临新的需求时,系统必须是稳如磐石的。

满足“开-闭”原则的设计可以给一个软件系统提供两个无可比拟的优势(少干架)

1: 通过扩展已有软件系统,可以提供新的行为、以满足对软件系统的新需求,使变化中的系统有一定的适应性和灵活性

2: 已有的软件模块、特别是抽象层的模块是万万不能在修改的,这就使变化中的软件系统有一定的稳定性和延续性。

具有这两个优点的软件系统、是一个高层次上实现了复用的系统、也是一个易于维护和扩展的系统。

如何实现“开-闭”原则???

咋看起来、不能修改和可以扩展是相互矛盾的。怎么来实现不能修改的同时用能扩展尼???

解决问题关键还是老生常谈的抽象化了。我们都知道Java语言是一个面向对象的语言,我们可以给系统定一个一个一劳永逸、不再修改的抽象层(或者接口),此设计可以有无穷无尽的行为实现层来实现。

在Java中我们可以抽象出一个或者多个抽象类或者接口、规定出所有具体类(实现类)必须提供的方法特征作为系统设计的抽象层。这个抽象层预见了所有可能的扩展,因此在任何扩展情况下都不会改变。这就使系统的抽象层不需要修改,从而满足“开-闭”原则中的第二条:对修改关闭。

同时、由于从抽象层派生出一个或者多个具体实现类可以改变系统的行为。因此系统的设计对扩展是开放的,这就满足了“开-闭”原则的第一条。

要做到“开-闭”原则不是一件容易的事、但是也不是完全无规律可循、这些规律也同样是以设计原则的身份出现,但是他们都是“开-闭”的手段和工具、是附属于“开-闭”的。

里氏代换原则、依赖倒转原则、合成/聚合复用原则、迪米特法则、接口隔离原则等。

2.2、里氏代换原则(LSP)

从“开-闭”原则中可以看出面向对象设计重要原则是创建抽象化。并且从抽象化导出具体化。

具体化可以给出不同的版本,每一个版本都给出不同的实现(说直白点就是基类和子类的关系)。

从抽象化到具体化的导出要使用到继承关系和这里要引入的里氏代换原则。

什么是里氏代换原则???

一个软件实体如果使用的是一个基类的话,那么一定适用于其子类,而且它根本不能察觉出基类对象和子类对象的区别(也就是说,任何基类出现的地方都可以替换成子类)。

比如: 有两个类,一个是Base类,另一个是Derived类,并且Derived类是Base类的子类。

那么一个方法如果可以接受一个基类对象base的话method(Base base)那么它必然可以接受一个子类对象derived,也就是method(Derived derived)。

注意:里氏代换原则反过来是无法实现的。

2.3、依赖倒转原则(DIP)

实现“开-闭”原则的关键是抽象化、并且从抽象化导出具体实现,如说“开-闭”是面向对象设计的目标的话,依赖倒转原则是面向对象的设计的主要机制。
依赖倒转原则讲的是: 要依赖于抽象,不要依赖于具体。

什么是依赖倒转原则???

简单的说,依赖倒转原则要求客户依赖抽象耦合。

依赖倒转原则表述的是;细节应当依赖于抽象。

其另一种表述是:要针对接口编程,不要针对实现编程,

针对接口编程意思是说,应当使用Java接口和抽象类进行变量的类型声明、参量的类型声明、方法的返回类型声明、以及数据类型的转换等。

不要针对实现编程的意思是说:不应当使用具体类进行变量的类型声明、参量的类型声明、方法的返回类型声明、以及数据类型的转换等。

要保证做到这一点,一个具体的Java 类应当只实现Java接口或者抽象类中声明过的方法,而不应当有多余的方法。

倒转依赖关系强调一个系统内的实体之间的关系的灵活性。基本上,如果设计师希望遵守“开-闭”原则,那么倒转依赖原则便是达到要求的途径。

2.4、接口隔离原则(ISP)

接口隔离原则讲的是:使用多个专门的接口比使用单一总接口要好。换而言之,从一个客户类的角度来讲,一个类对另一个的依赖性应当建立在最小的接口上

什么是接口隔离原则???

使用多个专门的接口比使用单一的总接口要好

一个类对另外一个类的依赖性应当是建立在最小的接口上的。

一个接口代表一个角色,不应当将不同的角色都交给一个接口。

没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。“不应该强迫客户依赖于它们不用的方法。

接口属于客户,不属于它所在的类层次结构。”这个说得很明白了,再通俗点说,不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。

2.5、合成/聚合复用原则(CARP)

合成/聚合复用原则经常又叫做合成复用原则。合成/聚合复用原则就是在一个新对象里面使用一个已经存在的对象,使之成为新对象的一部分,新对象通过向这些对象委派达到复用功能的目的。
这个设计原则有另一个更简单的表述: 要进尽量使用合成/聚合,尽量不要使用继承。

合成一词使用比较广泛,经常用易引起混淆。为了避免混淆我们来简单的考察下"合成"和“聚合”的区别

1: 合成和聚合均是关联的特殊种类。
2: 聚合用来表示“拥有”关系或者整体与部分的关系、同时部分可以单独存在。
3: 合成则表示一种强的多的“拥有”关系,部分和整体的生命周期是一致的,部分离开整体无法单独存活的。比如人是一个整体各个肢体是部分。

2.6、迪米特法则(LoD)

迪米特法则又叫最少知道原则,就是说,一个对象应当对其他对象有尽可能少的了解。

迪米特法则最初是用来作为面向对象的系统设计风格的一种法则,1987年秋天由 Ian Holland 在美国东北大学为一个叫迪米特的项目设计提出的。因此叫做迪米特法则。

迪米特法则的各种表述

没有任何一个其它的OO设计原则像迪米特法则这样有如此之多的表述方式,下面是几种有代表性的表述。

1: 只与你直接的朋友通信
2: 不要跟“陌生人”说话
3: 每一个软件单位对其的单位都只有最少的了解,而且局限于哪些与本单位密切相关的软件单位。

在上面表述中里面,什么是“直接“,”陌生“和”密切“则被有意识的模糊化了,以便在不同的环境下可以有不同的解释。

总结

这些设计原则都是软件工程里面很基础也很重要的部分,也是我们开发人员最容易忽略的部分。

作为面试官的几年里,应聘者能完整答上来设计模式的几大原则或者面向对象设计原则的太少了(包括一些高级和资深)。

如果这几大原则没有吃透的话,是不可能设计出一个好的软件系统的。写这篇的目的也在于自己回顾加深一下理解。

查看原文

赞 1 收藏 1 评论 0

认证与成就

  • 获得 72 次点赞
  • 获得 8 枚徽章 获得 0 枚金徽章, 获得 3 枚银徽章, 获得 5 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

注册于 2019-04-22
个人主页被 2.6k 人浏览