热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【微服务】Etcd实现服务器注册和发现|Etcd、Eureka、Consul、Zookeeper比较

目录Etcd、Eureka、Consul、Zookeeper的比较Etcd服务注册与发现的必要:etcd简介etcd分布式一致性算法etcd应用场景et

目录

Etcd、Eureka、Consul、Zookeeper 的比较

Etcd

服务注册与发现的必要:

etcd简介

etcd分布式一致性算法

etcd应用场景

etcd安装

服务注册与发现实例(go语言)

服务注册的简单实现1:

服务注册的简单实现2:

都是key-value存储,redis 可以代替 etcd吗?

为什么选择Etcd而不选择Zookeeper

附录

附录1:etcd基本使用(数据库CURD和持久化等)

数据库操作

非数据库操作

附录2:etcd应用场景

5.1服务发现

5.2消息发布与订阅

5.3负载均衡

5.4分布式通知与协调

5.5分布式锁

5.6分布式队列

5.7集群监控与LEADER竞选

附录3:ETCD 词汇表



Etcd、Eureka、Consul、Zookeeper 的比较

 etcd除了受到Zookeeper与doozer启发而催生的项目,还拥有与之类似的功能外,更具有以下4个特点:

  • 简单:基于HTTP+JSON的API让你用curl命令就可以轻松使用。
  • 安全:可选SSL客户认证机制。
  • 快速:每个实例每秒支持一千次写操作。
  • 可信:使用Raft算法充分实现了分布式。

至于为什么不用zookeeper或者eureka等,除了根据项目考虑之外,就看个人喜好了,如果有哪位大佬知道更多内容,麻烦也在留言区告知小编一下,万分感谢!

以下是常用的服务发现产品之间的比较:

FeatureConsulzookeeperetcdeuerka
服务健康检查服务状态,内存,硬盘等(弱)长连接,keepalive连接心跳可配支持
多数据中心支持
kv存储服务支持支持支持
一致性raftpaxosraft
capcacpcpap
使用接口(多语言能力)支持http和dns客户端http/grpchttp(sidecar)
watch支持全量/支持long polling支持支持 long polling支持 long polling/大部分增量
自身监控metricsmetricsmetrics
安全acl /httpsaclhttps支持(弱)
spring cloud集成已支持已支持已支持已支持

 

 

 

https://blog.csdn.net/qq_34395857/article/details/89212566 

zookeeper 实现一个简单的服务注册与发现:https://www.cnblogs.com/chinxi/p/12994321.html

Etcd

服务注册与发现的必要:

讲一个很简单的场景,一般服务端架构最前面是 一台网关 ,网关后面是 n 台运行着一样的 服务 的机器。 客户端一般就是访问网关 ,然后 网关 就把流量 转发到 后面的 服务器上。那么我们来考虑这么一个问题,后面 服务器 信息处理不过来的时候,我们需要加机器。最low的方法就是 加上一台服务器,然后 修改网关服务器的配置表 加上 新加的 服务器的IP 和端口,然后重启网关。还有就是 当 后面的 服务器万一 down 了,网关是不知道的,还会把 流量转发到 down的 服务器上,造成 服务的不可用。

 

要解决上面这个问题就需要 [服务注册与发现] 如etcd 这类产品了,etcd 是一个 分布式 的高一致性的 键值存储系统。我们每次网关 后面加一个服务,只需要向etcd 注册 该服务(其实就是 存一个值)然后向etcd 发送心跳,当etcd 没有检测到心跳就会 把这个键值对 删了(这整个动作是etcd里的租约模式),网关那边 就只需要 watch 这个 key ,就能够知道 所有服务的所有动态了。



链接:https://www.jianshu.com/p/7c0d23c818a5

etcd简介

  etcd是一个开源的分布式键值对存储工具。在每个coreos节点上面运行的etcd,共同组建了coreos集群的共享数据总线。etcd可以保证coreos集群的稳定,可靠。当集群网络出现动荡,或者当前master节点出现异常时,etcd可以优雅的进行master节点的选举工作,同时恢复集群中损失的数据。

       etcd为分布式系统提供可靠的键值存储。可以用在系统的降级处理、服务的发现、配置的共享等多个方面。而Etcd的底层数据存储上与一个NoSQL的数据库基本没有差别,但更准确的说法说是一个高可用的键值存储系统,并且etcd提供了TTL和订阅与发布(Subscript/Public)功能。与一般的NoSQL数据库不同,Etcd在设计的初衷主要用于是共享配置和服务发现(比noSQL 开发了一些面向服务发现的接口,提供面向服务发现的逻辑和协议),它的灵感来自于ZooKeeper和Doozer。(Etcd是CoreOS生态系统中处于连接各个节点通信和支撑集群服务协同运作的核心地位的模)

etcd有如下的特点:

  • 简单:安装配置简单,API丰富(支持http,jason),提供HTTP API进行交互,使用也很简单
  • 安全:支持SSL证书验证
  • 快速:根据官方提供的benchmark数据,单实例支持每秒2k+读操作
  • 可靠:采用raft算法,实现分布式系统数据的可用性和一致性

     通过http轮询,监听网络变化 
 

etcd分布式一致性算法

etcd使用的分布式一致性算法是Raft协议:

https://www.bilibili.com/video/BV1yJ411P76f?from=search&seid=5674215994201741363

 

etcd应用场景

etcd应用场景有服务发现、消息发布与订阅、负载均衡、分布式通知与协调、分布式锁、分布式队列、集群监控与LEADER竞选,详细见文章末尾附录。

etcd应用比较多的应用场景是用于服务发现,服务发现(Service Discovery)要解决的是分布式系统中最常见的问题之一,即在同一个分布式集群中的进程或服务如何才能找到对方并建立连接。

从本质上说,服务发现就是要了解集群中是否有进程在监听upd或者tcp端口,并且通过名字就可以进行查找和链接。

解决服务发现的问题,需要下面三大支柱,缺一不可。

  • 一个强一致性、高可用的服务存储目录。

基于Ralf算法的etcd天生就是这样一个强一致性、高可用的服务存储目录。

  • 一种注册服务和健康服务健康状况的机制。

用户可以在etcd中注册服务,并且对注册的服务配置key TTL,定时保持服务的心跳以达到监控健康状态的效果。

  • 一种查找和连接服务的机制。

通过在etcd指定的主题下注册的服务也能在对应的主题下查找到。

(还可以在每个服务机器上都部署一个proxy模式的etcd,这样就可以确保访问etcd集群的服务都能够互相连接。)


链接:https://www.jianshu.com/p/f68028682192

 

etcd安装

etcd在生产环境中一般推荐集群方式部署。本文定位为入门,主要讲讲单节点安装和基本使用。

etcd目前默认使用2379端口提供HTTP API服务,2380端口和peer通信(这两个端口已经被IANA官方预留给etcd);在之前的版本中可能会分别使用4001和7001,在使用的过程中需要注意这个区别。

因为etcd是go语言编写的,所以设备上应该先部署goland环境:https://blog.csdn.net/bandaoyu/article/details/107721973

安装好goland环境后,安装只需要下载对应的二进制文件,并放到合适的路径就行。

下载软件包

$ wget https://github.com/coreos/etcd/releases/download/v3.1.5/etcd-v3.1.5-linux-amd64.tar.gz
$ tar xzvf etcd-v3.1.5-linux-amd64.tar.gz
$ mv etcd-v3.1.5-linux-amd64 /opt/etcd

解压后是一些文档和两个二进制文件etcd和etcdctl。etcd是server端,etcdctl是客户端。

$ ls /opt/etcd/etcd-v3.1.5-linux-amd64/Documentation etcd etcdctl README-etcdctl.md README.md READMEv2-etcdctl.md

如果在测试环境,启动一个单节点的etcd服务,只需要运行etcd命令就行。

$ cd /opt/etcd/etcd-v3.1.5-linux-amd64/
$ ./etcd

输出: 

$ ./etcd
2017-04-10 11:46:44.772465 I | etcdmain: etcd Version: 3.1.5
2017-04-10 11:46:44.772512 I | etcdmain: Git SHA: 20490ca
2017-04-10 11:46:44.772607 I | etcdmain: Go Version: go1.7.5
2017-04-10 11:46:44.772756 I | etcdmain: Go OS/Arch: linux/amd64
2017-04-10 11:46:44.772817 I | etcdmain: setting maximum number of CPUs to 2, total number of available CPUs is 2
2017-04-10 11:46:44.772851 W | etcdmain: no data-dir provided, using default data-dir ./default.etcd
2017-04-10 11:46:44.773298 I | embed: listening for peers on http://localhost:2380
2017-04-10 11:46:44.773583 I | embed: listening for client requests on localhost:2379
2017-04-10 11:46:44.775967 I | etcdserver: name = default
2017-04-10 11:46:44.775993 I | etcdserver: data dir = default.etcd
2017-04-10 11:46:44.776167 I | etcdserver: member dir = default.etcd/member
2017-04-10 11:46:44.776253 I | etcdserver: heartbeat = 100ms
2017-04-10 11:46:44.776264 I | etcdserver: election = 1000ms
2017-04-10 11:46:44.776270 I | etcdserver: snapshot count = 10000
2017-04-10 11:46:44.776285 I | etcdserver: advertise client URLs = http://localhost:2379
2017-04-10 11:46:44.776293 I | etcdserver: initial advertise peer URLs = http://localhost:2380
2017-04-10 11:46:44.776306 I | etcdserver: initial cluster = default=http://localhost:2380
2017-04-10 11:46:44.781171 I | etcdserver: starting member 8e9e05c52164694d in cluster cdf818194e3a8c32
2017-04-10 11:46:44.781323 I | raft: 8e9e05c52164694d became follower at term 0
2017-04-10 11:46:44.781351 I | raft: newRaft 8e9e05c52164694d [peers: [], term: 0, commit: 0, applied: 0, lastindex: 0, lastterm: 0]
2017-04-10 11:46:44.781883 I | raft: 8e9e05c52164694d became follower at term 1
2017-04-10 11:46:44.795542 I | etcdserver: starting server... [version: 3.1.5, cluster version: to_be_decided]
2017-04-10 11:46:44.796453 I | etcdserver/membership: added member 8e9e05c52164694d [http://localhost:2380] to cluster cdf818194e3a8c32
2017-04-10 11:46:45.083350 I | raft: 8e9e05c52164694d is starting a new election at term 1
2017-04-10 11:46:45.083494 I | raft: 8e9e05c52164694d became candidate at term 2
2017-04-10 11:46:45.083520 I | raft: 8e9e05c52164694d received MsgVoteResp from 8e9e05c52164694d at term 2
2017-04-10 11:46:45.083598 I | raft: 8e9e05c52164694d became leader at term 2
2017-04-10 11:46:45.083654 I | raft: raft.node: 8e9e05c52164694d elected leader 8e9e05c52164694d at term 2
2017-04-10 11:46:45.084544 I | etcdserver: published {Name:default ClientURLs:[http://localhost:2379]} to cluster cdf818194e3a8c32
2017-04-10 11:46:45.084638 I | etcdserver: setting up the initial cluster version to 3.1
2017-04-10 11:46:45.084857 I | embed: ready to serve client requests
2017-04-10 11:46:45.085918 E | etcdmain: forgot to set Type=notify in systemd service file?
2017-04-10 11:46:45.086668 N | embed: serving insecure client requests on 127.0.0.1:2379, this is strongly discouraged!
2017-04-10 11:46:45.087004 N | etcdserver/membership: set the initial cluster version to 3.1
2017-04-10 11:46:45.087195 I | etcdserver/api: enabled capabilities for version 3.1

 

从上面的输出中,我们可以看到很多信息。以下是几个比较重要的信息:

  • name表示节点名称,默认为default。
  • data-dir 保存日志和快照的目录,默认为当前工作目录default.etcd/目录下。
  • 在http://localhost:2380和集群中其他节点通信。
  • 在http://localhost:2379提供HTTP API服务,供客户端交互。
  • heartbeat为100ms,该参数的作用是leader多久发送一次心跳到
  • followers,默认值是100ms。
  • election为1000ms,该参数的作用是重新投票的超时时间,如果follow在该+ 时间间隔没有收到心跳包,会触发重新投票,默认为1000ms。
  • snapshot count为10000,该参数的作用是指定有多少事务被提交时,触发+ 截取快照保存到磁盘。
  • 集群和每个节点都会生成一个uuid。
  • 启动的时候会运行raft,选举出leader。
  • 上面的方法只是简单的启动一个etcd服务,但要长期运行的话,还是做成一个sys服务好一些。下面将以systemd为例,介绍如何建立一个etcd服务。

创建systemd服务(使得可以用 systemctl start etcd 命令启动、控制etcd)

  • 设定etcd配置文件

建立相关目录

$ mkdir -p /var/lib/etcd/
$ mkdir -p /opt/etcd/config/

创建etcd配置文件

$ cat <#节点名称
ETCD_NAME&#61;$(hostname -s)
#数据存放位置
ETCD_DATA_DIR&#61;/var/lib/etcd
EOF

创建systemd配置文件

$ cat <Description&#61;Etcd Server
Documentation&#61;https://github.com/coreos/etcd
After&#61;network.target[Service]
User&#61;root
Type&#61;notify
EnvironmentFile&#61;-/opt/etcd/config/etcd.conf
ExecStart&#61;/opt/etcd/etcd
Restart&#61;on-failure
RestartSec&#61;10s
LimitNOFILE&#61;40000[Install]
WantedBy&#61;multi-user.target
EOF

启动etcd

$ systemctl daemon-reload && systemctl enable etcd && systemctl start etcd

摘自&#xff1a;https://www.jianshu.com/p/f68028682192

验证安装成功

 

将etcd的路径加入到环境变量PATH中&#xff08;这样就可以直接从命令行使用etcd&#xff09;

#通过修改profile文件:
vim /etc/profile在profile最后添加下面的语句&#xff1a;export PATH&#61;/opt/etcd:$PATH再执行下面命令使得配置文件生效&#xff1a;source /etc/profile

查看版本

$ etcd --version
etcd Version: 3.1.5
Git SHA: 20490ca
Go Version: go1.7.5
Go OS/Arch: linux/amd64

 

服务注册与发现实例&#xff08;go语言&#xff09;

etcd服务注册与发现工作过程简介&#xff1a;

etcd 是一个 分布式 的高一致性的 键值存储系统。我们每次网关后面加一个服务&#xff0c;只需要向etcd 注册 该服务&#xff08;其实就是 存一个值&#xff09;然后向etcd 发送心跳&#xff0c;当etcd 没有检测到心跳就会 把这个键值对 删了(这整个动作是etcd里的租约模式)&#xff0c;网关那边 就只需要 watch 这个 key &#xff0c;就能够知道 所有服务的所有动态了。

&#xff08;etcd的 租约模式:客户端申请 一个租约 并设置 过期时间&#xff0c;每隔一段时间 就要 请求 etcd 申请续租。客户端可以通过租约存key。如果不续租 &#xff0c;过期了&#xff0c;etcd 会删除这个租约上的 所有key-value。类似于心跳模式。&#xff09;

 

系统中实现服务注册与发现所需的基本功能有&#xff1a;

  • 服务注册&#xff1a;同一service的所有节点注册到相同目录下&#xff0c;节点启动后将自己的信息注册到所属服务的目录中。
  • 健康检查&#xff1a;服务节点定时发送心跳&#xff0c;注册到服务目录中的信息设置一个较短的TTL&#xff0c;运行正常的服务节点每隔一段时间会去更新信息的TTL。
  • 服务发现&#xff1a;通过名称能查询到服务提供外部访问的 IP 和端口号。比如网关代理服务时能够及时的发现服务中新增节点、丢弃不可用的服务节点&#xff0c;同时各个服务间也能感知对方的存在。

在分布式系统中&#xff0c;如何管理节点间的状态一直是一个难题&#xff0c;etcd 是由开发并维护的&#xff0c;它使用 Go 语言编写&#xff0c;并通过Raft 一致性算法处理日志复制以保证强一致性。etcd像是专门为集群环境的服务发现和注册而设计&#xff0c;它提供了数据 TTL 失效、数据改变监视、多值、目录监听、分布式锁原子操作等功能&#xff0c;可以方便的跟踪并管理集群节点的状态。

服务注册的简单实现Golang&#xff1a;


1、安装client库

依赖etcd的client库&#xff0c;所以需要先安装

go get -v github.com/coreos/etcd/clientv3

如果下载失败&#xff0c;则手动下载 https://github.com/etcd-io/etcd/archive/v3.1.5.zip&#xff0c;解压&#xff0c;取出clientv3&#xff0c;放到$GOPATH/src/github.com/coreos/etcd/目录下

2、实例代码

写两个 Demo 程序&#xff0c;一个服务充当service&#xff0c;一个客户端程序充当网关代理&#xff08;gateway&#xff09;。服务运行后会去etcd 以自己服务名命名的目录中注册服务节点&#xff0c;并定时续租&#xff08;更新 TTL&#xff09;。客户端&#xff08;gateway&#xff09;从 etcd查询服务目录中的节点信息代理服务的请求&#xff0c;并且会在协程中实时监控服务目录中的变化&#xff0c;维护到自己的服务节点信息列表中。

&#xff08;更详细的过程说明&#xff1a;https://blog.csdn.net/wohu1104/article/details/108552649&#xff09;

网上找了蛮多资料后&#xff0c;加上自己封装后的产物。开箱即用。

 

服务注册的简单实现&#xff1a;

注意&#xff1a;import clientv3的配置填写$GOPATH/src下的真实目录&#xff0c;比如我这里&#xff1a;"github.com/coreos/etcd/client/v3"&#xff0c;参考&#xff1a;https://blog.csdn.net/wohu1104/article/details/108552649

package mainimport ("context""fmt""github.com/coreos/etcd/client/v3""time"
)//创建租约注册服务
type ServiceReg struct {client *clientv3.Clientlease clientv3.LeaseleaseResp *clientv3.LeaseGrantResponsecanclefunc func()keepAliveChan <-chan *clientv3.LeaseKeepAliveResponsekey string
}func NewServiceReg(addr []string, timeNum int64) (*ServiceReg, error) {conf :&#61; clientv3.Config{Endpoints: addr,DialTimeout: 5 * time.Second,}var (client *clientv3.Client)if clientTem, err :&#61; clientv3.New(conf); err &#61;&#61; nil {client &#61; clientTem} else {return nil, err}ser :&#61; &ServiceReg{client: client,}if err :&#61; ser.setLease(timeNum); err !&#61; nil {return nil, err}go ser.ListenLeaseRespChan()return ser, nil
}//设置租约
func (this *ServiceReg) setLease(timeNum int64) error {lease :&#61; clientv3.NewLease(this.client)//设置租约时间leaseResp, err :&#61; lease.Grant(context.TODO(), timeNum)if err !&#61; nil {return err}//设置续租ctx, cancelFunc :&#61; context.WithCancel(context.TODO())leaseRespChan, err :&#61; lease.KeepAlive(ctx, leaseResp.ID)if err !&#61; nil {return err}this.lease &#61; leasethis.leaseResp &#61; leaseRespthis.canclefunc &#61; cancelFuncthis.keepAliveChan &#61; leaseRespChanreturn nil
}//监听 续租情况
func (this *ServiceReg) ListenLeaseRespChan() {for {select {case leaseKeepResp :&#61; <-this.keepAliveChan:if leaseKeepResp &#61;&#61; nil {fmt.Printf("已经关闭续租功能\n")return} else {fmt.Printf("续租成功\n")}}}
}//通过租约 注册服务
func (this *ServiceReg) PutService(key, val string) error {kv :&#61; clientv3.NewKV(this.client)_, err :&#61; kv.Put(context.TODO(), key, val, clientv3.WithLease(this.leaseResp.ID))return err
}//撤销租约
func (this *ServiceReg) RevokeLease() error {this.canclefunc()time.Sleep(2 * time.Second)_, err :&#61; this.lease.Revoke(context.TODO(), this.leaseResp.ID)return err
}func main() {ser,_ :&#61; NewServiceReg([]string{"127.0.0.1:2379"},5)ser.PutService("/node/111","heiheihei")select{}
}

那就让我来简单的解释一下吧。

  1. etcd的 租约模式:客户端申请 一个租约 并设置 过期时间&#xff0c;每隔一段时间 就要 请求 etcd 申请续租。客户端可以通过租约存key。如果不续租 &#xff0c;过期了&#xff0c;etcd 会删除这个租约上的 所有key-value。类似于心跳模式。
  2. 一般相同的服务存的 key 的前缀是一样的 比如 “server/001"&#61;> "127.0.0.1:1212" 和 ”server/002"&#61;>"127.0.0.1:1313" 这种模式&#xff0c;然后 客户端 就直接 匹配 “server/” 这个key。
  3. 具体代码不复杂。要是看不懂就留言问我吧。

编译&#xff1a;

go build gotest.go

服务发现的简单实现&#xff1a;


import ("go.etcd.io/etcd/clientv3""time""context""go.etcd.io/etcd/mvcc/mvccpb""sync""log"
)type ClientDis struct {client *clientv3.ClientserverList map[string]stringlock sync.Mutex
}func NewClientDis (addr []string)( *ClientDis, error){conf :&#61; clientv3.Config{Endpoints: addr,DialTimeout: 5 * time.Second,}if client, err :&#61; clientv3.New(conf); err &#61;&#61; nil {return &ClientDis{client:client,serverList:make(map[string]string),}, nil} else {return nil ,err}
}func (this * ClientDis) GetService(prefix string) ([]string ,error){resp, err :&#61; this.client.Get(context.Background(), prefix, clientv3.WithPrefix())if err !&#61; nil {return nil, err}addrs :&#61; this.extractAddrs(resp)go this.watcher(prefix)return addrs ,nil
}func (this *ClientDis) watcher(prefix string) {rch :&#61; this.client.Watch(context.Background(), prefix, clientv3.WithPrefix())for wresp :&#61; range rch {for _, ev :&#61; range wresp.Events {switch ev.Type {case mvccpb.PUT:this.SetServiceList(string(ev.Kv.Key),string(ev.Kv.Value))case mvccpb.DELETE:this.DelServiceList(string(ev.Kv.Key))}}}
}func (this *ClientDis) extractAddrs(resp *clientv3.GetResponse) []string {addrs :&#61; make([]string,0)if resp &#61;&#61; nil || resp.Kvs &#61;&#61; nil {return addrs}for i :&#61; range resp.Kvs {if v :&#61; resp.Kvs[i].Value; v !&#61; nil {this.SetServiceList(string(resp.Kvs[i].Key),string(resp.Kvs[i].Value))addrs &#61; append(addrs, string(v))}}return addrs
}func (this *ClientDis) SetServiceList(key,val string) {this.lock.Lock()defer this.lock.Unlock()this.serverList[key] &#61; string(val)log.Println("set data key :",key,"val:",val)
}func (this *ClientDis) DelServiceList(key string) {this.lock.Lock()defer this.lock.Unlock()delete(this.serverList,key)log.Println("del data key:", key)
}func (this *ClientDis) SerList2Array()[]string {this.lock.Lock()defer this.lock.Unlock()addrs :&#61; make([]string,0)for _, v :&#61; range this.serverList {addrs &#61; append(addrs,v)}return addrs
}func main () {cli,_ :&#61; NewClientDis([]string{"127.0.0.1:2379"})cli.GetService("/node")select {}
}

1.创建一个client 连到etcd。
2.匹配到所有相同前缀的 key。把值存到 serverList 这个map里面。
3 watch这个 key前缀&#xff0c;当有增加或者删除的时候 就 修改这个map。
4所以这个map就是 实时的 服务列表

总结

以上就是基于 etcd的服务注册与发现了&#xff0c;大家可以 自己动手试试&#xff0c;载一个 etcd &#xff0c;然后分别运行这两个文件。就能看到效果了。 代码我也传到github上面了 https://github.com/mistaker/etcdTool 。


作者&#xff1a;xyt001
链接&#xff1a;https://www.jianshu.com/p/7c0d23c818a5
 

其他参考&#xff1a;https://www.jianshu.com/p/9bd1ab83b220

都是key-value存储&#xff0c;redis 可以代替 etcd吗&#xff1f;

理论上只要是你实现了服务注册与发现的接口 ,存储层是可以替换的.用 redis/mysql 也不是不可以~
选 etcd 这种类型只因它更适合做这个。

原因如下&#xff1a;

1、redis 主从是异步复制的机制&#xff0c;这就导致了其有丢失数据的风险。

2、分布式系统最重要的就是一致性协议&#xff0c;redis 是不支持的。如果发生脑裂&#xff0c;可能两个微服务都会声称自己对某段 IP 的请求负责。

总之&#xff0c;etcd和redis虽然存储层的结构一致&#xff0c;但是为各自业务开发了对应的接口和协议&#xff0c;etcd面向服务发现设计了接口和协议&#xff0c;所以etcd比redis更适合服务发现。redis要用于服务发现&#xff0c;需要用户做一些封装和适配。

参考&#xff1a;https://www.v2ex.com/t/520367?p&#61;1

 

为什么选择Etcd而不选择Zookeeper

etcd可实现的功能&#xff0c;Zookeeper都能实现&#xff0c;那么为什么要用etcd而非直接使用Zookeeper呢&#xff1f;相较之下&#xff0c;Zookeeper有如下缺点&#xff1a;

1.复杂。Zookeeper的部署维护复杂&#xff0c;管理员需要掌握一系列的知识和技能&#xff1b;而Paxos强一致性算法也是素来以复杂难懂而闻名于世&#xff1b;另外&#xff0c;Zookeeper的使用也比较复杂&#xff0c;需要安装客户端&#xff0c;官方只提供了java和C两种语言的接口。

2.Java编写。这里不是对Java有偏见&#xff0c;而是Java本身就偏向于重型应用&#xff0c;它会引入大量的依赖。而运维人员则普遍希望机器集群尽可能简单&#xff0c;维护起来也不易出错。

3.发展缓慢。Apache基金会项目特有的“Apache Way”在开源界饱受争议&#xff0c;其中一大原因就是由于基金会庞大的结构以及松散的管理导致项目发展缓慢。

etcd的优点&#xff1a;

1.简单。使用Go语言编写部署简单&#xff1b;使用HTTP作为接口使用简单&#xff1b;使用Raft算法保证强一致性让用户易于理解。

2.数据持久化。etcd默认数据一更新就进行持久化。

3.安全。etcd支持SSL客户端安全认证。

最后&#xff0c;etcd作为一个年轻的项目&#xff0c;正在高速迭代和开发中&#xff0c;这既是一个优点&#xff0c;也是一个缺点。优点在于它的未来具有无限的可能性&#xff0c;缺点是版本的迭代导致其使用的可靠性无法保证&#xff0c;无法得到大项目长时间使用的检验。然而&#xff0c;目前CoreOS、Kubernetes和Cloudfoundry等知名项目均在生产环境中使用了etcd&#xff0c;所以总的来说&#xff0c;etcd值得你去尝试。
链接&#xff1a;https://www.jianshu.com/p/d63265949e52
 

 

附录

附录1:etcd基本使用(数据库CURD和持久化等&#xff09;

etcdctl是一个命令行客户端&#xff0c;它能提供一些简洁的命令&#xff0c;供用户直接跟etcd服务打交道&#xff0c;而无需基于 HTTP API方式。可以方便我们在对服务进行测试或者手动修改数据库内容。建议刚刚接触etcd时通过etdctl来熟悉相关操作。这些操作跟HTTP API基本上是对应的。

etcd项目二进制发行包中已经包含了etcdctl工具&#xff0c;etcdctl支持的命令大体上分为数据库操作和非数据库操作两类。

查看版本

$ etcd --version
etcd Version: 3.1.5
Git SHA: 20490ca
Go Version: go1.7.5
Go OS/Arch: linux/amd64

查看帮助&#xff1a; 

$ etcdctl -h
NAME:etcdctl - A simple command line client for etcd.USAGE:etcdctl [global options] command [command options] [arguments...]VERSION:3.1.5COMMANDS:backup backup an etcd directorycluster-health check the health of the etcd clustermk make a new key with a given valuemkdir make a new directoryrm remove a key or a directoryrmdir removes the key if it is an empty directory or a key-value pairget retrieve the value of a keyls retrieve a directoryset set the value of a keysetdir create a new directory or update an existing directory TTLupdate update an existing key with a given valueupdatedir update an existing directorywatch watch a key for changesexec-watch watch a key for changes and exec an executablemember member add, remove and list subcommandsuser user add, grant and revoke subcommandsrole role add, grant and revoke subcommandsauth overall auth controlshelp, h Shows a list of commands or help for one commandGLOBAL OPTIONS:--debug output cURL commands which can be used to reproduce the request--no-sync don&#39;t synchronize cluster information before sending request--output simple, -o simple output response in the given format (simple, &#96;extended&#96; or &#96;json&#96;) (default: "simple")--discovery-srv value, -D value domain name to query for SRV records describing cluster endpoints--insecure-discovery accept insecure SRV records describing cluster endpoints--peers value, -C value DEPRECATED - "--endpoints" should be used instead--endpoint value DEPRECATED - "--endpoints" should be used instead--endpoints value a comma-delimited list of machine addresses in the cluster (default: "http://127.0.0.1:2379,http://127.0.0.1:4001")--cert-file value identify HTTPS client using this SSL certificate file--key-file value identify HTTPS client using this SSL key file--ca-file value verify certificates of HTTPS-enabled servers using this CA bundle--username value, -u value provide username[:password] and prompt if password is not supplied.--timeout value connection timeout per request (default: 2s)--total-timeout value timeout for the command execution (except watch) (default: 5s)--help, -h show help--version, -v print the version

常用命令选项:

--debug 输出CURL命令&#xff0c;显示执行命令的时候发起的请求
--no-sync 发出请求之前不同步集群信息
--output, -o &#39;simple&#39; 输出内容的格式(simple 为原始信息&#xff0c;json 为进行json格式解码&#xff0c;易读性好一些)
--peers, -C 指定集群中的同伴信息&#xff0c;用逗号隔开(默认为: "127.0.0.1:4001")
--cert-file HTTPS下客户端使用的SSL证书文件
--key-file HTTPS下客户端使用的SSL密钥文件
--ca-file 服务端使用HTTPS时&#xff0c;使用CA文件进行验证
--help, -h 显示帮助命令信息
--version, -v 打印版本信息

数据库操作

数据库操作围绕对键值和目录的CRUD完整生命周期的管理。

etcd在键的组织上采用了层次化的空间结构(类似于文件系统中目录的概念)&#xff0c;用户指定的键可以为单独的名字&#xff0c;如:testkey&#xff0c;此时实际上放在根目录/下面&#xff0c;也可以为指定目录结构&#xff0c;如/cluster1/node2/testkey&#xff0c;则将创建相应的目录结构。

注&#xff1a;CRUD即Create,Read,Update,Delete是符合REST风格的一套API操作。


  • set

指定某个键的值。例如:

$ etcdctl set /testdir/testkey "Hello world"
Hello world

支持的选项包括&#xff1a;

--ttl &#39;0&#39; 该键值的超时时间(单位为秒)&#xff0c;不配置(默认为0)则永不超时
--swap-with-value value 若该键现在的值是value&#xff0c;则进行设置操作
--swap-with-index &#39;0&#39; 若该键现在的索引值是指定索引&#xff0c;则进行设置操作

  • get

获取指定键的值。例如&#xff1a;

$ etcdctl get /testdir/testkey
Hello world

当键不存在时&#xff0c;则会报错。例如&#xff1a;

$ etcdctl get /testdir/testkey2
Error: 100: Key not found (/testdir/testkey2) [5]

支持的选项为:

--sort 对结果进行排序
--consistent 将请求发给主节点&#xff0c;保证获取内容的一致性。

  • update

当键存在时&#xff0c;更新值内容。例如&#xff1a;

$ etcdctl update /testdir/testkey "Hello"
Hello

当键不存在时&#xff0c;则会报错。例如:

$ etcdctl update /testdir/testkey2 "Hello"
Error: 100: Key not found (/testdir/testkey2) [6]

支持的选项为:

--ttl &#39;0&#39; 超时时间(单位为秒)&#xff0c;不配置(默认为 0)则永不超时。

  • rm

删除某个键值。例如:

$ etcdctl rm /testdir/testkey
PrevNode.Value: Hello

当键不存在时&#xff0c;则会报错。例如:

$ etcdctl rm /testdir/testkey
Error: 100: Key not found (/testdir/testkey) [7]

支持的选项为&#xff1a;

--dir 如果键是个空目录或者键值对则删除
--recursive 删除目录和所有子键
--with-value 检查现有的值是否匹配
--with-index &#39;0&#39;检查现有的index是否匹配

  • mk

如果给定的键不存在&#xff0c;则创建一个新的键值。例如:

$ etcdctl mk /testdir/testkey "Hello world"
Hello world

当键存在的时候&#xff0c;执行该命令会报错&#xff0c;例如:

$ etcdctl mk /testdir/testkey "Hello world"
Error: 105: Key already exists (/testdir/testkey) [8]

支持的选项为:

--ttl &#39;0&#39; 超时时间(单位为秒&#xff09;&#xff0c;不配置(默认为 0)。则永不超时

  • mkdir

如果给定的键目录不存在&#xff0c;则创建一个新的键目录。例如&#xff1a;

$ etcdctl mkdir testdir2

当键目录存在的时候&#xff0c;执行该命令会报错&#xff0c;例如&#xff1a;

$ etcdctl mkdir testdir2
Error: 105: Key already exists (/testdir2) [9]

支持的选项为&#xff1a;

--ttl &#39;0&#39; 超时时间(单位为秒)&#xff0c;不配置(默认为0)则永不超时。

  • setdir

创建一个键目录。如果目录不存在就创建&#xff0c;如果目录存在更新目录TTL。

$ etcdctl setdir testdir3

支持的选项为:

--ttl &#39;0&#39; 超时时间(单位为秒)&#xff0c;不配置(默认为0)则永不超时。

  • updatedir

更新一个已经存在的目录。

$ etcdctl updatedir testdir2

支持的选项为:

--ttl &#39;0&#39; 超时时间(单位为秒)&#xff0c;不配置(默认为0)则永不超时。

  • rmdir

删除一个空目录&#xff0c;或者键值对。

$ etcdctl setdir dir1
$ etcdctl rmdir dir1

若目录不空&#xff0c;会报错:

$ etcdctl set /dir/testkey hi
hi
$ etcdctl rmdir /dir
Error: 108: Directory not empty (/dir) [17]

  • ls

列出目录(默认为根目录)下的键或者子目录&#xff0c;默认不显示子目录中内容。

例如&#xff1a;

$ etcdctl ls
/testdir
/testdir2
/dir$ etcdctl ls dir
/dir/testkey

支持的选项包括:

--sort 将输出结果排序
--recursive 如果目录下有子目录&#xff0c;则递归输出其中的内容
-p 对于输出为目录&#xff0c;在最后添加/进行区分

非数据库操作


  • backup

备份etcd的数据。

$ etcdctl backup --data-dir /var/lib/etcd --backup-dir /home/etcd_backup

支持的选项包括:

--data-dir etcd的数据目录
--backup-dir 备份到指定路径

  • watch

监测一个键值的变化&#xff0c;一旦键值发生更新&#xff0c;就会输出最新的值并退出。

例如:用户更新testkey键值为Hello watch。

$ etcdctl get /testdir/testkey
Hello world
$ etcdctl set /testdir/testkey "Hello watch"
Hello watch
$ etcdctl watch testdir/testkey
Hello watch

支持的选项包括:

--forever 一直监测直到用户按CTRL&#43;C退出
--after-index &#39;0&#39; 在指定index之前一直监测
--recursive 返回所有的键值和子键值

  • exec-watch

监测一个键值的变化&#xff0c;一旦键值发生更新&#xff0c;就执行给定命令。

例如&#xff1a;用户更新testkey键值。

$ etcdctl exec-watch testdir/testkey -- sh -c &#39;ls&#39;
config Documentation etcd etcdctl README-etcdctl.md README.md READMEv2-etcdctl.md

支持的选项包括:

--after-index &#39;0&#39; 在指定 index 之前一直监测
--recursive 返回所有的键值和子键值

  • member

通过listaddremove命令列出、添加、删除etcd实例到etcd集群中。

查看集群中存在的节点

$ etcdctl member list
8e9e05c52164694d: name&#61;dev-master-01 peerURLs&#61;http://localhost:2380 clientURLs&#61;http://localhost:2379 isLeader&#61;true

删除集群中存在的节点

$ etcdctl member remove 8e9e05c52164694d
Removed member 8e9e05c52164694d from cluster

向集群中新加节点

$ etcdctl member add etcd3 http://192.168.1.100:2380
Added member named etcd3 with ID 8e9e05c52164694d to cluster


摘自&#xff1a;链接&#xff1a;https://www.jianshu.com/p/f68028682192

 

附录2&#xff1a;etcd应用场景

 

5.1服务发现

服务发现&#xff08;Service Discovery&#xff09;要解决的是分布式系统中最常见的问题之一&#xff0c;即在同一个分布式集群中的进程或服务如何才能找到对方并建立连接。从本质上说&#xff0c;服务发现就是想要了解集群中是否有进程在监听udp或tcp端口&#xff0c;并且通过名字就可以进行查找和连接。要解决服务发现的问题&#xff0c;需要有下面三大支柱&#xff0c;缺一不可。

·一个强一致性、高可用的服务存储目录。基于Raft算法的etcd天生就是这样一个强一致性高可用的服务存储目录。

·一种注册服务和监控服务健康状态的机制。用户可以在etcd中注册服务&#xff0c;并且对注册的服务设置key TTL&#xff0c;定时保持服务的心跳以达到监控健康状态的效果。

·一种查找和连接服务的机制。通过在etcd指定的主题下注册的服务也能在对应的主题下查找到。为了确保连接&#xff0c;我们可以在每个服务机器上都部署一个proxy模式的etcd&#xff0c;这样就可以确保能访问etcd集群的服务都能互相连接。

 

图3服务发现图

 

5.2消息发布与订阅

在分布式系统中&#xff0c;最为适用的组件间通信方式是消息发布与订阅机制。具体而言&#xff0c;即构建一个配置共享中心&#xff0c;数据提供者在这个配置中心发布消息&#xff0c;而消息使用者则订阅他们关心的主题&#xff0c;一旦相关主题有消息发布&#xff0c;就会实时通知订阅者。通过这种方式可以实现分布式系统配置的集中式管理与实时动态更新。

·应用中用到的一些配置信息存放在etcd上进行集中管理。这类场景的使用方式通常是这样的&#xff1a;应用在启动的时候主动从etcd获取一次配置信息&#xff0c;同时&#xff0c;在etcd节点上注册一个Watcher并等待&#xff0c;以后每次配置有更新的时候&#xff0c;etcd都会实时通知订阅者&#xff0c;以此达到获取最新配置信息的目的。

·分布式搜索服务中&#xff0c;索引的元信息和服务器集群机器的节点状态信息存放在etcd中&#xff0c;供各个客户端订阅使用。使用etcd的key TTL功能可以确保机器状态是实时更新的。

·分布式日志收集系统。这个系统的核心工作是收集分布在不同机器上的日志。收集器通常按照应用&#xff08;或主题&#xff09;来分配收集任务单元&#xff0c;因此可以在etcd上创建一个以应用&#xff08;或主题&#xff09;命名的目录P&#xff0c;并将这个应用&#xff08;或主题&#xff09;相关的所有机器ip&#xff0c;以子目录的形式存储在目录P下&#xff0c;然后设置一个递归的etcd Watcher&#xff0c;递归式地监控应用&#xff08;或主题&#xff09;目录下所有信息的变动。这样就实现了在机器IP&#xff08;消息&#xff09;发生变动时&#xff0c;能够实时通知收集器调整任务分配。

·系统中信息需要动态自动获取与人工干预修改信息请求内容的情况。通常的解决方案是对外暴露接口&#xff0c;例如JMX接口&#xff0c;来获取一些运行时的信息或提交修改的请求。而引入etcd之后&#xff0c;只需要将这些信息存放到指定的etcd目录中&#xff0c;即可通过HTTP接口直接被外部访问。

 

图4消息发布与订阅图

 

5.3负载均衡

在场景一中也提到了负载均衡&#xff0c;本文提及的负载均衡均指软负载均衡。在分布式系统中&#xff0c;为了保证服务的高可用以及数据的一致性&#xff0c;通常都会把数据和服务部署多份&#xff0c;以此达到对等服务&#xff0c;即使其中的某一个服务失效了&#xff0c;也不影响使用。这样的实现虽然会导致一定程度上数据写入性能的下降&#xff0c;但是却能实现数据访问时的负载均衡。因为每个对等服务节点上都存有完整的数据&#xff0c;所以用户的访问流量就可以分流到不同的机器上。

·etcd本身分布式架构存储的信息访问支持负载均衡。etcd集群化以后&#xff0c;每个etcd的核心节点都可以处理用户的请求。所以&#xff0c;把数据量小但是访问频繁的消息数据直接存储到etcd中也是个不错的选择&#xff0c;如业务系统中常用的二级代码表。二级代码表的工作过程一般是这样&#xff0c;在表中存储代码&#xff0c;在etcd中存储代码所代表的具体含义&#xff0c;业务系统调用查表的过程&#xff0c;就需要查找表中代码的含义。所以如果把二级代码表中的小量数据存储到etcd中&#xff0c;不仅方便修改&#xff0c;也易于大量访问。

·利用etcd维护一个负载均衡节点表。etcd可以监控一个集群中多个节点的状态&#xff0c;当有一个请求发过来后&#xff0c;可以轮询式地把请求转发给存活着的多个节点。类似KafkaMQ&#xff0c;通过Zookeeper来维护生产者和消费者的负载均衡。同样也可以用etcd来做Zookeeper的工作。

 

图5负载平衡图

5.4分布式通知与协调

这里讨论的分布式通知与协调&#xff0c;与消息发布和订阅有些相似。两者都使用了etcd中的Watcher机制&#xff0c;通过注册与异步通知机制&#xff0c;实现分布式环境下不同系统之间的通知与协调&#xff0c;从而对数据变更进行实时处理。实现方式通常为&#xff1a;不同系统都在etcd上对同一个目录进行注册&#xff0c;同时设置Watcher监控该目录的变化&#xff08;如果对子目录的变化也有需要&#xff0c;可以设置成递归模式&#xff09;&#xff0c;当某个系统更新了etcd的目录&#xff0c;那么设置了Watcher的系统就会收到通知&#xff0c;并作出相应处理。

·通过etcd进行低耦合的心跳检测。检测系统和被检测系统通过etcd上某个目录关联而非直接关联起来&#xff0c;这样可以大大减少系统的耦合性。

·通过etcd完成系统调度。某系统有控制台和推送系统两部分组成&#xff0c;控制台的职责是控制推送系统进行相应的推送工作。管理人员在控制台做的一些操作&#xff0c;实际上只需要修改etcd上某些目录节点的状态&#xff0c;而etcd就会自动把这些变化通知给注册了Watcher的推送系统客户端&#xff0c;推送系统再做出相应的推送任务。

·通过etcd完成工作汇报。大部分类似的任务分发系统&#xff0c;子任务启动后&#xff0c;到etcd来注册一个临时工作目录&#xff0c;并且定时将自己的进度进行汇报&#xff08;将进度写入到这个临时目录&#xff09;&#xff0c;这样任务管理者就能够实时知道任务进度。

 

图6分布式通知与协调图

 

5.5分布式锁

因为etcd使用Raft算法保持了数据的强一致性&#xff0c;某次操作存储到集群中的值必然是全局一致的&#xff0c;所以很容易实现分布式锁。锁服务有两种使用方式&#xff0c;一是保持独占&#xff0c;二是控制时序。

·保持独占&#xff0c;即所有试图获取锁的用户最终只有一个可以得到。etcd为此提供了一套实现分布式锁原子操作CAS&#xff08;CompareAndSwap&#xff09;的API。通过设置prevExist值&#xff0c;可以保证在多个节点同时创建某个目录时&#xff0c;只有一个成功&#xff0c;而该用户即可认为是获得了锁。

·控制时序&#xff0c;即所有试图获取锁的用户都会进入等待队列&#xff0c;获得锁的顺序是全局唯一的&#xff0c;同时决定了队列执行顺序。etcd为此也提供了一套API&#xff08;自动创建有序键&#xff09;&#xff0c;对一个目录建值时指定为POST动作&#xff0c;这样etcd会自动在目录下生成一个当前最大的值为键&#xff0c;存储这个新的值&#xff08;客户端编号&#xff09;。同时还可以使用API按顺序列出所有当前目录下的键值。此时这些键的值就是客户端的时序&#xff0c;而这些键中存储的值可以是代表客户端的编号。

 

图7分布式锁图

 

5.6分布式队列

分布式队列的常规用法与场景五中所描述的分布式锁的控制时序用法类似&#xff0c;即创建一个先进先出的队列&#xff0c;保证顺序。

另一种比较有意思的实现是在保证队列达到某个条件时再统一按顺序执行。这种方法的实现可以在/queue这个目录中另外建立一个/queue/condition节点。

·condition可以表示队列大小。比如一个大的任务需要很多小任务就绪的情况下才能执行&#xff0c;每次有一个小任务就绪&#xff0c;就给这个condition数字加1&#xff0c;直到达到大任务规定的数字&#xff0c;再开始执行队列里的一系列小任务&#xff0c;最终执行大任务。

·condition可以表示某个任务在不在队列。这个任务可以是所有排序任务的首个执行程序&#xff0c;也可以是拓扑结构中没有依赖的点。通常&#xff0c;必须执行这些任务后才能执行队列中的其他任务。

·condition还可以表示其它的一类开始执行任务的通知。可以由控制程序指定&#xff0c;当condition出现变化时&#xff0c;开始执行队列任务。

 

图8分布式队列图

 

5.7集群监控与LEADER竞选

通过etcd来进行监控实现起来非常简单并且实时性强&#xff0c;用到了以下两点特性。

1.前面几个场景已经提到Watcher机制&#xff0c;当某个节点消失或有变动时&#xff0c;Watcher会第一时间发现并告知用户。

2.节点可以设置TTL key&#xff0c;比如每隔30s向etcd发送一次心跳使代表该节点仍然存活&#xff0c;否则说明节点消失。

这样就可以第一时间检测到各节点的健康状态&#xff0c;以完成集群的监控要求。

另外&#xff0c;使用分布式锁&#xff0c;可以完成Leader竞选。对于一些长时间CPU计算或者使用IO操作&#xff0c;只需要由竞选出的Leader计算或处理一次&#xff0c;再把结果复制给其他Follower即可&#xff0c;从而避免重复劳动&#xff0c;节省计算资源。

Leader应用的经典场景是在搜索系统中建立全量索引。如果每个机器分别进行索引的建立&#xff0c;不但耗时&#xff0c;而且不能保证索引的一致性。通过在etcd的CAS机制竞选Leader&#xff0c;由Leader进行索引计算&#xff0c;再将计算结果分发到其它节点。

 

图9集群监控与Leader竞选图


作者&#xff1a;Jay_Guo
链接&#xff1a;https://www.jianshu.com/p/d63265949e52
来源&#xff1a;简书
 

 

附录3&#xff1a;ETCD 词汇表

Raft&#xff1a;etcd所采用的保证分布式系统强一致性的算法。

Node&#xff1a;一个Raft状态机实例。

Member&#xff1a; 一个etcd实例。它管理着一个Node&#xff0c;并且可以为客户端请求提供服务。

Cluster&#xff1a;由多个Member构成可以协同工作的etcd集群。

Peer&#xff1a;对同一个etcd集群中另外一个Member的称呼。

Client&#xff1a; 向etcd集群发送HTTP请求的客户端。

WAL&#xff1a;预写式日志&#xff0c;etcd用于持久化存储的日志格式。

snapshot&#xff1a;etcd防止WAL文件过多而设置的快照&#xff0c;存储etcd数据状态。

Proxy&#xff1a;etcd的一种模式&#xff0c;为etcd集群提供反向代理服务。

Leader&#xff1a;Raft算法中通过竞选而产生的处理所有数据提交的节点。

Follower&#xff1a;竞选失败的节点作为Raft中的从属节点&#xff0c;为算法提供强一致性保证。

Candidate&#xff1a;当Follower超过一定时间接收不到Leader的心跳时转变为Candidate开始Leader竞选。

Term&#xff1a;某个节点成为Leader到下一次竞选开始的时间周期&#xff0c;称为一个Term。

Index&#xff1a;数据项编号。Raft中通过Term和Index来定位数据。


作者&#xff1a;向永清_数字经济
链接&#xff1a;https://www.jianshu.com/p/3bd041807974
来源&#xff1a;简书


 


推荐阅读
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文比较了eBPF和WebAssembly作为云原生VM的特点和应用领域。eBPF作为运行在Linux内核中的轻量级代码执行沙箱,适用于网络或安全相关的任务;而WebAssembly作为图灵完备的语言,在商业应用中具有优势。同时,介绍了WebAssembly在Linux内核中运行的尝试以及基于LLVM的云原生WebAssembly编译器WasmEdge Runtime的案例,展示了WebAssembly作为原生应用程序的潜力。 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 本文讨论了读书的目的以及学习算法的重要性,并介绍了两个算法:除法速算和约瑟夫环的数学算法。同时,通过具体的例子和推理,解释了为什么x=x+k序列中的第一个人的位置为k,以及序列2和序列3的关系。通过学习算法,可以提高思维能力和解决问题的能力。 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • LVS实现负载均衡的原理LVS负载均衡负载均衡集群是LoadBalance集群。是一种将网络上的访问流量分布于各个节点,以降低服务器压力,更好的向客户端 ... [详细]
  • POCOCLibraies属于功能广泛、轻量级别的开源框架库,它拥有媲美Boost库的功能以及较小的体积广泛应用在物联网平台、工业自动化等领域。POCOCLibrai ... [详细]
  • 三、查看Linux版本查看系统版本信息的命令:lsb_release-a[root@localhost~]#lsb_release-aLSBVersion::co ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了VoLTE端到端业务详解|VoLTE用户注册流程相关的知识,希望对你有一定的参考价值。书籍来源:艾怀丽 ... [详细]
author-avatar
DLDLBABY1_182
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有