为什么?

为什么会有服务注册和服务发现?在它以前我们是怎么做的?

举个例子:

比如我们做MySQL读写分离,就在本地配置一个文件,然后程序读取这个配置文件里的数据进行数据库读写分离的设置。

但是随着业务发展迅速,业务模块越来越多,数据也越来越多,MySQL数据库也越来越多,需要读取MySQL服务的业务模块也越来越多。每次增加MySQL实例,每个业务模块都要手动去写一次本地配置。

想一想这里有什么问题?可以改进吗?

每次手动写配置,是不是很浪费时间,能不能做到自动一些?能不能做到只配置一次,业务模块就可以自动读取更新后的配置?于是我们就开始动脑筋了,就开始琢磨解决的办法了。

在计算机领域,没有什么是增加一个中间层解决不了的问题,有的话,“那就在增加一层”,对,最后那句是我说的- -!。

于是就想:能不能把所有的配置集中存放,程序模块的配置更新由各个程序自动的来配置中心读取,更新配置。而不是每次手动的增加每个程序模块的配置。

于是我们就增加了一个“中间层”- 配置中心,集中存储,管理分散在各个程序中的配置。配置中心就向外面提供配置服务。

不过Etcd应该属于服务配置中心,属于更加细化的配置中心。

还有更加专注的配置中心,比如Apollo,Nacos,disconf等等。

是什么?

什么是服务注册和服务发现?

  • 服务注册 :就是向配置中心注册一个配置的功能。
  • 服务发现:就是发现配置中心增加、修改、删除了配置的功能。发现配置的异动情况,让更新配置。

会遇到哪些问题?

服务发现和服务注册怎么解决问题以及会遇到哪些问题?

  1. 怎么标识一个服务?

    在计算机里,标识一个计算机中运行的程序可以用ip+端口形式来标识,配置服务也可以用这种方式。
  2. 怎么发现一个配置服务的异动?

    配置更新,删除(下线),增加了,怎么发现配置的这些异动情况?一种是长轮询,一种是心跳,每隔多长时间检查一次,还有发布订阅模式。
  3. 服务是否可用?

    这种就要检查服务的可用情况了,一般是健康检查。

... ...

等等问题

怎么解决

业内主要的几个解决方案ZooKeeper,Etcd,Consul ,等。我们介绍etcd的使用。

etcd介绍

etcd是CoreOS团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库。etcd内部采用raft协议作为一致性算法,etcd基于Go语言实现。

前面博客文章也有一些它的使用情况。

它是一个kv键值的数据库:

所以可以存储数据,那么就可以存储配置数据。

它有watch功能:

所以可以发现配置的异动情况。变化时候可以起到通知作用。

它有key TTL功能:

etcdv3可以通过lease租约,设置服务生存周期TTL,让key自动过期,通过KeepAlive定期续租,避免过期。

当然,它还可以做分布式锁、分布式队列等等其他功能,你可以google去学习它的其他功能。

例子

  • 注册服务和获取服务
// PutValueDemo 插入值demo,配置里面put相当于注册一个服务(服务注册),get相当于获取一个服务(服务发现)
func (demo EtcdDemo) PutValueDemo(client *clientv3.Client) {
fmt.Println("\n...put value demo...")
fmt.Println("put value: ", demo)
_, err := demo.PutValue(client)
if err != nil {
fmt.Println("failed to put value, err: ", err)
return
} getVal, err := demo.GetValue(client)
if err != nil {
fmt.Println("get val err: ", err)
return
}
fmt.Println("get key:",string(getVal.Kvs[0].Key),",value:", string(getVal.Kvs[0].Value), ", Revision: ", getVal.Header.Revision)
}

如果你单独在main函数里测试PutValueDemo(),

client, err := clientv3.New(clientv3.Config{
Endpoints: []string{"127.0.0.1:2379"},
DialTimeout: time.Second * 5,
})
if err != nil {
fmt.Println("failed to connect etcd: ", err)
return
}
defer client.Close() demo := EtcdDemo{Key: "test1", Val: "val1"}
demo.PutValueDemo(client)

你会发现:

Revision 的值,每次都是增加的。

get val: val1 ,key: test1 , Revision:  1

get val: val1 ,key: test1 , Revision:  2

这也是etcd的一个特性,可以用个来做分布式锁。

  • watch 监测服务变化
// watchDemo 监听key的变化
func (demo EtcdDemo) WatchDemo(client *clientv3.Client) {
fmt.Println("\n...watch demo...")
stopChan := make(chan interface{}) // 是否停止信号
go func() {
watchChan := client.Watch(context.TODO(), demo.Key, clientv3.WithPrefix())
for {
select {
case result := <- watchChan:
for _, event := range result.Events {
fmt.Printf("%s %q : %q\n", event.Type, event.Kv.Key, event.Kv.Value)
}
case <-stopChan:
fmt.Println("stop watching...")
return
}
}
}() for i := 0; i < 5; i++ {
var demo EtcdDemo
demo.Key = fmt.Sprintf("key_%02d", i)
demo.Val = strconv.Itoa(i)
demo.PutValue(client)
}
time.Sleep(time.Second * 1) stopChan <- 1 //停止watch,在插入就不会监听到了
}

运行后:

...watch demo...

putResp Revision:  13

PUT "key_00" : "0"

PUT "key_01" : "1"

putResp Revision:  14

PUT "key_02" : "2"

putResp Revision:  15

PUT "key_03" : "3"

putResp Revision:  16

PUT "key_04" : "4"

putResp Revision:  17

stop watching...

Revision单调递增变化的。

watch 可以监测到put变化的情况。

  • 租约lease
// LeaseDemo 租约
func (demo EtcdDemo) LeaseDemo(client *clientv3.Client) {
fmt.Println("\n...lease demo...") lease, err := client.Grant(context.TODO(), 2) //创建一个租约
if err != nil {
fmt.Println("grant err: ", err)
return
} testKey := "testleasekey"
// 给这个testkey一个 2秒的TTL租约
client.Put(context.TODO(), testKey, "testvalue", clientv3.WithLease(lease.ID))
getVal, err := client.Get(context.TODO(), testKey)
if err != nil {
fmt.Println("get val err: ", err)
return
}
vallen := len(getVal.Kvs)
fmt.Println("before time sleep, val len: ", vallen) fmt.Println("sleep 4 seconds")
time.Sleep(4 * time.Second) //睡眠4秒,让租约过期 getVal, _ = client.Get(context.TODO(), testKey)
vallen = len(getVal.Kvs)
fmt.Println("after 4 seconds, val len: ", vallen)
}

运行:

...lease demo...

before time sleep, val len:  1

sleep 4 seconds

after 4 seconds, val len:  0 //这里租约到期,删掉了这个key和val

完整代码在这里github

参考

golang微服务实践:服务注册与服务发现 - Etcd的使用的更多相关文章

  1. .Net微服务实践(五)[服务发现]:Consul介绍和环境搭建

    目录 介绍 服务发现 健康检查.键值存储和数据中心 架构 Consul模式 环境安装 HTTP API 和Command CLI 示例API介绍 最后 在上篇.Net微服务实践(四)[网关]:Ocel ...

  2. .Net微服务实践(四)[网关]:Ocelot限流熔断、缓存以及负载均衡

    目录 限流 熔断 缓存 Header转化 HTTP方法转换 负载均衡 注入/重写中间件 后台管理 最后 在上篇.Net微服务实践(三)[网关]:Ocelot配置路由和请求聚合中我们介绍了Ocelot的 ...

  3. Golang微服务实践

    背景 在之前的文章<漫谈微服务>我已经简单的介绍过微服务,微服务特性是轻量级跨平台和跨语言的服务,也列举了比较了集中微服务通信的手段的利弊,本文将通过RPC通信的方式实现一个增删查Redi ...

  4. Node.js微服务实践(一)

    什么是微服务 微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成.系统中的各个微服务可被独立部署,各个微服务之间是松耦合的.每个微服务仅关注于完成一件任务并很好地完成该任务.在所有情况下 ...

  5. 【GoLang】golang 微服务框架 介绍

    原文如下: rpcx是一个类似阿里巴巴 Dubbo 和微博 Motan 的分布式的RPC服务框架,基于Golang net/rpc实现. 谈起分布式的RPC框架,比较出名的是阿里巴巴的dubbo,包括 ...

  6. 【GoLang】GoLang 微服务、开源库等参考资料

    参考资料: GoLang书籍: https://github.com/dariubs/GoBooksGo名库: https://github.com/Unknwon/go-rock-libraries ...

  7. ASP.NET Core OceLot 微服务实践

    1.OceLot中间件介绍 在传统的BS应用中,随着业务需求的快速发展变化,需求不断增长,迫切需要一种更加快速高效的软件交付方式.微服务可以弥补单体应用不足,是一种更加快速高效软件架构风格.单体应用被 ...

  8. QCon技术干货:个推基于Docker和Kubernetes的微服务实践

    2016年伊始,Docker无比兴盛,如今Kubernetes万人瞩目.在这个无比需要创新与速度的时代,由容器.微服务.DevOps构成的云原生席卷整个IT界.在近期举办的QCon全球软件开发大会上, ...

  9. 基于SpringCloud的微服务实践

    微服务不同于单一架构应用, 是典型的分布式场景, 各服务之间通过IPC进行通信. 实现微服务的过程中, 我们需要解决以下问题: 服务注册和服务发现. 根据应用选择合适的通信协议和数据协议. 例如可以选 ...

  10. .NET CORE微服务实践

    .NET CORE微服务实践 https://www.cnblogs.com/zengqinglei/p/9570343.html .NET CORE 实践部署架构图 实践源码:https://git ...

随机推荐

  1. [转帖]【SOP】最佳实践之 TiDB 业务写变慢分析

    https://zhuanlan.zhihu.com/p/647831844 前言 在日常业务使用或运维管理 TiDB 的过程中,每个开发人员或数据库管理员都或多或少遇到过 SQL 变慢的问题.这类问 ...

  2. [转帖]使用 mydumper/loader 全量导入数据

    数据迁移 mydumper 是一个更强大的数据迁移工具,具体可以参考 https://github.com/maxbube/mydumper. 我们使用 mydumper 从 MySQL 导出数据,然 ...

  3. [转帖]dd - Linux世界中的搬运工

    <存储工具系列文章>主要介绍存储相关的测试和调试工具,包括不限于dd.fio.vdbench.iozone.iometer.cosbench等性能负载工具,及strace等调试工具. dd ...

  4. [转帖]Tcpdump抓包命令

    tcpdump和ethereal可以用来获取和分析网络通讯活动,他们都是使用libpcap库来捕获网络封包的. ​在混杂模式下他们可以监控网络适配器的所有通讯活动并捕获网卡所接收的所有帧. ​要想设置 ...

  5. [转帖]ARMv8架构概述、相关技术文档以及ARMv8处理器简介

    ARMv8架构 文章目录 ARMv8架构 参考文档 ARMv8架构的概述 从32位到64位的变化The changes from 32 bits to 64 bits 1,Larger registe ...

  6. vue/cli3.0相对路径打包

    在项目下新增vue.config.js文件 module.exports={ productionSourceMap: false, publicPath: process.env.NODE_ENV ...

  7. STM32CubeMX教程27 SDIO - 读写SD卡

    1.准备材料 正点原子stm32f407探索者开发板V2.4 STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) ST-LINK/V2驱动 ...

  8. C#不显示小数点0部分

    c#去掉小数点后的无效0 ,保留指定位数的小数,比如10.0显示成10,小数部分会四舍五入 float value = 0.0500f; value.ToString("0.##" ...

  9. win10安装wget,从此可以更快的下载文件 and windows10 下 zip命令行参数详解

    1.win10安装wget 1.1安装下载 GNU Wget 1.21.3 for Windows 依次如下: 2.将下载好的wget.exe放到 C:/windows/system32文件夹下 也可 ...

  10. C/C++ 提权与强制卸载DLL

    权限提升 #include <Windows.h> #include <stdio.h> BOOL SetPrivilege(LPCTSTR lpszPrivilege, BO ...