分布式一致性工具课题

2019-07-05

CAP定理

在理论计算机科学中,CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer’s theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点:

  • 一致性(Consistency):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
  • 可用性(Availability):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
  • 分区容忍性(Partition tolerance):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

根据定理,分佈式系统只能满足三项中的两项而不可能满足全部三项[4]。理解CAP理论的最简单方式是想象两个节点分处分区两侧。允许至少一个节点更新状态会导致数据不一致,即丧失了C性质。如果为了保证数据一致性,将分区一侧的节点设置为不可用,那么又丧失了A性质。除非两个节点可以互相通信,才能既保证C又保证A,这又会导致丧失P性质。

参考:https://zh.wikipedia.org/wiki/CAP%E5%AE%9A%E7%90%86

一致性算法

一致性算法主要有Paxos、Raft、ZAB三种:

其中Paxos深入理解起来有难度,在实际应用中也难以实现。Raft相当于简化版的Multi Paxos,ZAB和Raft原理一致,部分标签命名方式不一样,实际应用中比较多的应该是Raft算法。

Raft动画解释

Raft演示集群场景测试

参考:https://www.jianshu.com/p/9a9290fb0727

学习参考视频:https://www.bilibili.com/video/av21667358/?spm_id_from=333.788.videocard.0

工具选型

  • 名称 优点 缺点 接口 一致性
    zookeeper 1.功能强大,不仅仅只是服务发现
    2.提供watcher机制能实时获取服务提供者的状态
    3.dubbo等框架支持
    1.没有健康检查
    2.需在服务中集成sdk,复杂度高
    3.不支持多数据中心
    sdk Paxos
    consul 1.简单易用,不需要集成sdk
    2.自带健康检查
    3.支持多数据中心
    4.提供web管理界面
    1.不能实时获取服务信息的变化通知 http/dns Raft
    etcd 1.简单易用,不需要集成sdk
    2.可配置性强
    1.没有健康检查
    2.需配合第三方工具一起完成服务发现
    3.不支持多数据中心
    http Raft

综合考虑并参考公司本身用的是Etcd,本次课题选择使用Etcd集群搭建进行静态发现和DNS动态发现实验测试。

Etcd集群搭建

1、简介

Etcd 是 CoreOS 推出的高可用的键值存储系统,主要用于k8s集群的服务发现等,而本身 Etcd 也支持集群模式部署,从而实现自身高可用。Etcd构建自身高可用集群主要有三种形式:

  • 静态发现: 预先已知 Etcd 集群中有哪些节点,在启动时直接指定好 Etcd 的各个 node 节点地址
  • Etcd 动态发现: 通过已有的 Etcd 集群作为数据交互点,然后在扩展新的集群时实现通过已有集群进行服务发现的机制
  • DNS 动态发现: 通过 DNS 查询方式获取其他节点地址信息

本次课题主要学习静态发现和DNS动态发现

2、静态发现

2.1、环境准备

本次课题没有限制环境搭建方式,CenoOS官方提供了Etcd的rpm,可以通过yum直接安装。

yum install etcd -y

分别安装到3台虚拟机上,节点配置如下:

节点 地址
etcd1 192.168.100.101
etcd2 192.168.100.102
etcd3 192.168.100.103

2.2、修改Etcd配置

#编辑配置文件
[root@etcd1 ~]# vim /etc/etcd/etcd.conf
#配置如下
# 节点名称
ETCD_NAME=etcd1
# 数据存放位置
ETCD_DATA_DIR="/var/lib/etcd/etcd1"
# 监听其他 Etcd 实例的地址
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
# 监听客户端地址
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379,http://0.0.0.0:4001"
# 通知其他 Etcd 实例地址
 ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.100.101:2380"
# 初始化集群内节点地址
 ETCD_INITIAL_CLUSTER="etcd1=http://192.168.100.101:2380,etcd2=http://192.168.100.102:2380,etcd3=http://192.168.100.103:2380"
# 初始化集群状态,new 表示新建
ETCD_INITIAL_CLUSTER_STATE="new"
 # 初始化集群 token
ETCD_INITIAL_CLUSTER_TOKEN="mritd-etcd-cluster"
# 通知 客户端地址
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.100.101:2379,http://192.168.100.101:4001"

etcd的单机使用参考:https://www.hi-linux.com/posts/40915.html

2.3、测试集群

集群搭建好后,分别在各个节点上启动etcd。在任意节点执行etcdctl mamber list即可列出所有集群节点信息,同时可以使用 etcdctl cluster-health 检查集群健康状态。

#启动etcd
[root@etcd1 ~]# systemctl start etcd
#查看节点信息
[root@etcd1 ~]# etcdctl member list
1dd433ececcf25d7: name=etcd3 peerURLs=http://192.168.100.103:2380 clientURLs=http://192.168.100.103:2379,http://192.168.100.103:4001 isLeader=false
378e354d4ff62108: name=etcd2 peerURLs=http://192.168.100.102:2380 clientURLs=http://192.168.100.102:2379,http://192.168.100.102:4001 isLeader=true
50c741cfee76183e: name=etcd1 peerURLs=http://192.168.100.101:2380 clientURLs=http://192.168.100.101:2379,http://192.168.100.101:4001 isLeader=false
#查看节点健康状态
[root@etcd1 ~]# etcdctl cluster-health
member 1dd433ececcf25d7 is healthy: got healthy result from http://192.168.100.103:2379
member 378e354d4ff62108 is healthy: got healthy result from http://192.168.100.102:2379
member 50c741cfee76183e is healthy: got healthy result from http://192.168.100.101:2379
cluster is healthy

3、dnsmasq搭建

  • Etcd 在基于DNS做服务发现时,实际上是利用 DNS的SRV记录不断轮训查询实现的,所以首先要加入 DNS SRV记录,故采用dnsmasq作为dns服务器。

  • 配置一台虚拟机的ip地址为192.168.100.104搭建dnsmasq。

3.1、安装dnsmasq

#安装dnsmasq
[root@dnsmasq ~]# yum install -y dnsmasq

3.2、主要配置

#编辑配置文件
[root@dnsmasq ~]# vim /etc/dnsmasq.conf
#主要配置如下

# 上游 DNS 定义
resolv-file=/etc/resolv.dnsmasq.conf
# 取消从本地 hosts 读取
no-hosts
# 监听地址
listen-address=127.0.0.1,192.168.100.104
# 指定本地 dns host 配置
addn-hosts=/etc/dnsmasq.hosts
# 设置 dns 缓存大小
cache-size=150

3.3、DNS解析配置

# 增加本地回环
[root@dnsmasq ~]# echo 'nameserver 127.0.0.1' >> /etc/resolv.conf
# 增加本地 hosts
[root@dnsmasq ~]# cp /etc/hosts /etc/dnsmasq.hosts
# 添加上游 DNS 服务器
[root@dnsmasq ~]# echo 'nameserver 8.8.8.8' >> /etc/resolv.dnsmasq.conf
[root@dnsmasq ~]# echo 'nameserver 192.168.100.100' >> /etc/resolv.dnsmasq.conf

3.4、测试

#安装bind-utils工具包
[root@dnsmasq ~]# yum -y install bind-utils
#使用dig命令测试
[root@dnsmasq ~]# dig @192.168.100.104 www.baidu.com

; <<>> DiG 9.9.4-RedHat-9.9.4-74.el7_6.1 <<>> @192.168.100.104 www.baidu.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23167
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.baidu.com.			IN	A

;; ANSWER SECTION:
www.baidu.com.		1082	IN	CNAME	www.a.shifen.com.
www.a.shifen.com.	183	IN	A	180.97.33.107
www.a.shifen.com.	183	IN	A	180.97.33.108

;; Query time: 0 msec
;; SERVER: 192.168.100.104#53(192.168.100.104)
;; WHEN: 五 7月 05 05:49:04 CST 2019
;; MSG SIZE  rcvd: 104

4、DNS动态发现

4.1、创建DNS记录

# 增加 SRV 记录
[root@dnsmasq ~]# vim /etc/dnsmasq.conf
# 增加内容如下
srv-host=_etcd-server._tcp.mritd.me,etcd1.mritd.me,2380,0,100
srv-host=_etcd-server._tcp.mritd.me,etcd2.mritd.me,2380,0,100
srv-host=_etcd-server._tcp.mritd.me,etcd3.mritd.me,2380,0,100

# 然后增加对应的域名解析
[root@dnsmasq ~]# vim /etc/dnsmasq.hosts
# 增加内容如下
192.168.100.101 etcd1.mritd.me
192.168.100.102 etcd2.mritd.me
192.168.100.103 etcd3.mritd.me

4.2、重启dnsmasq测试是否成功

#重启服务
[root@dnsmasq ~]# systemctl restart dnsmasq
#查询SRV
[root@dnsmasq ~]# dig @192.168.100.104 +noall +answer SRV _etcd-server._tcp.mritd.me
_etcd-server._tcp.mritd.me. 0	IN	SRV	0 100 2380 etcd2.mritd.me.
_etcd-server._tcp.mritd.me. 0	IN	SRV	0 100 2380 etcd1.mritd.me.
_etcd-server._tcp.mritd.me. 0	IN	SRV	0 100 2380 etcd3.mritd.me.
#查询域名解析
[root@dnsmasq ~]# dig @192.168.100.104 +noall +answer etcd1.mritd.me etcd2.mritd.me etcd3.mritd.me
etcd1.mritd.me.		0	IN	A	192.168.100.101
etcd2.mritd.me.		0	IN	A	192.168.100.102
etcd3.mritd.me.		0	IN	A	192.168.100.103

4.3、修改Etcd

Linux 系统默认从 /etc/resolv.conf 配置文件读取 DNS 服务器,为了让 Etcd 能够从 dnsmasq 服务器获取自定义域名解析,要修改3台 Etcd 服务器的 /etc/resolv.conf 文件

#编辑resolv.conf文件
[root@etcd1 ~]# vim /etc/resolv.conf
# 保证我们自定义的 dnsmasq 服务器在第一位

# Generated by NetworkManager
search lan lan.
nameserver 192.168.100.104
nameserver 192.168.100.2
nameserver 127.0.0.1

4.4、配置Etcd

修改 Etcd 配置文件,开启 DNS 服务发现,主要是删除掉 ETCD_INITIAL_CLUSTER 字段(用于静态服务发现),并指定 DNS SRV 域名(ETCD_DISCOVERY_SRV)

# 编辑 etcd 配置文件
[root@etcd1 ~]# vim /etc/etcd/etcd.conf

# 节点名称
ETCD_NAME=etcd1
# 数据存放位置
ETCD_DATA_DIR="/var/lib/etcd/etcd1"
# 监听其他 Etcd 实例的地址
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
# 监听客户端地址
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379,http://0.0.0.0:4001"
# 通知其他 Etcd 实例地址
 ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.100.101:2380"
# 初始化集群内节点地址(用于静态发现)
# ETCD_INITIAL_CLUSTER="etcd1=http://192.168.100.101:2380,etcd2=http://192.168.100.102:2380,etcd3=http://192.168.100.103:2380"
# 初始化集群状态,new 表示新建
ETCD_INITIAL_CLUSTER_STATE="new"
 # 初始化集群 token
ETCD_INITIAL_CLUSTER_TOKEN="mritd-etcd-cluster"
# 通知 客户端地址
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.100.101:2379,http://192.168.100.101:4001"
#指定DNS SRV域名
#ETCD_DISCOVERY_SRV="mritd.me"

4.5、测试动态发现

# 由于端口并未绑定到 0.0.0.0,所以需要指定 etcd 服务器
# 静态服务发现是绑定了 0.0.0.0 
# 出于安全考虑最好只监听局域网
[root@etcd1 ~]# etcdctl --endpoints "http://etcd1.mritd.me:2379,http://etcd1.mritd.me:4001" member list
1dd433ececcf25d7: name=etcd3 peerURLs=http://192.168.100.103:2380 clientURLs=http://192.168.100.103:2379,http://192.168.100.103:4001 isLeader=false
378e354d4ff62108: name=etcd2 peerURLs=http://192.168.100.102:2380 clientURLs=http://192.168.100.102:2379,http://192.168.100.102:4001 isLeader=true
50c741cfee76183e: name=etcd1 peerURLs=http://192.168.100.101:2380 clientURLs=http://192.168.100.101:2379,http://192.168.100.101:4001 isLeader=false