Welcome to go-chassis’s documentation!¶
Introductions¶
Concepts¶
- Registry
- 注册中心负责微服务的注册和发现
- Registrator
- 自注册组件,go-chassis在启动后会连接注册中心,自注册服务信息
- Service Discovery
- 服务发现组件,负责服务发现并周期性轮询注册中心中的服务到本地缓存。
- Protocol server and client
- 支持开发者自己将协议逻辑插入到go chassis中,接入统一的治理和微服务管理当中
Features¶
- 注册发现:帮助微服务自注册并发现其他微服务
- 插件化注册中心:默认对接Service Center和文件系统,开发者可自己扩展Kubernetes,Consul,Eureka等服务
- 限流:提供客户端与服务端限流
- 负载均衡:提供Filter与Strategy2种方式对实例进行选择,并可定制
- 熔断:可通过超时时间,错误率,并发量等条件进行熔断控制,保护系统,防止雪崩效应
- 降级:熔断后可配置降级策略
- 处理链:支持在一次请求调用中,插入自己的处理逻辑
- 插件化协议:默认支持http,Highway RPC 2种协议
- 插件化Cipher:在证书,aksk等敏感数据加载时,支持使用自己的加解密算法
- Metrics:支持导出Prometheus格式监控数据
- Tracing:分布式调用链追踪,支持对接Zipkin
- 日志:支持扩展自己的Writer实现,可上报给kafka,Elasticseach等组件,默认支持本地文件和stdout
- 动态配置框架:对接不同Source,当Source中的配置项出现变化,将触发事件,让微服务感知,用户可自定义事件触发的动作
- 配置热加载:负载均衡,熔断,降级等等配置支持运行时热加载
How it works¶
这里解释运行时发生了什么
不同协议请求进入到各协议Server,Server将具体的协议请求转换为Invocation统一抽象模型,并传入Handler chain,在这里Chassis已经默认实现了很多的Handler,比如熔断,限流等,最终再进入Transport handler,使用具体的协议客户端传输到目标。
每次请求生成的监控数据通过http API导出的方式,由Prometheus收集处理
日志可通过扩展,输出到kafka等服务中也可使用华为公有云APM服务收集
注册中心默认对接Service center
Archaius为动态配置框架,可从各种不同的source中读取配置
Get started¶
最小化安装¶
- Go 参照官方文档安装1.8+版本 https://golang.org/doc/install
- 执行命令 git clone git@github.com:ServiceComb/go-chassis.git
- 执行命令 go get -u github.com/FiloSottile/gvt
- 进入go-chassis目录执行gvt restore
- 请参考文档安装Service center https://github.com/ServiceComb/service-center/releases
使用RPC通信¶
安装protobuff 3.2.0 https://github.com/google/protobuf
安装golang插件 https://github.com/golang/protobuf
Writing Rest service¶
服务端 1个工程或者go package,推荐结构如下
server/
├── conf
│ ├── chassis.yaml
│ └── microservice.yaml
└── main.go
1.编写接口
type RestFulHello struct {}
func (r *RestFulHello) Sayhello(b *restful.Context) {
b.Write([]byte("get user id: " + b.ReadPathParameter("userid")))
}
2.注册路由
func (s *RestFulHello) URLPatterns() []restful.Route {
return []restful.Route{
{http.MethodGet, "/sayhello/{userid}", "Sayhello"},
}
}
3.注册接口
第一个参数表示你要向哪个协议注册,第三个为schema ID,会在调用中使用
chassis.RegisterSchema(“rest”, &RestFulHello{}, server.WithSchemaId(“RestHelloService”)) 说明:
想注册的rest协议的接口,必须实现URLPatterns方法定义路由 路由中暴露为API的方法都要入参均为*restful.Context 3.修改配置文件chassis.yaml
cse:
service:
registry:
address: http://127.0.0.1:30100
protocols:
rest:
listenAddress: 127.0.0.1:5001
4.修改microservice.yaml
service_description:
name: RESTServer
5.main.go中启动服务
func main() {
//start all server you register in server/schemas.
if err := chassis.Init(); err != nil {
lager.Logger.Error("Init failed.", err)
return
}
chassis.Run()
}
客户端 1个工程或者go package,推荐结构如下
client/
├── conf
│ ├── chassis.yaml
│ └── microservice.yaml
└── main.go
1.修改配置文件chassis.yaml
cse:
service:
registry:
address: http://127.0.0.1:30100
2.修改microservice.yaml
service_description: name: RESTClient 3.main中调用服务端,请求包括服务名,schema,operation及参数
//if you use go run main.go instead of binary run, plz export CHASSIS_HOME=/path/to/conf/folder
func main() {
//Init framework
if err := chassis.Init(); err != nil {
lager.Logger.Error("Init failed.", err)
return
}
req, _ := rest.NewRequest("GET", "cse://RESTServer/sayhello/world")
defer req.Close()
resp, err := core.NewRestInvoker().ContextDo(context.TODO(), req)
if err != nil {
lager.Logger.Error("error", err)
return
}
defer resp.Close()
lager.Logger.Info(string(resp.ReadBody()))
}
Writing RPC service¶
定义请求与返回结构体 1个工程或者go package,推荐结构如下
schemas
├── helloworld
│ ├──helloworld.proto
1.定义helloworld.proto文件
syntax = "proto3";
package helloworld;
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
2.通过pb生成go文件 helloworld.pb.go
protoc –go_out=. hello.proto 将生成的go文件拷贝到目录中
schemas
├── helloworld
│ ├──helloworld.proto
│ └──helloworld.pb.go
服务端 1个工程或者go package,推荐结构如下
server/
├── conf
│ ├── chassis.yaml
│ └── microservice.yaml
└── main.go
1.编写接口
type HelloServer struct {
}
func (s *HelloServer) SayHello(ctx context.Context, in *helloworld.HelloRequest) (*helloworld.HelloReply, error) {
return &helloworld.HelloReply{Message: "Go Hello " + in.Name}, nil
}
2.注册接口
第一个参数表示你要向哪个协议注册,第三个为schema ID,会在调用中使用
chassis.RegisterSchema(“highway”, &HelloServer{}, server.WithSchemaId(“HelloService”)) 说明:
想暴露为API的方法都要符合以下条件
第一个参数为context.Context
第二个参数必须是结构体指针
返回的第一个必须是结构体指针
返回的第二个为error
3.修改配置文件chassis.yaml
cse:
service:
registry:
address: http://127.0.0.1:30100
protocols:
highway:
listenAddress: 127.0.0.1:5000
4.修改microservice.yaml
service_description:
name: Server
5.main.go中启动服务
func main() {
//start all server you register in server/schemas.
if err := chassis.Init(); err != nil {
lager.Logger.Error("Init failed.", err)
return
}
chassis.Run()
}
客户端 1个工程或者go package,推荐结构如下
client/
├── conf
│ ├── chassis.yaml
│ └── microservice.yaml
└── main.go
1.拿到pb文件生成go代码
protoc –go_out=. hello.proto 2.修改配置文件chassis.yaml
cse:
service:
registry:
address: http://127.0.0.1:30100
3.修改microservice.yaml
service_description:
name: Client
4.main中调用服务端,指定微服务名,schema,operation与参数和返回
//if you use go run main.go instead of binary run, plz export CHASSIS_HOME=/path/to/conf/folder
func main() {
//Init framework
if err := chassis.Init(); err != nil {
lager.Logger.Error("Init failed.", err)
return
}
//declare reply struct
reply := &helloworld.HelloReply{}
//Invoke with microservice name, schema ID and operation ID
if err := core.NewRPCInvoker().Invoke(context.Background(), "Server", "HelloService", "SayHello", &helloworld.HelloRequest{Name: "Peter"}, reply); err != nil {
lager.Logger.Error("error", err)
}
lager.Logger.Info(reply.Message)
}
User guides¶
微服务定义¶
概述¶
一个微服务需要通过microservice.yaml文件对自己进行定义。 微服务与微服务实例概念: 每个进程对应一个微服务实例,多个实例可能属于同一个微服务。 比如:以程序为单位,编译打包后运行便产生了一个微服务实例,他们的代码是同源的,也就是说他们属于同一个微服务
配置¶
name
(required, string) 微服务名称
APPLICATION_ID
(optional, string) 所属应用 默认default
version
(optional, string) 版本号 默认0.0.1
properties
(optional, map) 微服务元数据,通常在开发期就已经定死
instance_properties
(optional, map) 微服务实例元数据,运行期每个实例的内容可能会根据运行环境而有差异
例子¶
service_description:
name: Server
properties:
project: test
instance_properties:
nodeIP: 192.168.0.111
Registry¶
概述¶
微服务的注册发现默认通过服务中心完成。 用户可以配置与服务中心的通信方式,服务中心地址,以及自身注册到服务中心的信息。 微服务启动过程中,会自动向服务中心进行注册。 在微服务运行过程中,go-chassis会周期从服务中心查询其他服务的实例信息缓存到本地
配置¶
注册中心相关配置分布在两个yaml文件中,分别为chassis.yaml和microservice.yaml文件。 chassis.yaml中配置使用的注册中心类型、注册中心的地址信息。
- type: 对接的服务中心类型默认加载servicecenter和file两种,registry也支持用户定制registry并注册。
- scope: 默认不允许跨应用间访问,只允许本应用间访问,当配置为full时则允许跨应用间访问,且能发现本租户全部微服务。
- autodiscovery: 是否开启自动发现,开启后将从服务中心注册发现注册的其他服务中心。
- register: 配置项默认为自动注册,即框架启动时完成实例的自动注册。当配置manual时,框架只会注册配置文件中的微服务,不会注册实例,使用者可以通过服务中心对外的API完成实例注册。
- api.version: 目前只支持v4版本。
disabled
(optional, bool) 是否开启服务注册发现模块,默认为false
type
(optional, string) 对接服务中心插件类型,默认为servicecenter
scope
(optional, bool) 默认为full,允许跨app发现,填入app以禁止跨应用发现
autodiscovery
(optional, bool) 自动发现 服务中心集群节点 默认为false
address
(optional, bool)服务中心地址 允许配置多个以逗号隔开,默认为空
register
(optional, bool) 是否自动自注册,默认为 auto,可选manual
refreshInterval
(optional, string) 更新实例缓存的时间间隔,格式为数字加单位(s/m/h),如1s/1m/1h,默认为30s
api.version
(optional, string) 访问服务中心的api版本,默认为v4
watch
(optional, bool) 是否watch实例变化事件,默认为false
API¶
Registry提供以下接口供用户注册微服务及实例。以下方法通过Registry提供的相关接口实现,内置有两种Registry的实现,默认为servicecenter。另外支持用户自行定义实现Registry接口的插件,用于服务注册发现。
注册微服务实例¶
RegisterMicroserviceInstances() error
注册微服务¶
RegisterMicroservice() error
自定义Registry插件¶
InstallPlugin(name string, f func(opts ...Option) Registry)
示例¶
服务中心最简化配置只需要registry的address,注册的微服务实例通过appId、服务名和版本决定。
APPLICATION_ID: default #optional
cse:
service:
registry:
disabled: false #optional: 默认开启registry模块
type: servicecenter #optional: 默认类型为对接服务中心
scope: full #optional: scope为full注册时允许跨app
autodiscovery: true
address: http://10.0.0.1:30100,http://10.0.0.2:30100
register: auto #optional:默认为自动 [auto manual]
refeshInterval : 30s
watch: true
api:
version: v4
服务发现¶
概述¶
Service discovery 是关于如何发现服务的配置。 和Registry的区别是,他仅负责发现服务,而不负责注册服务 Service Discovery与Registry只能选择其一进行配置 启用此功能可以与Istio的Pilot集成
配置¶
服务发现的配置在chassis.yaml。
type
(optional, string) 对接服务中心插件类型,默认为servicecenter
address
(optional, bool)服务中心地址 允许配置多个以逗号隔开,默认为空
refreshInterval
(optional, string) 更新实例缓存的时间间隔,格式为数字加单位(s/m/h),如1s/1m/1h,默认为30s
示例¶
cse:
service:
Registry:
serviceDiscovery:
type: pilot
address: http://istio-pilot.istio-system:8080
refeshInterval : 30s
客户端健康检查¶
概述¶
客户端健康检查(Health Check)是指客户端对服务端实例缓存进行健康性的判断。
在网络分区或延时较大的环境下,客户端可能会出现上报心跳到服务中心失败的情况,导致结果是,客户端会将收到的实例下线事件,并移除本地实例缓存,最终影响业务调用。
为防止上述情况发生,go-chassis提供这样的健康检查机制:当客户端监听到某个(或latest)版本的服务端可用实例下降到0个时, 客户端会在同步移除实例缓存前进行一次健康检查,调用服务端暴露的健康检查接口(RESTful或Highway)并校验其返回值来确认是否要移除实例缓存。
配置¶
服务端注册¶
go-chassis默认不会主动注册服务端的健康检查接口,需要用户主动import到项目中。
// 注册健康检查接口
import _ "github.com/ServiceComb/go-chassis/healthz/provider"
加入上述代码片段后,go-chassis会按照暴露的服务协议类型对应注册健康检查接口,接口描述如下
RESTful:
- Method: GET
- Path: /healthz
- Response:
{ "appId": "string", "serviceName": "string", "version": "string" }
Highway:
- Schema: _chassis_highway_healthz
- Operation: HighwayCheck
- Response:
// The response message containing the microservice key message Reply { string appId = 1; string serviceName = 2; string version = 3; }
Invoker¶
API¶
Rest调用¶
使用NewRestInvoker创建一个invoker实例,可接受chain, filters等自定义选项
ContextDo可以接受一个http request作为参数,开发者可通过request的API对request进行操作,并作为参数传入该方法
func NewRestInvoker(opt ...Option) *RestInvoker
func (ri *RestInvoker) ContextDo(ctx context.Context, req *rest.Request, options ...InvocationOption) (*rest.Response, error)
RPC调用¶
使用NewRPCInvoker创建invoker实例,可接受chain, filters等自定义选项
指定远端的服务名,struct name,以及func name,以及请求参数和返回接口即可进行调用
最终结果会赋值到reply参数中
func NewRPCInvoker(opt ...Option) *RPCInvoker
func (ri *RPCInvoker) Invoke(ctx context.Context, microServiceName, schemaID, operationID string, arg interface{}, reply interface{}, options ...InvocationOption) error
无论Rest还是RPC调用方法都能够接受多种选项对一次调用进行控制,参考options.go查看更多选项
示例¶
RPC¶
添加了2个具体调用选项,使用highway rpc,并使用roundrobin路由策略
invoker.Invoke(ctx, "Server", "HelloServer", "SayHello",
&helloworld.HelloRequest{Name: "Peter"},
reply,
core.WithProtocol("highway"),
core.WithStrategy(loadbalance.StrategyRoundRobin),
core.WithVersion("0.0.1"),
)
Rest¶
与普通的http调用不同的是url参数不使用ip:port而是服务名并且http://变为cse://
在初始化invoker时还指定了这次请求要经过的处理链名称custom
req, _ := rest.NewRequest("GET", "cse://RESTServer/sayhello/world")
defer req.Close()
resp, err := core.NewRestInvoker(core.ChainName("custom")).ContextDo(context.TODO(), req)
负载均衡策略¶
配置¶
负载均衡的配置项为cse.loadbalance.[MicroServiceName].[PropertyName],其中若省略MicroServiceName,则为全局配置;若指定MicroServiceName,则为针对特定微服务的配置。优先级:针对特定微服务的配置 > 全局配置。
为便于描述,以下配置项说明仅针对PropertyName字段
strategy.name
(optional, bool) RoundRobin | 策略,可选值:RoundRobin,Random,SessionStickiness,WeightedResponse。 SessionStickiness目前只支持Rest调用。
注意:
- 使用SessionStickiness策略,需要业务代码存储cookie,并在http请求中带入Cookie。使用go-chassis进行调用时,http头中将返回如下信息:Set-Cookie: SERVICECOMBLB=0406060d-0009-4e06-4803-080008060f0d,若用户使用SessionStickiness策略,需要将将该头部信息保存,并在发送后续请求时带上如下http头:Cookie: SERVICECOMBLB=0406060d-0009-4e06-4803-080008060f0d**
- 使用 WeightedResponse策略,启用后30s 策略会计算好数据并生效,80%左右的请求会被发送到延迟最低的实例里
API¶
除了通过配置文件传入负载均衡策略,还支持用户客户端调用传入WithStrategy的方式。
invoker.Invoke(ctx, "Server", "HelloServer", "SayHello",
&helloworld.HelloRequest{Name: "Peter"},
reply,
core.WithContentType("application/json"),
core.WithProtocol("highway"),
core.WithStrategy(loadbalance.StrategyRoundRobin),
)
示例¶
配置chassis.yaml的负载均衡部分,以及添加处理链。
cse:
loadbalance: # 全局负载均衡配置
strategy:
name: RoundRobin
microserviceA: # 微服务级别的负载均衡配置
strategy:
name: SessionStickiness
负载均衡过滤器¶
概述¶
负载均衡过滤器实现在负载均衡模块中,它允许开发者定制自己的过滤器,使得经过负载均衡策略选择实例前,预先对实例进行筛选。在一次请求调用过程中可以使用多个过滤策略,对从本地cache或服务中心获取的实例组进行过滤,将经过精简的实例组交给负载均衡策略做后续处理。
配置¶
目前可配的filter只有根据Available Zone Filter。可根据微服务实例的region以及AZ信息进行过滤,优先寻找同Region与AZ的实例。
cse:
loadbalance:
serverListFilters: zoneaware
需要配置实例的Datacenter信息
region:
name: us-east
availableZone: us-east-1
API¶
Go-chassis支持多种实现Filter接口的过滤器。FilterEndpoint支持通过实例访问地址过滤,FilterMD支持通过元数据过滤,FilterProtocol支持通过协议过滤,FilterAvailableZoneAffinity支持根据Zone过滤。
type Filter func([]*registry.MicroServiceInstance) []*registry.MicroServiceInstance
示例¶
客户端实例过滤器Filter的使用支持用户通过API调用传入,并且可以一次传入多个Filter,对实例组进行层层条件筛选。客户端调用传入的方式是调用options的WithFilter方法。
invoker.Invoke(ctx, "Server", "HelloServer", "SayHello",
&helloworld.HelloRequest{Name: "Peter"},
reply,
core.WithProtocol("highway"),
core.WithStrategy(loadbalance.StrategyRoundRobin),
core.WithFilters(
loadbalance.FilterEndpoint("highway://127.0.0.1:8080"),
loadbalance.FilterProtocol("highway"),
),
)
动态配置¶
概述¶
go-chassis提供动态配置管理能力,支持CSE配置中心,本地文件,环境变量及命令行等多种配置管理,并由archaius包提供统一的接口获取配置。
API¶
archaius包提供获取全部配置和四种获取指定配置值的Get方法,同时提供默认值,即若指定配置值未配置则使用默认值。另外提供Exist方法判断指定配置值是否存在。用户可使用UnmarshalConfig方法提供反序列化配置到结构体的方法。go-archaius内置5个配置源,获取配置时优先从优先级高的配置源获取指定配置项,若无则按优先级高低依次从后续配置源获取,直到遍历所有配置源。内置配置源生效的优先级由高到底分别是配置中心,命令行,环境变量,文件,外部配置源。
获取指定配置值¶
GetBool(key string, defaultValue bool) bool
GetFloat64(key string, defaultValue float64) float64
GetInt(key string, defaultValue int) int
GetString(key string, defaultValue string) string
Get(key string) interface{}
Exist(key string) bool
获取全部配置¶
GetConfigs() map[string]interface{}
反序列化配置到结构体¶
UnmarshalConfig(obj interface{}) error
在go-archaius默认纳入动态管理的配置文件外,提供了AddFile方法允许用户添加其他文件到动态配置管理中。AddKeyValue可额外为外部配置源添加配置对。除默认加载的配置源外,允许用户实现自己的配置源,并通过RegisterListener注册到动态配置管理框架中。
添加文件源¶
AddFile(file string) error
外部配置源添加配置对¶
AddKeyValue(key string, value interface{}) error
注册/注销动态监听¶
RegisterListener(listenerObj core.EventListener, key ...string) error
UnRegisterListener(listenerObj core.EventListener, key ...string) error
在对接config center配置中心时请求中需指定demensionsInfo信息来确定获取配置的实例。该接口允许为配置项分区域DI配置和查询。
添加DI及获取指定DI的配置值¶
GetConfigsByDI(dimensionInfo string) map[string]interface{}
GetStringByDI(dimensionInfo, key string, defaultValue string) string
AddDI(dimensionInfo string) (map[string]string, error)
示例¶
示例中文件配置如下,可通过archaius包的Get方法读取指定文件配置项。
cse:
fallback:
Consumer:
enabled: true
maxConcurrentRequests: 20
archaius.GetInt("cse.fallback.Consumer.Consumer.maxConcurrentRequests", 10)
archaius.GetBool("cse.fallback.Consumer.Consumer.enabled", false)
Router¶
概述¶
路由策略可应用于AB测试场景和新版本的灰度升级,主要通过路由规则来根据请求的来源、目标服务、Http Header及权重将服务访问请求分发到不同版本的微服务实例中。
比如通过路由管理你可以简单的实现新老版本服务切换
配置¶
路由规则当前只支持在配置文件配置,支持rest和highway协议。
Consumer配置¶
灰度发布的路由规则只在服务的消费端配置使用,用于将特定的请求,按一定权重,分发至同一服务名的不同分组。用户可在conf/router.yaml 文件中设置:
routeRule:
{targetServiceName}: # 服务名
- precedence: {number} #优先级
match: #匹配策略
source: {sourceServiceName} #匹配某个服务名
headers: #header匹配
{key0}:
regex: {regex}
{key1}
exact: {=?}
route: #路由规则
- weight: {percent} #权重值
tags:
version: {version1}
app: {appId}
- precedence: {number1}
match:
refer: {sourceTemplateName} #参考某个source模板ID
route:
- weight: {percent}
tags:
version: {version2}
app: {appId}
sourceTemplate: #定义source模板
{templateName}: # source 模板ID
source: {sourceServiceName}
sourceTags:
{tag}:{value}
headers:
{key0}:
regex: {regex}
{key1}
exact: {=?}
{key2}:
noEqu: {!=?}
{key3}
greater: {>?}
{key4}:
less: {<?}
{key5}
noLess: {>=?}
{key6}:
noGreater: {<=?}
路由规则说明:
- 匹配特定请求由match配置,匹配条件是:source(源服务名)、source tags 及headers,另外也可以使用refer字段来使用source模板进行匹配。
- Match中的Source Tags用于和服务调用请求中的sourceInfo中的tags 进行逐一匹配。
- Header中的字段的匹配支持正则, 等于, 小于, 大, 于不等于等匹配方式。
- 如果未定义match,则可匹配任何请求。
- 转发权重定义在routeRule.{targetServiceName}.route下,由weight配置。
- 服务分组定义在routeRule.{targetServiceName}.route下,由tags配置,配置内容有version和app。
例子¶
目标服务¶
每个路由规则的目标服务名称都由routeRule中的Key值指定。例如下表所示,所有以“Carts”服务为目标服务的路由规则均被包含在以“Carts”为Key值的列表中。
routeRule:
Carts:
- precedence: 1
route:
- weight: 100 #percent
tags:
version: 0.0.1
Key值(目标服务名称)应该满足是一个合法的域名称。例如,一个在服务中心中注册的服务名称。
规则优先级¶
针对某个特定的目标服务可以定义多条路由规则,在路由规则匹配过程中的匹配顺序按照各个规则的“precedence”字段的值来确定。“precedence”字段是可选配置,默认为0,值越大则优先级越高。如果两个规则的“precedence”配置值相同,则它们的实际匹配顺序是不确定的。
一种常用的模式是为指定的目标服务提供一条或多条具有高优先级的匹配请求源/Header的路由规则,并同时提供一条低优先级的只依照版本权重分发请求的路由规则,且这条规则不设置任何匹配条件以处理剩余的其他请求。
以下面的路由规则为例,对所有访问“Carts“服务的请求,如果满足header中包含”Foo:bar“,则将请求分发到服务的”2.0“版本的实例中,剩余的其他请求全部分发到”1.0“版本的实例中。
routeRule:
Carts:
- precedence: 2
match:
headers:
Foo:
exact: bar
route:
- weight: 100
tags:
version: 2.0
- precedence: 1
route:
- weight: 100
tags:
version: 1.0
请求匹配规则¶
match:
refer: {templateName}
source: {sourceServiceName}
headers:
{key}:
regex: {regex}
{key1}:
exact: {exact}
请求的匹配规则属性配置如下:
refer
(optional, string) 引用的匹配规则模板名称,用户可选择在sourceTemplate中定义匹配规则模板,并在此处引用。若引用了匹配规则模板,则其他配置项不用配置。
source
(optional, string) 表示发送请求的服务,和consumer是一个意义。
headers
(optional, string) 匹配headers。 如果配置了多条Header 字段校验规则,则需要同时满足所有规则才可完成路由规则匹配。 匹配方式有以下几种:精确匹配(exact):header必须等于配置; 正则(regex):按正则匹配header内容;不等于(noEqu):header不等于配置值;大于等于(noLess): header不小于配置值;小于等于(noGreater):header不大于配置值;大于(greater):header大于配置值;小于(less): header小于配置值
示例:
match:
source: vmall
headers:
cookie:
regex: "^(.*?;)?(user=jason)(;.*)?$"
仅适用于来自vmall,header中的“cookie”字段包含“user=jason”的服务访问请求。
分发规则¶
每个路由规则中都会定义一个或多个具有权重标识的后端服务,这些后端服务对应于用标签标识的不同版本的目标服务的实例。如果某个标签对应的注册服务实例有多个,则指向该标签版本的服务请求会按照用户配置的负责均衡策略进行分发,默认会采用round-robin策略。
分发规则的属性配置如下: weight
(optional, string) 本条规则的分发比重,配置为1-100的整数,表示百分比。
tags
(optional, string) 用于区分相同服务名的不同服务分组, 支持的key值为:版本(version),默认值为0.0.1。应用(app),默认值为default。
下面的例子表示75%的访问请求会被分流到具有“version:2.0”标签的服务实例中,其余25%的访问请求会被分发到1.0版本的实例中。
route:
- weight: 75
tags:
version: 2.0
- weight: 25
tags:
version: 1.0
定义匹配模板¶
我们可以通过预定义源模板(模板中的结构为一个Match结构),并在match部分引用该模板来进行路由规则的匹配。在下面的例子中,“vmall-with-special-header”是一个预定义的源模板的Key值,并在Carts的请求匹配规则中被引用。
routeRule:
Carts:
- precedence: 2
match:
refer: vmall-with-special-header
route:
- weight: 100
tags:
version: 2.0
sourceTemplate:
vmall-with-special-header:
source: vmall
headers:
cookie:
regex: "^(.*?;)?(user=jason)(;.*)?$"
Rate limiting¶
概述¶
用户可以通过配置限流策略限制provider端或consumer端的请求频率,使每秒请求数限制在最大请求量的大小。其中provider端的配置可限制接收处理请求的频率,consumer端的配置可限制发往指定微服务的请求的频率。
配置¶
限流配置在rate_limiting.yaml中,同时需要在chassis.yaml的handler chain中添加handler。其中qps.limit.[service] 是指限制从service 发来的请求的处理频率,若该项未配置则global.limit生效。Consumer端不支持global全局配置,其他配置项与Provider端一致。
flowcontrol.qps.enabled
(optional, bool) 是否开启限流,默认true
flowcontrol.qps.global.limit
(optional, int) 每秒允许的请求数,默认2147483647max int)
flowcontrol.qps.limit.{service}
(optional, string) 针对某微服务每秒允许的请求数 ,默认2147483647max int)
Provider示例¶
provider端需要在chassis.yaml添加ratelimiter-provider。同时在rate_limiting.yaml中配置具体的请求数。
cse:
handler:
chain:
Provider:
default: ratelimiter-provider
cse:
flowcontrol
Provider:
qps:
enabled: true # enable rate limiting or not
global:
limit: 100 # default limit of provider
limit:
Server: 100 # rate limit for request from a provider
Consumer示例¶
在consumer端需要添加ratelimiter-consumer这个handler。同时在rate_limiting.yaml中配置具体的请求数。
cse:
handler:
chain:
Consumer:
default: ratelimiter-consumer
cse:
flowcontrol:
Consumer:
qps:
enabled: true # enable rate limiting or not
limit:
Server: 100 # rate limit for request to a provider
API¶
qpslimiter提供获取流控实例的接口GetQpsTrafficLimiter和相关的处理接口。其中ProcessQpsTokenReq根据目标qpsRate在handler chain当中sleep相应时间实现限流,UpdateRateLimit提供更新qpsRate限制的接口,DeleteRateLimiter提供了删除流控实例的接口。
对请求流控¶
qpslimiter.GetQpsTrafficLimiter().ProcessQpsTokenReq(key string, qpsRate int)
更新流控限制¶
qpslimiter.GetQpsTrafficLimiter().UpdateRateLimit(key string, value interface{})
删除流控实例¶
qpslimiter.GetQpsTrafficLimiter().DeleteRateLimiter(key string)
Fault Tolerance¶
概述¶
go-chassis提供自动重试的容错能力,用户可配置retry及backOff策略自动启用重试功能。
配置¶
重试功能的相关配置与客户端负载均衡策略都在chassis.yaml的cse.loadbalance.配置下。当retryEnabled配置为true时,可通过配置retryOnSame和retryOnNext定制重试次数。另外可通过backOff定制重试策略,默认支持三种backOff策略。
- zero: 固定重试时间为0的重试策略,即失败后立即重试不等待。
- constant: 固定时间为backoff.minMs的重试策略,即失败后等待backoff.minMs再重试。
- jittered: 按指数增加重试时间的重试策略,初始重试时间为backoff.minMs,最大重试时间为backoff.MaxMs。
retryEnabled
(optional, bool) 是否开启重试功能, 默认值为false
retryOnSame
(optional, int) 请求失败后向同一个实例重试的次数,默认为0
retryOnNext
(optional, int) 请求失败后向其他实例重试的次数,默认为0
backoff.kind
(optional, string) 重试策略: [jittered或constant或zero] 默认为zero
backoff.MinMs
(optional, bool) 重试最小时间间隔 单位ms , 默认值为false
backoff.MaxMs
(optional, int) 重试最大时间间隔 单位ms, 默认值为0
示例¶
配置chassis.yaml负载均衡部分中的重试参数。
cse:
loadbalance:
retryEnabled: true
retryOnNext: 2
retryOnSame: 3
backoff:
kind: jittered
MinMs: 200
MaxMs: 400
熔断与降级¶
概述¶
降级策略是当服务请求异常时,微服务所采用的异常处理策略。
降级策略有三个相关的技术概念:“隔离”、“熔断”、“容错”:
- “隔离”是一种异常检测机制,常用的检测方法是请求超时、流量过大等。一般的设置参数包括超时时间、同时并发请求个数等。
- “熔断”是一种异常反应机制,“熔断”依赖于“隔离”。熔断通常基于错误率来实现。一般的设置参数包括统计请求的个数、错误率等。
- “容错”是一种异常处理机制,“容错”依赖于“熔断”。熔断以后,会调用“容错”的方法。一般的设置参数包括调用容错方法的次数等。
把这些概念联系起来:当”隔离”措施检测到N次请求中共有M次错误的时候,”熔断”不再发送后续请求,调用”容错”处理函数。这个技术上的定义,是和Netflix Hystrix一致的,通过这个定义,非常容易理解它提供的配置项,参考:https://github.com/Netflix/Hystrix/wiki/Configuration。当前ServiceComb提供两种容错方式,分别为返回null值和抛出异常。
配置¶
配置格式为:
cse.{namespace}.Consumer.{serviceName}.{property}: {configuration}
字段意义:
{namespace}取值为:isolation|circuitBreaker|fallback|fallbackpolicy,分别表示隔离、熔断、降级、降级策略。
{serviceName}表示服务名,即某个服务提供者。
{property}表示具体配置项。
{configuration}表示具体配置内容。
为了方便描述,下表中的配置项均省略了Consumer和{serviceName}。
cse.isolation.timeout.enabled
(optional, bool) 是否启用超时检测,默认false
cse.isolation.timeoutInMilliseconds
(optional, int) 超时阈值,默认30000
cse.isolation.maxConcurrentRequests
(optional, int)最大并发数阈值 默认1000
cse.circuitBreaker.enabled
(optional, bool) 是否启用熔断措施,默认true
cse.circuitBreaker.forceOpen
(optional, bool) 不管失败次数,都进行熔断 默认false
cse.circuitBreaker.forceClosed
(optional, bool)任何时候都不熔断,当与forceOpen同时配置时,forceOpen优先。默认false
cse.circuitBreaker.sleepWindowInMilliseconds
(optional, int) 熔断后,多长时间恢复。恢复后,会重新计算失败情况。注意:如果恢复后的调用立即失败,那么会立即重新进入熔断。 默认15000
cse.circuitBreaker.requestVolumeThreshold
(optional, int) 10s内统计错误发生次数阈值,超过阈值则触发熔断 | 由于10秒还会被划分为10个1秒的统计周期,经过1s中后才会开始计算错误率,因此从调用开始至少经过1s,才会发生熔断 默认20
cse.circuitBreaker.errorThresholdPercentage
(optional, int) 错误率阈值,达到阈值则触发熔断 默认50
cse.fallback.enabled
(optional, bool) 是否启用出错后的故障处理措施 默认为true
cse.fallbackpolicy.policy
(optional, string) 出错后的处理策略 可选 returnnull throwexception,默认returnnull
示例¶
---
cse:
isolation:
Consumer:
timeout:
enabled: false
timeoutInMilliseconds: 1
maxConcurrentRequests: 100
Server:
timeout:
enabled: true
timeoutInMilliseconds: 1000
maxConcurrentRequests: 1000
circuitBreaker:
Consumer:
enabled: false
forceOpen: false
forceClosed: true
sleepWindowInMilliseconds: 10000
requestVolumeThreshold: 20
errorThresholdPercentage: 10
Server:
enabled: true
forceOpen: false
forceClosed: false
sleepWindowInMilliseconds: 10000
requestVolumeThreshold: 20
errorThresholdPercentage: 5
fallback:
Consumer:
enabled: true
maxConcurrentRequests: 20
fallbackpolicy:
Consumer:
policy: throwexception
Tracing¶
概述¶
调用跟踪模块主要实现与“服务监控”的对接,按照服务监控的要求,产生span和SLA数据,按照配置文件的定义将产生的调用链数据输出到zipkin或文件中,用于分析调用链的调用过程和状态。
配置¶
使用调用链追踪功能,必须先在handler chain中添加对应handler:tracing-provider或tracing-consumer,默认存在。
tracing.collectorType
(requied, string) 定义调用数据向什么服务发送,支持 zipkin,namedPipe
tracing.collectorTarget
(requied, string) 服务的URI,比如文件路径,http地址。 collectorType为http时,collectorTarget为zipkin地址否则,namedPipe为文件路径
示例¶
追踪数据发送至zipkin:
cse:
handler:
chain:
Provider:
default: tracing-provider,bizkeeper-provider
tracing:
collectorType: zipkin
collectorTarget: http://localhost:9411/api/v1/spans
追踪数据写入linux named pipe:
tracing:
collectorType: namedPipe
collectorTarget: /home/chassis.trace
Metrics¶
概述¶
Metrics用于度量服务性能指标。开发者可通过配置文件来将框架自动手机的metrics导出并让prometheus收集。
如果有业务代码定制的metrics,也可以通过API来调用,来定制自己的的metrics
配置¶
cse.metrics.enable
(optional, bool) 是否开启metrics功能,默认为false
cse.metrics.apipath
(optional, string) metrics接口,默认为/metrics
cse.metrics.enableGoRuntimeMetrics
(optional, bool) 是否开启go runtime监测,默认为false
API¶
包路径
import "github.com/ServiceComb/go-chassis/metrics"
获取go-chassis的metrics registry,用户定制的metrics,可以通过这个registry来添加,最终也会自动导出到API的返回中
func GetSystemRegistry() metrics.Registry
获取go-chassis使用的prometheus registry,允许用户直接对Prometheus registry进行操作
func GetSystemPrometheusRegistry() *prometheus.Registry
创建一个特定名称的metrics registry
func GetOrCreateRegistry(name string) metrics.Registry
使用特定metrics registry向prometheus汇报metrics数据
func ReportMetricsToPrometheus(r metrics.Registry)
汇报metrics数据的http handler
func MetricsHandleFunc(req *restful.Request, rep *restful.Response)
示例¶
cse:
metrics:
apiPath: /metrics # we can also give api path having prefix "/" ,like /adas/metrics
enable: true
enableGoRuntimeMetrics: true
若rest监听在127.0.0.1:8080,则作上述配置后,可通过 http://127.0.0.1:8080/metrics 获取metrics数据。
Log¶
概述¶
用户可配置微服务的运行日志的相关属性,比如输出方式,日志级别,文件路径以及日志转储相关属性。
配置¶
日志配置文件为lager.yaml,配置模板如下:
- logger_level表示日志级别,由低到高分别为 DEBUG, INFO, WARN, ERROR, FATAL 共5个级别,这里设置的级别是日志输出的最低级别,只有不低于该级别的日志才会输出。
- writers表示日志的输出方式,默认为文件和标准输出。
- logger_file表示日志输出文件。
- log_format_text: 默认为false,即设定日志的输出格式为 json。若为true则输出格式为plaintext,类似log4j。建议使用json格式输出的日志。
- rollingPolicy: 默认为size,即根据大小进行日志rotate操作;若配置为daily则基于事件做日志rotate。
- log_rotate_date: 日志rotate时间配置,单位”day”,范围为(0, 10)。
- log_rotate_size: 日志rotate文件大小配置,单位”MB”,范围为(0,50)。
- log_backup_count: 日志最大存储数量,单位“个”,范围为[0,100)。
---
writers: file,stdout
# LoggerLevel: |DEBUG|INFO|WARN|ERROR|FATAL
logger_level: DEBUG
logger_file: log/chassis.log
log_format_text: false
#rollingPolicy daily/size
rollingPolicy: size
#log rotate and backup settings
log_rotate_date: 1
log_rotate_size: 10
log_backup_count: 7
API¶
通过配置lager.yaml,go-chassis会自动为服务加载日志模块,并默认输出日志到文件或标准输出。
Debug和Info级别的日志¶
lager.Logger.Info(action string, data ...Data)
lager.Logger.Debug(action string, data ...Data)
lager.Logger.Debugf(format string, args ...interface{})
lager.Logger.Infof(format string, args ...interface{})
Warn Error Fatal级别的日志¶
lager.Logger.Warn(action string, err error, data ...Data)
lager.Logger.Error(action string, err error, data ...Data)
lager.Logger.Fatal(action string, err error, data ...Data)
lager.Logger.Warnf(err error, format string, args ...interface{})
lager.Logger.Errorf(err error, format string, args ...interface{})
lager.Logger.Fatalf(err error, format string, args ...interface{})
TLS¶
概述¶
用户可以通过配置SSL/TLS启动HTTPS通信,保障数据的安全传输。包括客户端与服务端TLS,通过配置来自动启用Consumer与Provider的TLS配置。
配置¶
tls可配置于chassis.yaml文件或单独的tls.yaml文件。在如下格式中,tag指明服务名以及服务类型,key指定对应configuration的配置项。
ssl:
[tag].[key]: [configuration]
TAG¶
tag为空时ssl配置为公共配置。registry.consumer及configcenter.consumer是作为消费者访问服务中心和配置中心时的ssl配置。protocol.serviceType允许协议和类型的任意组合。name.protocol.serviceType在协议和类型的基础上可定制服务名。
registry.Consumer
服务注册中心TLS配置
serviceDiscovery.Consumer
服务发现TLS配置
contractDiscovery.Consumer
契约发现TLS配置
registrator.Consumer
服务注册中心TLS配置
configcenter.Consumer
配置中心TLS配置 |
{protocol}.{serviceType}
协议为任意协议目前包括 highway,rest,用户扩展协议后,即可使用新的协议配置。 类型为Consumer,Provider |
{name}.{protocol}.{serviceType}
定制某微服务的独有的TLS配置 name为微服务名
KEY¶
ssl支持以下配置项,其中若私钥KEY文件加密,则需要指定加解密插件及密码套件等信息进行解密。
cipherPlugin
(optional, string) 指定加解密插件 内部插件支持 default aes, 默认default |
verifyPeer
(optional, bool) | 是否验证对端,默认false
cipherSuits
(optional, string) TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 密码套件 |
protocol
(optional, string) TLS协议的最小版本,默认为TLSv1.2
caFile
(optional, string) ca文件路径
certFile
(optional, string) 私钥cert文件路径
keyFile
(optional, string) 私钥key文件路径
certPwdFile
(optional, string) 私钥key加密的密码文件
API¶
通过为Provider和Consumer配置ssl,go-chassis会自动为其加载相关配置。用户也可以通过chassis暴露的接口直接使用相关API。以下API主要用于获取ssl配置以及tls.Config。
获取默认SSL配置¶
GetDefaultSSLConfig() *common.SSLConfig
获取指定SSL配置¶
GetSSLConfigByService(svcName, protocol, svcType string) (*common.SSLConfig, error)
获取指定TLSConfig¶
GetTLSConfigByService(svcName, protocol, svcType string) (*tls.Config, *common.SSLConfig, error)
示例¶
Provider配置¶
以下为rest类型provider提供HTTPS访问的ssl配置,其中tag为protocol.serviceType的形式。
ssl:
rest.Provider.cipherPlugin: default
rest.Provider.verifyPeer: true
rest.Provider.cipherSuits: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
rest.Provider.protocol: TLSv1.2
rest.Provider.keyFile: /etc/ssl/server_key.pem
rest.Provider.certFile: /etc/ssl/server.cer
rest.Provider.certPwdFile: /etc/ssl/cert_pwd_plain
rest.Provider.caFile: /etc/ssl/trust.cer
Consumer配置¶
以下为访问rest类型服务的消费者的ssl配置。tag为name.protocol.serviceType的形式,其中Server为要访问的服务名,rest为协议。verifyPeer若配置为true将启动双向认证,否则客户端将忽略对服务端的校验。
ssl:
Server.rest.Consumer.cipherPlugin: default
Server.rest.Consumer.verifyPeer: true
Server.rest.Consumer.cipherSuits: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
Server.rest.Consumer.protocol: TLSv1.2
Server.rest.Consumer.keyFile: /etc/ssl/server_key.pem
Server.rest.Consumer.certFile: /etc/ssl/server.cer
Server.rest.Consumer.certPwdFile: /etc/ssl/cert_pwd_plain
Server.rest.Consumer.caFile: /etc/ssl/trust.cer
契约管理¶
概述¶
go-chassis读取服务契约并将其内容上传至注册中心。
配置¶
契约文件必须为yaml格式文件,契约文件应放置于go-chassis的schema目录。
schema目录位于:
1,conf/{serviceName}/schema,其中conf表示go-chassis的conf文件夹
2,${SCHEMA_ROOT}
2的优先级高于1。
API¶
包路径
import "github.com/ServiceComb/go-chassis/core/config/schema"
契约字典,key值为契约文件名,value为契约文件内容
var DefaultSchemaIDsMap map[string]string
示例¶
conf
`-- myservice
`-- schema
|-- myschema1.yaml
`-- myschema2.yaml
与Istio集成¶
服务发现¶
概述¶
go-chassis对接Istio的pilot组件,实现服务发现能力。
配置¶
接入pilot进行服务发现的配置在chassis.yaml。
registrator.disabled
设置禁用服务主动注册能力,与Istio集成后,由其对接的平台进行服务注册
serviceDiscovery.type
设置启用接入pilot插件
serviceDiscovery.address
pilot服务地址 允许配置多个以逗号隔开
示例¶
cse:
service:
Registry:
registrator:
disabled: true
serviceDiscovery:
type: pilot
address: http://istio-pilot.istio-system:8080
Development guides¶
Handler¶
概述¶
Go chassis以插件的形式支持在一次请求调用中,插入自己的处理逻辑。
实现¶
实现handler需要以下三个步骤:实现Handler接口,并根据其名称注册,最后在chassis.yaml中添加handler chain相关配置。其中[service_type] 可配置为Provider或Consumer,[chain_name]默认为default。
注册处理逻辑¶
RegisterHandler(name string, f func() Handler) error
实现处理接口¶
type Handler interface {
Handle(*Chain, *invocation.Invocation, invocation.ResponseCallBack)
Name() string
}
添加配置¶
cse:
handler:
chain:
[service_type]:
[chain_name]: [your_handler_name]
示例¶
示例中注册的是名为fake-handler的处理链,其实现的Handle方法仅记录inv的endpoint信息。
package handler
import (
"github.com/ServiceComb/go-chassis/core/handler"
"github.com/ServiceComb/go-chassis/core/invocation"
"log"
)
const Name = "fake-handler"
type FakeHandler struct{}
func init() { handler.RegisterHandler(Name, New) }
func New() handler.Handler { return &FakeHandler{} }
func (h *FakeHandler) Name() string { return Name }
func (h *FakeHandler) Handle(chain *handler.Chain, inv *invocation.Invocation,
cb invocation.ResponseCallBack) {
log.Printf("fake handler running for %v", inv.Endpoint)
chain.Next(inv, func(r *invocation.InvocationResponse) error {
return cb(r)
})
}
chassis.yaml配置示例如下
cse:
handler:
chain:
Provider:
default: fake-handler
Archaius¶
概述¶
go-archaius是go-chassis的动态配置框架,目前支持CSE 配置中心,本地文件,ENV,CMD等配置管理。如果用户希望接入自己的配置服务中,可以参考本章节实现。
使用说明¶
go-archaius支持同时配置多种源,包括命令行,环境变量,外部源及文件等。用户可通过ConfigurationFactory接口的AddSource方法添加自己的配置源,并通过RegisterListener方法注册EventListener。
AddSource(core.ConfigSource) error
RegisterListener(listenerObj core.EventListener, key ...string) error
其中配置源需要实现ConfigSource接口。其中GetPriority和GetSourceName必须实现且有有效返回,分别用于获取配置源优先级和配置源名称。GetConfigurations和GetConfigurationByKey方法用于获取全部配置和指定配置项,需要用户实现。其他方法可以返回空。
- GetPriority方法用于确定配置源的优先级,go-archaius内置的5个配置源优先级由高到底分别是配置中心,命令行,环境变量,文件,外部配置源,对应着0到4五个整数值。用户自己接入的配置源可自行配置优先级级别,数值越小则优先级越高。GetSourceName方法用于返回配置源名称。
- 若没有区域区分的集中式配置中心,DemensionInfo相关接口可返回nil不实现。
- Cleanup用于清空本地缓存的配置。
- DynamicConfigHandler接口可根据需要实现,用于实现动态配置动态更新的回调方法。
type ConfigSource interface {
GetSourceName() string
GetConfigurations() (map[string]interface{}, error)
GetConfigurationsByDI(dimensionInfo string) (map[string]interface{}, error)
GetConfigurationByKey(string) (interface{}, error)
GetConfigurationByKeyAndDimensionInfo(key, dimensionInfo string) (interface{}, error)
AddDimensionInfo(dimensionInfo string) (map[string]string, error)
DynamicConfigHandler(DynamicConfigCallback) error
GetPriority() int
Cleanup() error
}
注册EventListener用于在配置源更新时由Dispatcher分发事件,由注册的listener处理。
type EventListener interface {
Event(event *Event)
}
示例¶
实现configSource¶
type fakeSource struct {
Configuration map[string]interface{}
changeCallback core.DynamicConfigCallback
sync.Mutex
}
func (*fakeSource) GetSourceName() string { return "TestingSource" }
func (*fakeSource) GetPriority() int { return 0 }
func (f *fakeSource) GetConfigurations() (map[string]interface{}, error) {
config := make(map[string]interface{})
f.Lock()
defer f.Unlock()
for key, value := range f.Configuration {
config[key] = value
}
return config, nil
}
func (f *fakeSource) GetConfigurationByKey(key string) (interface{}, error) {
f.Lock()
defer f.Unlock()
configValue, ok := f.Configuration[key]
if !ok {
return nil, errors.New("invalid key")
}
return configValue, nil
}
func (f *fakeSource) DynamicConfigHandler(callback core.DynamicConfigCallback) error {
f.Lock()
defer f.Unlock()
f.changeCallback = callback
return nil
}
func (f *fakeSource) Cleanup() error {
f.Lock()
defer f.Unlock()
f.Configuration = make(map[string]interface{})
f.changeCallback = nil
return nil
}
func (*fakeSource) AddDimensionInfo(d string) (map[string]string, error) { return nil, nil }
func (*fakeSource) GetConfigurationByKeyAndDimensionInfo(k, d string) (interface{}, error) { return nil, nil }
func (*fakeSource) GetConfigurationsByDI(d string) (map[string]interface{}, error) { return nil, nil }
添加configSource¶
func NewConfigSource() core.ConfigSource {
return &fakeSource{
Configuration: make(map[string]interface{}),
}
}
factory, _ := goarchaius.NewConfigFactory(lager.Logger)
err := factory.AddSource(fakeSource.NewConfigSource())
注册evnetListener¶
type EventHandler struct{
Factory goarchaius.ConfigurationFactory
}
func (h EventHandler) Event(e *core.Event) {
value := h.Factory.GetConfigurationByKey(e.Key)
log.Printf("config value after change %s | %s", e.Key, value)
}
factory.RegisterListener(&EventHandler{Factory: factory}, "a*")
Cipher¶
配置¶
AES Cipher 配置¶
1、把so文件拷贝到项目${CHASSIS_HOME}/lib目录下,或者直接放到系统/usr/lib目录下面。优先读取${CHASSIS_HOME}/lib,然后再在/usr/lib下面查找。
2、通过环境变量PAAS_CRYPTO_PATH指定物料路径(root.key, common_shared.key)
3、引入aes包,使用加解密方法
自定义Cipher¶
可通过实现Cipher接口,自定义Cipher
type Cipher interface {
Encrypt(src string) (string, error)
Decrypt(src string) (string, error)
}
例子¶
使用AES Cipher示例¶
import (
_ "github.com/servicecomb/security/plugins/aes"
"testing"
"github.com/servicecomb/security"
"github.com/stretchr/testify/assert"
"log"
)
func TestAESCipher_Decrypt(t *testing.T) {
aesFunc := security.CipherPlugins["aes"]
cipher := aesFunc()
s, err := cipher.Encrypt("tian")
assert.NoError(t, err)
log.Println(s)
a, _ := cipher.Decrypt(s)
assert.Equal(t, "tian", a)
}
自定义Cipher 示例¶
package plain
import "github.com/servicecomb/security"
type DefaultCipher struct {
}
// register self-defined plugin in the cipherPlugin map
func init() {
security.CipherPlugins["default"] = new
}
// define a method of newing a plugin object, and register this method
func new() security.Cipher {
return &DefaultCipher{
}
}
// implement the Encrypt(string) method, to encrypt the clear text
func (c *DefaultCipher)Encrypt(src string) (string, error) {
return src, nil
}
// implement the Decrypt(string) method, to decrypt the cipher text
func (c *DefaultCipher)Decrypt(src string) (string, error) {
return src, nil
}
Protocol¶
如何实现¶
客户端¶
- 实现协议的客户端接口
type Client interface
- 实现以下接口来返回客户端插件
func(...clientOption.Option) Client
- 安装客户端插件
func InstallPlugin(protocol string, f ClientNewFunc)
- 处理链默认自带名为transport的handler,他将根据协议名加载对应的协议客户端,指定协议的方式如下
invoker.Invoke(ctx, "Server", "HelloServer", "SayHello",
&helloworld.HelloRequest{Name: "Peter"},
reply,
core.WithProtocol("grpc"),
)
服务端¶
- 实现协议的Server端
type Server interface
- 修改配置文件以启动协议监听
cse:
protocols:
grpc:
listenAddress: 127.0.0.1:5000
advertiseAddress: 127.0.0.1:5000