超级账本源码分析:peer服务启动流程
链块学院
2018-12-27
热度10341

区块链开发教程,本章节介绍peer node start命令的执行流程。

一,前言

上一节中我们分析了 peer 的命令结构,peer的node子命令中添加了一个start命令,这个命令就是启动一个peer的服务,本章节我们分析这个peer node start命令的执行流程。 


二,peer peer口节点启动

var nodeStartCmd =&cobra.Command { 
Use:“start”,
Short :“Start the node。”,
Long:`启动一个与网络交互的节点。
RunE:func(cmd * cobra.Command,args [] string )error {
return serve(args)
},
}


三,服务函数

服务函数的主要作用是启动fabric peer的各个服务,其实就是启动了各种GRPC的服务端,比如EventsServer服务,chaincodesupport服务等等。

下表是各个服务的作用描述:

服务描述
EventsServer服务可以提供事件的注册机制,比如可以通过它监视chaincode中的事件
ChaincodeSupport服务提供链代码的执行,停止功能
ServerAdmin服务提供对服务器,模块日志级别的获取和控制
Endorser服务为交易提供
背书服务GossipService服务网络中处理的八卦消息的接受和发送

func serve(args [] string)error { 
logger.Infof(“Starting%s”,version.GetInfo())
ledgermgmt.Initialize()
//必须在
//缓存任何参数之前处理参数覆盖缓存失败导致服务器立即终止。
如果chaincodeDevMode {
logger.Info(“在链代码开发模式下运行”)
logger.Info(“禁用加载有效性系统链代码”)
 
viper.Set(“chaincode.mode”,chaincode.DevModeUserRunsChaincode)
 
}
 
if err:= peer.CacheConfiguration( ); err!= nil {
return err
}
 
peerEndpoint,err:= peer.GetPeerEndpoint()
if err!= nil {
err = fmt.Errorf(“无法获得对等端点:%s”,


 
listenAddr:= viper.GetString(“peer.listenAddress”)
 
secureConfig,err:= peer.GetSecureConfig()
if err!= nil {
logger.Fatalf(“加载对等(%s)的安全配置错误”,错误)
}
peerServer ,err:= peer.CreatePeerServer(listenAddr,secureConfig)
if err!= nil {
logger.Fatalf(“无法创建对等服务器(%s)”,错误)
}
 
如果secureConfig.UseTLS {
logger.Info(“启用TLS“)
//设置CA支持
caSupport:= comm.GetCASupport()
caSupport.ServerRootCAs = secureConfig.ServerRootCAs
}
 
 //启动eventsHub服务
// TODO - 我们是否需要不同的SSL材料用于事件?
ehubGrpcServer,错误:= createEventHubServer(secureConfig)
if err!= nil {
grpclog.Fatalf(“无法创建ehub服务器:%v”,错误)
}
 
//启动链码服务
//启用链码信息缓存
ccprovider.EnableCCInfoCache()
 
ccSrv,ccEpFunc:= createChaincodeServer(peerServer ,listenAddr)
registerChaincodeSupport(ccSrv.Server(),ccEpFunc)
go ccSrv.Start()
 
logger.Debugf(“Running peer”)
 
 //启动管理服务
//注册管理服务器
pb.RegisterAdminServer(peerServer.Server(),core .NewAdminServer())
 
 //启动管理服务
//注册Endorser服务器
serverEndorser:= endorser.NewEndorserServer()
pb.RegisterEndorserServer(peerServer.Server(),serverEndorser)
 
//初始化八卦组件
bootstrap:= viper.GetStringSlice(“peer.gossip.bootstrap”)
 
serializedIdentity,err:= mgmt.GetLocalSigningIdentityOrPanic()。Serialize()
if err!= nil {
logger.Panicf(“序列化自我身份失败:%v”,错误)
}
 
 //启动gossip服务
messageCryptoService:= peergossip.NewMCS(
peer.NewChannelPolicyManagerGetter(),
localmsp.NewSigner(),
mgmt.NewDeserializersManager())
secAdv:= peergossip.NewSecurityAdvisor(mgmt.NewDeserializersManager())
 
//回调函数八卦服务的安全拨号选项
secureDialOpts:= func()[] grpc.DialOption {
var dialOpts [] grpc.DialOption
//设置max send / recv msg sizes
dialOpts = append(dialOpts,grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(comm.MaxRecvMsgSize()),
grpc.MaxCallSendMsgSize(comm.MaxSendMsgSize())))
//设置keepalive选项
dialOpts = append(dialOpts,comm.ClientKeepaliveOptions() ...)
 
如果comm.TLSEnabled(){
tlsCert:= peerServer.ServerCertificate()
dialOpts = append(dialOpts,grpc.WithTransportCredentials(comm.GetCASupport()。GetPeerCredentials(tlsCert)))
} else {
dialOpts = append(dialOpts, grpc.WithInsecure())
}
return dialOpts
}
err = service.InitGossipService(serializedIdentity,peerEndpoint.Address,peerServer.Server(),
messageCryptoService,secAdv,secureDialOpts,bootstrap ...)
if err!= nil {
return err
}
defer service.GetGossipService()。Stop()
 
 //
初始化系统链码//初始化系统链码
initSysCCs()
 
//这会打开所有链(包括testchainid)
peer.Initialize(func(cid string){
logger .Debugf(“部署系统CC,链<%s>”,cid)
scc.DeploySysCCs(cid)
})
 
logger.Infof(“起始对等体ID = [%s],网络ID = [%s],地址= [%s]“,
peerEndpoint.Id,viper.GetString(”peer.networkId“),peerEndpoint.Address)
 
//启动grpc服务器。在goroutine中完成,以便我们可以
根据需要部署// genesis块。
serve:= make(chan error)
 
sigs:= make(chan os.Signal,1)
signal.Notify(sigs,syscall.SIGINT,syscall.SIGTERM)
go func(){
sig:= <-sigs
logger.Debugf(“sig:%s”,sig)
serve < - nil
}()
 
go func(){
var grpcErr error
if grpcErr = peerServer.Start(); grpcErr!= nil {
grpcErr = fmt.Errorf(“grpc server exist with error:%s”,grpcErr)
} else {
logger.Info(“peer server exited”)
}
serve < - grpcErr
}()
 
if err:= writePid (config.GetPath(“peer.fileSystemPath”)+“/ peer.pid”,os.Getpid()); err!= nil {
return err
}
 
//启动事件中心服务器
如果ehubGrpcServer!= nil {
go ehubGrpcServer.Start()
}
 
 //如果配置使能了profile,则启动profiing服务
//启动分析http端点如果启用
if viper.GetBool(“peer.profile.enabled”){
go func(){
profileListenAddress:= viper.GetString(“peer.profile.listenAddress”)
logger.Infof(“使用listenAddress =%s启动分析服务器”,profileListenAddress )
如果profileErr:= http.ListenAndServe(profileListenAddress,nil); profileErr!= nil {
logger.Errorf(“Error starting profiler:%s”,profileErr)
}
}()
}
 
logger.Infof(“已启动对等体ID = [%s],网络ID = [%s],地址= [%s]“,
peerEndpoint.Id,viper.GetString(”peer.networkId“),peerEndpoint.Address)
 
//设置通过环境
//变量或core.yaml 定义的特定模块的日志记录级别
overrideLogModules:= [] string {“msp”,“gossip”,“ledger”,“cauthdsl”,“policies”,“grpc”}
for _,module:= range overrideLogModules {
err = common.SetLogLevelFromViper(module)
if err != nil {
logger.Warningf(“模块'%s'的错误设置日志级别:%s”,模块,err.Error())
}
} flogging.SetPeerStartupModulesMap
 
()
 
//阻塞直到grpc服务器退出
 //阻塞直到grpc退出
返回<-serve
}
```


3.1  一个dmin 服务

管理服务实现对服务器状态,模块日志级别的获取和控制,注册函数RegisterAdminServer在织物/ PROTOS /对等体/ admin.pb.go中:

//用于管理服务的服务器API 
 
类型AdminServer interface {
 //返回服务状态。
GetStatus(context.Context,* google_protobuf.Empty)(* ServerStatus,error)
StartServer(context.Context,* google_protobuf.Empty)(* ServerStatus,error)
GetModuleLogLevel(context.Context,* LogLevelRequest)(* LogLevelResponse,error)
SetModuleLogLevel (context.Context,* LogLevelRequest)(* LogLevelResponse,error)
RevertLogLevels(context.Context,* google_protobuf.Empty)(* google_protobuf.Empty,error)
}
 
func RegisterAdminServer(s * grpc.Server,srv AdminServer){
s.RegisterService (&_Admin_serviceDesc,srv)
}

从上面可以出管理员服务对外提供了5个方法,这5个方法的实现具体在织物/型芯/ admin.go中:

//用于对等
类型ServerAdmin struct {
}的AdminAdmin的ServerAdmin实现
 
// GetStatus报告服务器
func 的状态(* ServerAdmin)GetStatus(context.Context,* empty.Empty)(* pb.ServerStatus,error){
status:=&pb.ServerStatus {Status:pb.ServerStatus_STARTED}
log.Debugf(“返回状态:%s”,状态)
返回状态,nil
}
 
// StartServer启动服务器
func(* ServerAdmin)StartServer(context.Context,* empty.Empty)(* pb.ServerStatus,error){
status:=&pb.ServerStatus {Status:pb.ServerStatus_STARTED}
log.Debugf(“return status:%s”,status)
return status,nil
}
 
// GetModuleLogLevel获取指定模块的当前日志记录级别
// TODO修改签名以删除错误返回 - 它始终为nil
func(* ServerAdmin)GetModuleLogLevel(ctx context.Context,request * pb.LogLevelRequest)(* pb.LogLevelResponse,error){
logLevelString:=
flogging.GetModuleLevel (request.LogModule)logResponse:=&pb.LogLevelResponse {LogModule:request.LogModule,LogLevel:logLevelString}
return logResponse,nil
}
 
// SetModuleLogLevel设置指定的日志记录级别module
func(* ServerAdmin)SetModuleLogLevel(ctx context.Context,request * pb.LogLevelRequest)(* pb.LogLevelResponse,error){
logLevelString,err:= flogging.SetModuleLevel (request.LogModule,request.LogLevel)
logResponse:=&pb.LogLevelResponse {LogModule:request.LogModule,日志级别:logLevelString}
返回logResponse,ERR
}
 
// RevertLogLevels恢复日志级别的所有模块,以水平
//在对等体起动的端部限定。
FUNC(*的ServerAdmin)RevertLogLevels(context.Context,* empty.Empty)(* empty.Empty,错误){
ERR:= flogging.RevertToPeerStartupLevels()
 
返回&empty.Empty {},ERR
}

从上面的代码我们可以发现和的getStatus startserver的函数的内容是一样的,startserver的函数只返回了一个状态,其他没有任何操作,也就是说默认管理服务都是启动的,那管理服务最有意义的方法应该是日志等级相关的操作了.GetModuleLogLevel获取当前模块的日志等级,SetModuleLogLevel设置当前日志模块等级.RevertLogLevels方法可以将当前对等体的日志等级恢复到启动时的等级。


四,系统链码的注册和部署

服务

系统链码安装是scc.RegisterSysCCS函数,这个函数的调用路径是服务函数调用了registerChaincodeSupport函数,然后调用了scc.RegisterSysCCS:

func registerChaincodeSupport(grpcServer * grpc.Server,ccEpFunc ccEndpointFunc){ 
// get user mode
userRunsCC:= chaincode.IsDevMode()
 
 // get chaincode startup timeout
ccStartupTimeout:= viper.GetDuration(“chaincode.startuptimeout”)
if ccStartupTimeout <time。持续时间(5)*
time.Second { logger.Warningf(“无效的链代码启动超时值%s(应该至少为5s);默认为5s”,ccStartupTimeout)
ccStartupTimeout = time.Duration(5)* time.Second
} else {
logger.Debugf(“Chaincode启动超时值设置为%s”,ccStartupTimeout)
}
 
ccSrv:= chaincode.NewChaincodeSupport(ccEpFunc,userRunsCC,ccStartupTimeout)
 
 //现在初始化了链代码,注册所有系统链代码。
scc.RegisterSysCCs()
 
pb.RegisterChaincodeSupportServer(grpcServer,ccSrv)
}

系统的链码的安装是scc.DeploySysCCS,这个函数的调用路径是服务函数调用了InitSysCCs函数,然后调用了scc.DeploySysCCs:

func initSysCCs(){ 
 //部署系统链代码
scc.DeploySysCCs(“”)
logger.Infof(“Deployed system chaincodess”)
}


五,总结

本小节主要介绍节点启动命令的执行流程,也就是服务函数,服务函数会启动了EventsServer,ChaincodeSupport,Endorser,GossipService服务,另外服务函数还安装和部署了系统链码,下一章节我们介绍系统链码安装和部署的详细流程。


-结束-

(未经授权,谢绝转载,版权最终解释权归链块学院所有)

本内容旨在传递行业动态,不构成投资建议或承诺。
为你推荐

商务合作:TG:@Lottie96