目前市面上常见的服务治理有consul,etcd,zookeeper,euerka,咱们须要根据本身的服务特色选择本身相对合适的服务治理工具。java
Feature | Consul | zookeeper | etcd | euerka |
---|---|---|---|---|
服务健康检查 | 服务状态,内存,硬盘等 | (弱)长链接,keepalive | 链接心跳 | 可配支持 |
多数据中心 | 支持 | — | — | — |
kv存储服务 | 支持 | 支持 | 支持 | — |
一致性 | raft | paxos | raft | — |
cap | ca | cp | cp | ap |
使用接口(多语言能力) | 支持http和dns | 客户端 | http/grpc | http(sidecar) |
watch支持 | 全量/支持long polling | 支持 | 支持 long polling | 支持 long polling/大部分增量 |
自身监控 | metrics | — | metrics | metrics |
安全 | acl /https | acl | https支持(弱) | — |
spring cloud集成 | 已支持 | 已支持 | 已支持 | 已支持 |
调研一个工具须要看到其优势,更须要看到其缺点,当服务优势大于自身业务需求缺点,且缺点有对应的解决方案时,咱们能够倾向于考虑。node
euerka 听说如今已中止维护,决定不考虑使用。nginx
zookeeper 为java开发的,须要java环境,相对比较复杂,优先级较低。git
etcd 与consul为go开发,部署简单,功能相对更符合自身业务的需求。github
consul监控检查更为丰富,支持多数据中心,webui查看等,配合consul-template实现nginx动态负载均衡等特色更符合自身业务需求,由于决定选用consul做为业务的服务治理工具。
web
使用consul,其主要有四大特性:spring
1. 服务发现:利用服务注册,服务发现功能来实现服务治理。bootstrap
2. 健康检查:利用consul注册的检查检查函数或脚原本判断服务是否健康,若服务不存在则从注册中心移除该服务,减小故障服务请求。api
3. k/v数据存储:存储kv数据,能够做为服务配置中心来使用。安全
4. 多数据中心:能够创建多个consul集群经过inter网络进行互联,进一步保证数据可用性。
本人也是刚开始学习consul,感受使用consul主要也就是两大做用,服务注册发现,配置共享。
如今开始学习consul:
启动单机consul:consul agent -server -bootstrap-expect=1 -data-dir=data -node=consul -bind=x172.16.242.129-ui -client=0.0.0.0
咱们可已经过consul --help 修改一些配置信息,好比集群个数,绑定地址,数据存放地址,配置文件地址,加入集群等配置
启动consul后咱们能够经过web查看consul运行情况:http://172.16.242.129:8500/ui/dc1/nodes
服务启动后,如今开始测试consul的第一个功能:服务注册发现,本人使用的为go语言, 下面主要为服务注册,发现的一个demo, 须要注意的是,根据自身的实际配置去修改consul的地址信息和要注册服务的地址信息
package main import ( "github.com/gin-gonic/gin" consulapi "github.com/hashicorp/consul/api" "net/http" "fmt" "log" ) func main() { r := gin.Default() // consul健康检查回调函数 r.GET("/", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "ok", }) }) // 注册服务到consul ConsulRegister() // 从consul中发现服务 ConsulFindServer() // 取消consul注册的服务 //ConsulDeRegister() http.ListenAndServe(":8081", r) } // 注册服务到consul func ConsulRegister() { // 建立链接consul服务配置 config := consulapi.DefaultConfig() config.Address = "172.16.242.129:8500" client, err := consulapi.NewClient(config) if err != nil { log.Fatal("consul client error : ", err) } // 建立注册到consul的服务到 registration := new(consulapi.AgentServiceRegistration) registration.ID = "111" registration.Name = "go-consul-test" registration.Port = 8081 registration.Tags = []string{"go-consul-test"} registration.Address = "10.13.153.128" // 增长consul健康检查回调函数 check := new(consulapi.AgentServiceCheck) check.HTTP = fmt.Sprintf("http://%s:%d", registration.Address, registration.Port) check.Timeout = "5s" check.Interval = "5s" check.DeregisterCriticalServiceAfter = "30s" // 故障检查失败30s后 consul自动将注册服务删除 registration.Check = check // 注册服务到consul err = client.Agent().ServiceRegister(registration) } // 取消consul注册的服务 func ConsulDeRegister() { // 建立链接consul服务配置 config := consulapi.DefaultConfig() config.Address = "172.16.242.129:8500" client, err := consulapi.NewClient(config) if err != nil { log.Fatal("consul client error : ", err) } client.Agent().ServiceDeregister("111") } // 从consul中发现服务 func ConsulFindServer() { // 建立链接consul服务配置 config := consulapi.DefaultConfig() config.Address = "172.16.242.129:8500" client, err := consulapi.NewClient(config) if err != nil { log.Fatal("consul client error : ", err) } // 获取全部service services, _ := client.Agent().Services() for _, value := range services{ fmt.Println(value.Address) fmt.Println(value.Port) } fmt.Println("=================================") // 获取指定service service, _, err := client.Agent().Service("111", nil) if err == nil{ fmt.Println(service.Address) fmt.Println(service.Port) } } func ConsulCheckHeath() { // 建立链接consul服务配置 config := consulapi.DefaultConfig() config.Address = "172.16.242.129:8500" client, err := consulapi.NewClient(config) if err != nil { log.Fatal("consul client error : ", err) } // 健康检查 a, b, _ := client.Agent().AgentHealthServiceByID("111") fmt.Println(a) fmt.Println(b) } func ConsulKVTest() { // 建立链接consul服务配置 config := consulapi.DefaultConfig() config.Address = "172.16.242.129:8500" client, err := consulapi.NewClient(config) if err != nil { log.Fatal("consul client error : ", err) } // KV, put值 values := "test" key := "go-consul-test/172.16.242.129:8100" client.KV().Put(&consulapi.KVPair{Key:key, Flags:0, Value: []byte(values)}, nil) // KV get值 data, _, _ := client.KV().Get(key, nil) fmt.Println(string(data.Value)) // KV list datas, _ , _:= client.KV().List("go", nil) for _ , value := range datas{ fmt.Println(value) } keys, _ , _ := client.KV().Keys("go", "", nil) fmt.Println(keys) }
咱们可根据上述功能去实现一个服务注册,服务发现,配置共享的功能,咱们能够围绕这些根据自身业务需求进行灵活的变更,我的想法:根据此功能专门作一个服务管理的模块,客户端注册服务到服务模块,服务管理去提供其余模块的服务发现的功能,同时跟监控结合,当服务不可用时,或服务不存在时,经过监控通知相关人员,咱们也可使用页面跟咱们服务管理结合,经过前台服务录入形式进行注册服务等等。
假如公司服务使用nginx负载均衡的话,咱们可与consul和consul-template结合,动态生成nginx的配置文件,而后从新reload nginx,实现nginx的动态负载均衡。
固然还有其余方式实现nginx的动态负载均衡,如使用nginx-upsync-module和consul,openResty的lua脚本实现nginx动态负载均衡。