這麼多TiDB負載均衡方案總有一款適合你
【是否原創】是
【首發渠道】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中的最佳實踐官網有一篇文章詳細介紹過,手把手教你如何安裝和配置,地址是//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的架構和原理可以參考這篇文章://asktug.com/t/topic/93717,這裡只總結一下如何去快速使用。
首先從Github拉取源碼編譯安裝:
[root@localhost ~]# git clone //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就不得不考慮負載均衡的問題,希望本文能給大家帶來一些幫助。