etcd学习笔记

博客参考:K8s组件:etcd安装、使用及原理(Linux)

分布式系统架构中对一致性要求很高,etcd就满足了分布式系统中的一致性要求,实现了分布式一致性键值对存储的中间件。etcd完整的集群至少需要3台,这样才能选出一个master和两个node,具有强一致性,常用于注册中心(配置共享和服务发现)。现目前是分布式和云原生下的基础组件,如:k8s。内部使用的raft算法,算法具体内容见我的另外一篇博客,在此描述几个关键点:Leader、Candidate、Follower、任期、心跳探测。脑裂:当网络恢复之后,旧的Leader发现集群中的新Leader的Term比自己大,则自动降级为Follower,并从新Leader处同步数据达成集群数据一致。数据同步流程:当Client发起数据更新请求,请求会先到领袖节点C,节点C会更新日志数据,然后通知群众节点也更新日志,当群众节点更新日志成功后,会返回成功通知给领袖C,至此完成了“提交”操作;当领袖C收到通知后,会更新本地数据,并通知群众也更新本地数据,同时会返回成功通知给Client,至此完成了“应用”操作,如果后续Client又有新的数据更新操作,会重复上述流程。结构定义:从raftLog结构体可以看到,里面有两个存储位置,一个是storage,是保存已经持久化过的日志条目,unstable是保存的尚未持久化的日志条目。storage结构中字段的定义,它实际上就是包含一个WAL来保存日志条目,一个Snapshotter负责保存日志快照的。安装:略简易操作:
etcdctl put myKey "this is etcd"
etcdctl get myKey
etcdctl del myKeyetcd实现服务注册与发现:
1docker pull bitnami/etcd
2docker run -d --name Etcd-server --publish 2379:2379 --env ALLOW_NONE_AUTHENTICATION=yes --env ETCD_ADVERTISE_CLIENT_URLS=http://localhost:2379 bitnami/etcd:latest3)编写proto文件:syntax = "proto3";
option go_package = ".;rpc";
message Empty {
}
message HelloResponse {string hello = 1;
}
message RegisterRequest {string name = 1;string password = 2;
}
message RegisterResponse {string uid = 1;
}
service Server {rpc Hello(Empty) returns(HelloResponse);rpc Register(RegisterRequest) returns(RegisterResponse);
}4)通过这个文件和一个.sh脚本生成server和client代码。生成服务端的etcd.go:package mainimport ("context""fmt"clientv3 "go.etcd.io/etcd/client/v3""go.etcd.io/etcd/client/v3/naming/endpoints""log"
)const etcdUrl = "http://localhost:2379"
const serviceName = "chihuo/server"
const ttl = 10
var etcdClient *clientv3.Clientfunc etcdRegister(addr string) error {log.Printf("etcdRegister %s\b", addr)etcdClient, err := clientv3.NewFromURL(etcdUrl)if err != nil {return err}em, err := endpoints.NewManager(etcdClient, serviceName)if err != nil {return err}lease, _ := etcdClient.Grant(context.TODO(), ttl)err = em.AddEndpoint(context.TODO(), fmt.Sprintf("%s/%s", serviceName, addr), endpoints.Endpoint{Addr: addr}, clientv3.WithLease(lease.ID))if err != nil {return err}//etcdClient.KeepAlive(context.TODO(), lease.ID)alive, err := etcdClient.KeepAlive(context.TODO(), lease.ID)if err != nil {return err}go func() {for {<-alivefmt.Println("etcd server keep alive")}}()return nil
}func etcdUnRegister(addr string) error {log.Printf("etcdUnRegister %s\b", addr)if etcdClient != nil {em, err := endpoints.NewManager(etcdClient, serviceName)if err != nil {return err}err = em.DeleteEndpoint(context.TODO(), fmt.Sprintf("%s/%s", serviceName, addr))if err != nil {return err}return err}return nil
}生成的服务端的server.go:
package mainimport ("context""fmt""go_code/demo01/study/etcd-grpc/server/rpc"
)type Server struct {
}// server.proto文件中 服务提供的方法
// rpc Hello(Empty) returns(HelloResponse);
func (s Server) Hello(ctx context.Context, request *rpc.Empty) (*rpc.HelloResponse, error) {//server.proto定义的HelloResponse中只有一个string参数resp := rpc.HelloResponse{Hello: "hello client."}return &resp, nil
}/*
server.proto文件中定义的格式,因此设置resp.uidmessage RegisterResponse {string uid = 1;}
*/
func (s Server) Register(ctx context.Context, request *rpc.RegisterRequest) (*rpc.RegisterResponse, error) {resp := rpc.RegisterResponse{}resp.Uid = fmt.Sprintf("%s.%s", request.GetName(), request.GetPassword())return &resp, nil
}生成的服务端的main.go:
package mainimport ("context""flag""fmt""go_code/demo01/study/etcd-grpc/server/rpc""google.golang.org/grpc""log""net""os""os/signal""syscall"
)func main() {var port intflag.IntVar(&port, "port", 8001, "port")flag.Parse()addr := fmt.Sprintf("localhost:%d", port)//关闭信号处理ch := make(chan os.Signal, 1)signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL, syscall.SIGHUP, syscall.SIGQUIT)go func() {//开启协程从ch管道中读取,如果有服务停止,则注销etcd中的服务s := <-ch//处理etcd中服务的注销流程etcdUnRegister(addr)if i, ok := s.(syscall.Signal); ok {os.Exit(int(i))} else {os.Exit(0)}}()//注册服务err := etcdRegister(addr)if err != nil {panic(err)}lis, err := net.Listen("tcp", addr)if err != nil {panic(err)}grpcServer := grpc.NewServer(grpc.UnaryInterceptor(UnaryInterceptor()))rpc.RegisterServerServer(grpcServer, Server{})log.Printf("service start port %d\n", port)if err := grpcServer.Serve(lis); err != nil {panic(err)}
}func UnaryInterceptor() grpc.UnaryServerInterceptor {return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {log.Printf("call %s\n", info.FullMethod)resp, err = handler(ctx, req)return resp, err}
}生成的客户端的代码client.go:
package mainimport ("context""fmt"clientv3 "go.etcd.io/etcd/client/v3""go.etcd.io/etcd/client/v3/naming/resolver"rpc2 "go_code/demo01/study/etcd-grpc/client/rpc""google.golang.org/grpc/balancer/roundrobin""google.golang.org/grpc/credentials/insecure""log""time""google.golang.org/grpc"
)const etcdUrl = "http://localhost:2379"
const serviceName = "chihuo/server"func main() {//bd := &ChihuoBuilder{addrs: map[string][]string{"/api": []string{"localhost:8001", "localhost:8002", "localhost:8003"}}}//resolver.Register(bd)//获取etcd客户端etcdClient, err := clientv3.NewFromURL(etcdUrl)if err != nil {panic(err)}etcdResolver, err := resolver.NewBuilder(etcdClient)//通过grpc与服务建立连接conn, err := grpc.Dial(fmt.Sprintf("etcd:///%s", serviceName), grpc.WithResolvers(etcdResolver), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, roundrobin.Name)))if err != nil {fmt.Printf("err: %v", err)return}//rpc2 "go_code/demo01/study/etcd-grpc/client/rpc"//通过连接conn获取ServerClient(与服务器相互通信)ServerClient := rpc2.NewServerClient(conn)for {//通过客户端发起远程调用【请求服务端的Hello方法】,接受服务器的返回结果helloRespone, err := ServerClient.Hello(context.Background(), &rpc2.Empty{})if err != nil {fmt.Printf("err: %v", err)return}log.Println(helloRespone, err)time.Sleep(500 * time.Millisecond)}}5)启动三个server,并向etcd注册服务// 进入server/main.go所在目录
go run . --port 8081
go run . --port 8082
go run . --port 80836)启动一个client端,通过etcd拉取服务
go run .\main.go观察三个server的打印,可以发现,client端的请求时负载均衡的,每个server都有可能被访问到7)我们停止server3,发现client的请求被均衡的分发到server1、server28)进入docker部署的etcd内部,查询所有的key:发现只有8081和8082的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/18673.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Netty-读写原理

归档 GitHub: Netty-读写原理 读原理 参考&#xff1a;选择器-监听-原理 sign_o_002 主要看 NioByteUnsafe#read() 相当于读取底层信道中的字节 io.netty.channel.nio.AbstractNioByteChannel.NioByteUnsafe 下游链处理参考&#xff1a;处理器链-读流程 protected class Ni…

记录——随时更新

姓名&#xff1a;保密 生日&#xff1a;1998.01.09 民族&#xff1a;汉 爱好&#xff1a;吃 以下是我看过的&#xff0c;其中喜欢的&#xff0c;收集起来&#xff0c;以后有喜欢的还会添加&#xff0c;部分遗忘 电视剧 毒牙 非自然死亡(日剧) 校阅部女孩河野悦子(日剧) 失恋…

玩转STM32-直接存储器DMA(详细-慢工出细活)

文章目录 一、DMA介绍1.1 DMA简介1.2 DMA结构 二、DMA相关寄存器&#xff08;了解&#xff09;三、DMA的工作过程&#xff08;掌握&#xff09;四、DMA应用实例4.1 DMA常用库函数4.2 实例程序 一、DMA介绍 1.1 DMA简介 DMA用来提供外设与外设之间、外设与存储器之间、存储器与…

【算法】平衡二叉搜索树的左旋和右旋

树旋转是一种维护平衡树结构的重要操作&#xff0c;主要用于平衡二叉搜索树&#xff08;如AVL树和红黑树&#xff09;。树旋转分为左旋和右旋。 1. 树旋转的定义 左旋 (Left Rotation) 左旋操作将节点及其右子树进行调整&#xff0c;使其右子树的左子节点成为根节点&#xf…

有免费通配符证书吗?哪里可以申请?

市面上的免费SSL证书大多数为单域名证书&#xff0c;如果您的主域名拥有众多子域名&#xff0c;逐一申请单域名SSL证书不太现实&#xff0c;下面为介绍一款永久免费使用的通配符SSL证书申请流程 1 选择免费通配符证书提供商 免费通配符证书申请点击这里直接获取https://www.…

解决移动端使用el-drawer侧边栏展开时触摸滚动的问题

原因分析&#xff1a; 通过 el-drawer 控件实现了底部栏的展示和隐藏&#xff0c;但在移动设备上侧边栏展开时仍然可以通过触摸滑动页面内容&#xff0c;导致用户体验不佳&#xff0c;产生意外的滚动行为。 这是因为在底部栏展开时&#xff0c;未能有效阻止页面内容的触摸滑动…

分布式集群下的业务敏感数据加解密之具体业务解决方案(附代码)

前面的一篇文章中写了敏感数据加解密的通用解决方案&#xff0c;这篇文章来写一下具体的业务如何接入这个方案&#xff0c;业务的接入首要宗旨当然是对业务侵入性要最小&#xff0c;尽可能不影响原生的业务逻辑&#xff0c;说白了就是少改点代码。下面给大家提供一个简单的示例…

机械行业工程设计资质乙级技术负责人要求

机械行业工程设计资质乙级技术负责人的要求可以归纳为以下几点&#xff1a; 一、基本要求 学历&#xff1a;技术负责人应当具有大学本科以上学历。设计经历&#xff1a;技术负责人需要具有10年以上的设计经历。 二、项目经历要求 大型项目经验&#xff1a;技术负责人需要主…

redis 如何获取所有key的信息及值,相关过期时间查询

简单粗暴获取所有key keys * 另一种方式&#xff1a; scan 0 切换数据库&#xff1a; select db Map类型 获取map的数量 hlen key 获取map所有的数据 hvals key 或者 hgetall key 整个哈希表的过期时间&#xff1a; EXPIRE your_hash_key 3600 # 设置哈希表 yo…

前端渲染页面的原理

之前一直不愿意写一篇关于原理的&#xff0c;因为说起来实在是太繁杂&#xff0c;要写得细&#xff0c;码字梳理&#xff0c;计算下来起码都要差不多三周。以前一直躲避这个事情&#xff0c;现在反正有时间&#xff0c;为了不荒废自己&#xff0c;那就从头捋一遍。也方便自己后…

整理好了!2024年最常见 20 道 Rocket MQ面试题(四)

上一篇地址&#xff1a;整理好了&#xff01;2024年最常见 20 道 Rocket MQ面试题&#xff08;三&#xff09;-CSDN博客 七、RocketMQ消费模式有几种&#xff1f; RocketMQ 提供了两种主要的消费模式&#xff0c;分别是&#xff1a; 集群消费模式&#xff08;Clustering&…

HFish蜜罐实践:网络安全防御的主动出击

引言 随着网络攻击手段的不断演进&#xff0c;传统的被动防御策略已难以应对复杂多变的安全威胁。HFish蜜罐作为一种主动防御工具&#xff0c;通过模拟易受攻击的服务&#xff0c;吸引攻击者&#xff0c;不仅能有效捕获攻击行为&#xff0c;还能为安全分析和溯源提供宝贵信息。…

数据分析项目有哪些实施流程?揭示从数据准备到解决方案全过程

在当今数据驱动的商业环境中&#xff0c;数据分析项目的成功实施对于企业洞察市场趋势、优化产品服务、提升用户体验以及增强竞争力具有至关重要的作用。特别是对于直播类应用软件这样的快速增长领域&#xff0c;如何通过数据分析来扩大付费用户基础、提高用户留存率&#xff0…

音视频开发10 FFmpeg 内存模型-AVPacket, AVFrame

从现有的 Packet 拷贝一个新 Packet 的时候&#xff0c;有两种情况&#xff1a; • ①两个 Packet 的 buf 引用的是 同一数据缓存空间 &#xff0c;这时 候要注意数据缓存空间的释放问题&#xff1b; • ②两个 Packet 的 buf 引用不同的数据缓存空间 &#xff0c;每个 Pac…

矩阵结构下需要的文化导向

在产品研发与产品管理过程中&#xff0c;如何有效运行矩阵结构一直是企业面临的一大难题&#xff0c;尤其是在中国式官本位文化很强势的文化传统下。但是&#xff0c;这个难题是完全可以解决的&#xff0c;汉捷咨询在国内就已经帮助200多家企业建立了有效的矩阵结构。基于汉捷的…

2024年华为OD机试真题-项目排期-C++-OD统一考试(C卷D卷)

2024年OD统一考试(D卷)完整题库:华为OD机试2024年最新题库(Python、JAVA、C++合集) 题目描述: 项目组共有N个开发人员,项目经理接到了M个独立的需求,每个需求的工作量不同,且每个需求只能由一个开发人员独立完成,不能多人合作。假定各个需求直接无任何先后依赖关系,…

D2Admin:企业中后台产品前端集成方案的探索与实践

D2Admin&#xff1a;企业中后台产品前端集成方案的探索与实践 摘要&#xff1a;随着企业信息化建设的不断深入&#xff0c;中后台管理系统的前端技术选型与集成方案成为了关键。D2Admin作为一款完全开源免费的前端集成方案&#xff0c;通过采用最新的前端技术栈&#xff0c;提…

惠海半导体 30V-60V-100V-150VMOS管 打火机、加湿器NMOS管 高耐压

MOS管的工作原理 MOS管&#xff0c;即金属-氧化物-半导体场效应晶体管&#xff0c;是一种重要的电子元件&#xff0c;在电路中起着关键的作用。其工作原理主要基于半导体材料的特性以及电场对电荷的控制。 首先&#xff0c;MOS管的基本结构包括源极、栅极和漏极。其中&#xf…

我国赤泥年产量庞大 政策引导下赤泥绿色利用率将不断提升

我国赤泥年产量庞大 政策引导下赤泥绿色利用率将不断提升 赤泥是指从铝土矿中提炼氧化铝后产生的强碱性工业固体废渣&#xff0c;由于含大量氧化铁&#xff0c;表面呈现红色&#xff0c;而得名赤泥。   赤泥通常包含氧化铝、氧化铁、二氧化硅、氧化钙、碱金属及其他微量元素&…