【是否原創】是
【首發渠道】TiDB 社群
前言
分散式關係型資料庫TiDB是一種計算和儲存分離的架構,每一層都可以獨立地進行水平擴充套件,這樣就可以做到有的放矢,對症下藥。
從TiDB整體架構圖可以看到,計算層(圖中的TiDB Cluster)負責與外部應用使用MySQL協議通訊,每一個TiDB Server是一個無狀態節點彼此獨立,應用端連線任何一個TiDB節點都可以正常訪問資料庫。這樣做的好處有以下兩點:
-
簡單增加TiDB節點就可以提升叢集處理能力。
-
把TP請求和AP請求在計算層分開,各玩各的互不影響。
但這樣帶來的一個問題是,如果叢集有多個TiDB節點,應用端應該訪問哪一個呢?我們不可能在應用端寫多個資料庫連線,A業務訪問TiDB-1,B業務訪問訪問TiDB-2。又或者是習慣了分庫分表讀寫分離的同學會考慮用MyCat這類的資料庫中介軟體來實現請求轉發。
TiDB的誕生初衷就是徹底告別各種複雜的資料庫拆分模式,做到不和資料庫中介軟體強耦合,我們需要的是一個單純的代理來自動實現TiDB節點路由。
這時候,執行在TCP層的負載均衡元件顯然更適合。
TiDB可以用哪些負載均衡元件
經過多方調研和使用,這裡推薦以下三種TiDB負載均衡方案。
首先是HAProxy,它作為一款工作在TCP(四層)和HTTP(七層)的開源代理元件,支援豐富的負載均衡策略以及出色的效能從而使用非常廣泛,它是TiDB官方推薦的負載均衡方式。
其次是LVS,這也是一款鼎鼎大名的負載均衡開源軟體,它工作在網路第四層,流量直接通過Linux核心來處理效能非常高,同時也支援多種負載均衡演算法,但是配置和使用相對比較複雜。
最後要介紹一下TiDB孵化器下的Weir,這個專案最初由伴魚發起並開源,而後PingCAP也加入其中,也是官方推薦的負載均衡之一。除此之外,它還支援SQL審計、監控、多租戶、自適應熔斷限流等高階特性,對這方面有需求的可以優先考慮。和前面兩種不一樣的是,它是工作在第七層應用層的。
另外,像DNS解析或F5這類非軟體層面的負載均衡也可以用在TiDB上,但不在本文的討論範圍。
HAProxy
HAProxy在TiDB中的最佳實踐官網有一篇文章詳細介紹過,手把手教你如何安裝和配置,地址是https://docs.pingcap.com/zh/tidb/dev/haproxy-best-practices
這裡借用裡面的一張圖:
從這張圖裡面可以發現,引入HAProxy後它自身成為了一個單點,一旦出現故障那整個資料庫都無法訪問,那麼搭建高可用負載均衡是不可避免的,這裡我推薦的方式是使用Keepalived+VIP的方式,架構如下圖所示:
Keepalived的工作原理是基於虛擬路由冗餘協議(VRRP)讓兩臺主機繫結同一個虛擬IP,當其中的master節點故障時自動路由到backup節點,無需人工介入。
值得一提的是,bakcup節點在成為master前都是閒置狀態,有一定的資源浪費。
接下來看一下如何操作。
直接通過yum就可以安裝keepalived:
[root@localhost ~]# yum install -y keepalived
[root@localhost ~]# which keepalived
/usr/sbin/keepalived
它的配置檔案在/etc/keepalived/keepalived.conf
。
分別在兩臺負載均衡節點上安裝keepalived。
在第一臺節點(設定為master)上修改keepalived的配置如下:
! Configuration File for keepalived
global_defs {
router_id kad_01 #節點標識,要全域性唯一
}
vrrp_instance tidb_ha {
state MASTER #節點角色
interface ens192 #這裡設定成自己的網路卡名字,標識繫結到哪個網路卡
virtual_router_id 51 #虛擬路由id,同一組主備節點要相同
priority 100 #優先順序,要確保master的優先順序比backup的高
advert_int 1 #主備之間檢查頻率為1秒
authentication {
auth_type PASS
auth_pass tidb666 #主備之間的認證密碼
}
virtual_ipaddress {
10.3.65.200 #設定繫結的虛擬IP
}
}
這裡只演示了最基礎的幾個配置,它還可以用更多的配置實現複雜功能,可以參考其他資料實現。
然後啟動服務:
[root@localhost haproxy]# systemctl start keepalived
[root@localhost haproxy]# systemctl status keepalived
可以看到當前keepalived已經是active (running)
狀態,虛擬IP已經繫結到了網路卡上:
我們用虛擬IP為入口驗證一下是否能夠登入到TiDB中:
發現登入成功。
用相同的方式,用如下配置檔案在第二個節點啟動keepalived服務:
! Configuration File for keepalived
global_defs {
router_id kad_02 #節點標識,要全域性唯一
}
vrrp_instance tidb_ha {
state BACKUP #節點角色
interface eth0 #這裡設定成自己的網路卡名字,標識繫結到哪個網路卡
virtual_router_id 51 #虛擬路由id,同一組主備節點要相同
priority 50 #優先順序,要確保master的優先順序比backup的高
advert_int 1 #主備之間檢查頻率為1秒
authentication {
auth_type PASS
auth_pass tidb666 #主備之間的認證密碼
}
virtual_ipaddress {
10.3.65.200 #設定繫結的虛擬IP
}
}
這裡要注意router_id、state、priority要與第一個節點不同。
接著我模擬master節點故障,直接把它關機:
[root@localhost haproxy]# poweroff
Connection closing...Socket close.
Connection closed by foreign host.
Disconnected from remote host(centos-9) at 20:38:16.
Type `help' to learn how to use Xshell prompt.
[C:\~]$
退出連線後再次登入,發現依然正常:
另外一點使用HAProxy的彩蛋是,Prometheus官方已經出了HAProxy的exporter,而且從HAProxy 2.0開始已經自己提供了prometheus-exporter,這意味著我們可以很方便的把對HAProxy的監控整合到TiDB的監控體系中。
限於篇幅,以後再介紹詳細。
LVS
LVS支援三種工作模式,每種模式的工作原理這裡不做介紹,大家去參考其他資料,每一種模式的配置方式都不同,我只列出它們之間的對比結果:
我以使用最廣泛的DR模式來介紹配置過程,相比HAProxy它在網路上的配置要複雜一些。
從DR的工作原理可以得知,LVS所在的主機和它後面的真實服務主機都需要繫結同一個虛擬IP。
先配置LVS的主機,複製一份預設網路卡的配置進行修改:
[root@localhost ~]# cd /etc/sysconfig/network-scripts
[root@localhost network-scripts]# cp ifcfg-eth0 ifcfg-eth0:1
[root@localhost network-scripts]# vi ifcfg-eth0:1
TYPE="Ethernet"
PROXY_METHOD="none"
BROWSER_ONLY="no"
BOOTPROTO="static"
DEFROUTE="yes"
IPV4_FAILURE_FATAL="no"
IPV6INIT="yes"
IPV6_AUTOCONF="yes"
IPV6_DEFROUTE="yes"
IPV6_FAILURE_FATAL="no"
IPV6_ADDR_GEN_MODE="stable-privacy"
IPADDR=10.3.65.201 # 這裡配置虛擬IP
NETMASK=255.255.255.0
NAME="eth0:1"
DEVICE="eth0:1"
ONBOOT="yes"
~
[root@localhost network-scripts]# systemctl restart network
接著對TiDB節點進行網路卡配置:
[root@localhost ~]# cd /etc/sysconfig/network-scripts
[root@localhost network-scripts]# cp ifcfg-lo ifcfg-lo:1
[root@localhost network-scripts]# vi ifcfg-lo:1
DEVICE=lo:1
IPADDR=10.3.65.201
NETMASK=255.255.255.255
NETWORK=127.0.0.0
# If you're having problems with gated making 127.0.0.0/8 a martian,
# you can change this to something else (255.255.255.255, for example)
BROADCAST=127.255.255.255
ONBOOT=yes
NAME=loopback
~
[root@localhost network-scripts]# systemctl restart network
[root@localhost network-scripts]# vi /etc/sysctl.conf # 這裡新增下面顯示的幾條配置
[root@localhost network-scripts]# sysctl -p
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.default.arp_ignore = 1
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
[root@localhost network-scripts]# route add -host 10.3.65.201 dev lo:1
Linux核心從2.4版本開始就已經整合了LVS,所以我們不用單獨安裝了,這裡只需要安裝它的管理工ipvsadmin。
[root@localhost ~]# yum install ipvsadm
[root@localhost ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
通過ipvsadm新增LVS節點資訊:
[root@localhost ~]# ipvsadm -A -t 10.3.65.201:4000 -s wrr -p 5 #這裡新增虛擬IP,使用加權輪詢策略
然後把TiDB節點也新增進去:
[root@localhost network-scripts]# ipvsadm -a -t 10.3.65.201:4000 -r 10.3.65.126:4000 -g
這裡的-t引數指定LVS節點虛擬IP,-r引數指定後面的真實服務節點也就是TiDB的訪問埠,如果有多個TiDB節點就每個都加入。
準備就緒以後,我們把當前的資訊儲存到LVS配置檔案中,然後啟動服務即可:
[root@localhost network-scripts]# ipvsadm --save > /etc/sysconfig/ipvsadm
[root@localhost network-scripts]# cat /etc/sysconfig/ipvsadm
-A -t 10.3.65.201:4000 -s wrr
-a -t 10.3.65.201:4000 -r 10.3.65.126:4000 -g -w 1
[root@localhost network-scripts]# systemctl start ipvsadm
啟動以後通過虛擬IP來登入到TiDB中,發現登入成功:
LVS的高可用方案與前面提到的HAProxy類似,都是使用keepalived來實現,為了避免大量重複內容,這裡只給出Master的關鍵配置:
! Configuration File for keepalived
global_defs {
router_id kad_01 #節點標識,要全域性唯一
}
vrrp_instance tidb_ha {
state MASTER #節點角色
interface eth0 #這裡設定成自己的網路卡名字,標識繫結到哪個網路卡
virtual_router_id 51 #虛擬路由id,同一組主備節點要相同
priority 100 #優先順序,要確保master的優先順序比backup的高
advert_int 1 #主備之間檢查頻率為1秒
authentication {
auth_type PASS
auth_pass tidb666 #主備之間的認證密碼
}
virtual_ipaddress {
10.3.65.201 #設定繫結的虛擬IP
}
virtual_server 10.3.65.201 4000 {
delay_loop 6 #服務輪詢的時間間隔
lb_algo wrr #加權輪詢排程,排程演算法有 rr|wrr|lc|wlc|lblc|sh|sh
lb_kind DR #LVS工作模式 NAT|DR|TUN
persistence_timeout 50 #會話保持時間
protocol TCP #健康檢查協議
# 真實的後臺服務,這裡配TiDB訪問資訊,每個TiDB節點配置一個real_server
real_server 10.3.65.126 4000 {
weight 1
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
connect_port 4000
}
}
}
}
Backup節點配置參考前面的修改即可,更多詳細配置可以去網上搜尋。
Weir
網上關於Weir的資訊並不多,有用的資料都來自Github主頁的文件,Weir的架構和原理可以參考這篇文章:https://asktug.com/t/topic/93717,這裡只總結一下如何去快速使用。
首先從Github拉取原始碼編譯安裝:
[root@localhost ~]# git clone https://github.com/tidb-incubator/weir
[root@localhost ~]# cd weir
[root@localhost ~]# make weirproxy
它涉及到兩個配置檔案,一個和proxy相關(weir預設埠是6000),一個和namespace相關,都在conf目錄下。簡單起見,proxy的配置我不做任何修改都用預設值,只改一下namespace配置裡和TiDB有關的引數:
[root@localhost weir]# vi conf/namespace/test_namespace.yaml
version: "v1"
namespace: "test_namespace"
frontend:
allowed_dbs:
- "test"
slow_sql_time: 50
sql_blacklist:
denied_ips:
idle_timeout: 3600
users:
- username: "weir"
password: "111111"
backend:
instances:
- "10.3.65.126:4000"
username: "root"
password: ""
selector_type: "random"
pool_size: 10
idle_timeout: 60
~
詳細的配置引數可以參考官方文件。
修改好配置後執行啟動檔案:
[root@localhost weir]# ./bin/weirproxy &
通過Weir暴露的入口登入到TiDB,發現登入成功:
這裡要注意的是,MySQL客戶端登入時使用的賬號密碼是namespace中設定的資訊,不再是TiDB原本的賬號密碼。
Weir的高可用方案官方介紹的不多,沒有提供原生的高可用支援。從某個角度來看,Weir更像是TiDB SQL層的一個HTTP擴充套件,所以也是無狀態服務,如果部署多個Weir來做叢集的話,那麼它的上層就需要引入像Nginx或HAProxy這樣的負載均衡元件,問題好像一下子回到最開始了。
與前面兩種方案相比,Weir實施起來稍微有點重,不過它勝在支援前面兩種沒有的功能,這就需要大家根據實際情況取捨,還是希望Weir會越做越好。
總結
總體來說,本文介紹的內容都偏TiDB外側的東西,看似關係不大但是又很重要,一旦用了TiDB就不得不考慮負載均衡的問題,希望本文能給大家帶來一些幫助。