DevRel領域專家Denis Magda表示,他偶然發現了一篇解釋如何用PostgreSQL無縫替換etcd的文章。該文章指出,Kine項目作為外部etcd端點,可以將Kubernetes etcd請求轉換為底層關系數據庫的SQL查詢。
受到這種方法的啟發,Magda決定進一步探索Kine的潛力,從etcd切換到YugabyteDB。YugabyteDB是一個基于PostgreSQL構建的分布式SQL數據庫。
etcd有什么問題?
etcd是Kubernetes用來存放所有集群數據的鍵值庫。
在Kubernetes集群遇到可擴展性或高可用性(HA)問題之前,它通常不會引起人們的注意。以可擴展和高可用性(HA)的方式管理etcd對于大型Kubernetes部署來說尤其具有挑戰性。
此外,Kubernetes社區對etcd項目的未來開發也有越來越多的擔憂。它的社區規模正在縮小,只有少數維護人員有興趣和能力支持和推進這個項目。
這些問題催生了Kine,這是一個etcd API到SQL的轉換層。Kine正式支持SQLite、PostgreSQL和MySQL,這些系統的使用量正在不斷增長,并且擁有強大的社區。
為什么選擇分布式SQL數據庫?
雖然PostgreSQL、SQLite和MySQL是Kubernetes的理想選擇,但它們是為單一服務器部署而設計和優化的。這意味著它們可能會帶來一些挑戰,特別是對于具有更嚴格的可擴展性和可用性要求的大型Kubernetes部署。
如果開發人員的Kubernetes集群要求RPO(恢復點目標)為零,RTO(恢復時間目標)以秒為單位測量,那么MySQL或PostgreSQL部署的架構和維護將是一個挑戰。如果人們有興趣深入研究這個話題,可以探索PostgreSQL的高可用性選項。
分布式SQL數據庫作為一個相互連接的節點集群,可以跨多個機架、可用區或區域部署。通過設計,它們具有高可用性和可擴展性,因此可以為Kubernetes改進相同的特性。
在YugabyteDB上啟動Kine
而決定使用YugabyteDB作為Kubernetes的分布式SQL數據庫是受到PostgreSQL的影響。YugabyteDB建立在PostgreSQL源代碼的基礎上,在提供自己的分布式存儲實現的同時,重用了PostgreSQL的上半部分(查詢引擎)。
YugabyteDB和PostgreSQL之間的緊密聯系允許開發人員為YugabyteDB重新設計PostgreSQL的Kine實現。然而需要繼續關注,這不會是一個簡單的提升和轉移的故事。
現在,將這些想法轉化為行動,并在YugabyteDB上啟動Kine。為此,使用了一個配備了8個CPU和32GB內存的Ubuntu22.04虛擬機。
首先,在虛擬機上啟動一個三個節點的YugabyteDB集群。在進行分布式之前,可以在單個服務器上對分布式SQL數據庫進行試驗。有多種方法可以在本地啟動YugabyteDB,但作者更喜歡的方法是通過Docker:
Shell mkdir ~/yb_docker_datadocker network create custom-networkdocker run -d --name yugabytedb_node1 --net custom-network \-p 15433:15433 -p 7001:7000 -p 9000:9000 -p 5433:5433 \-v ~/yb_docker_data/node1:/home/yugabyte/yb_data --restart unless-stopped \yugabytedb/yugabyte:latest \bin/yugabyted start --tserver_flags="ysql_sequence_cache_minval=1" \--base_dir=/home/yugabyte/yb_data --daemon=falsedocker run -d --name yugabytedb_node2 --net custom-network \-p 15434:15433 -p 7002:7000 -p 9002:9000 -p 5434:5433 \-v ~/yb_docker_data/node2:/home/yugabyte/yb_data --restart unless-stopped \yugabytedb/yugabyte:latest \bin/yugabyted start --join=yugabytedb_node1 --tserver_flags="ysql_sequence_cache_minval=1" \--base_dir=/home/yugabyte/yb_data --daemon=falsedocker run -d --name yugabytedb_node3 --net custom-network \-p 15435:15433 -p 7003:7000 -p 9003:9000 -p 5435:5433 \-v ~/yb_docker_data/node3:/home/yugabyte/yb_data --restart unless-stopped \yugabytedb/yugabyte:latest \bin/yugabyted start --join=yugabytedb_node1 --tserver_flags="ysql_sequence_cache_minval=1" \--base_dir=/home/yugabyte/yb_data --daemon=false
注:在啟動YugabyteDB節點時設置ysql_sequence_cache_minval=1,以確保數據庫序列可以按順序遞增1。如果沒有這個選項,一個Kine連接到YugabyteDB將緩存序列的下一個100個ID。這可能導致在Kubernetes集群引導期間出現“版本不匹配”錯誤,因為一個Kine連接可能插入ID范圍從1到100的記錄,而另一個Kine連接可能插入ID范圍從101到200的記錄。
接下來,使用PostgreSQL實現啟動一個連接到YugabyteDB的Kine實例:
(1)克隆Kine庫:
Shell
1 git clone https://github.com/k3s-io/kine.git && cd kine
(2)啟動一個連接到本地YugabyteDB集群的Kine實例:
Shell
1 go run . --endpoint postgres://yugabyte:yugabyte@127.0.0.1:5433/yugabyte
(3)連接YugabyteDB,確認Kine架構已準備就緒:
SQL psql -h 127.0.0.1 -p 5433 -U yugabyteyugabyte=# \dList of relationsSchema | Name | Type | Owner--------+-------------+----------+----------public | kine | table | yugabytepublic | kine_id_seq | sequence | yugabyte
(2 rows)
很好,第一次測試成功了。Kine將YugabyteDB視為PostgreSQL,并且啟動時沒有任何問題。現在進入下一個階段:使用YugabyteDB在Kine之上啟動Kubernetes。
使用YugabyteDB在Kine上啟動Kubernetes
Kine可以被各種Kubernetes引擎使用,包括標準的Kubernetes部署、Rancher Kubernetes引擎(RKE)或K3?(一種輕量級的Kubernetes引擎)。為簡單起見,將使用后者。
K3s集群可以通過一個簡單的命令啟動:
(1)停止上一節中啟動的Kine實例。
(2)啟動連接到相同本地YugabyteDB集群的K3s(K3s可執行文件隨Kine提供):
Shell
curl -sfL https://get.k3s.io | sh -s - server --write-kubeconfig-mode=644 \--token=sample_secret_token \
--datastore-endpoint="postgres://yugabyte:yugabyte@127.0.0.1:5433/yugabyte"
(3)Kubernetes啟動時應該沒有問題,可以通過運行以下命令來確認:
Shell k3s kubectl get nodesNAME STATUS ROLES AGE VERSIONubuntu-vm Ready control-plane,master 7m13s v1.27.3+k3s1
Kubernetes在YugabyteDB上無縫運行。這要歸功于YugabyteDB很好的特性和與PostgreSQL的運行時兼容性。這意味著可以重用為PostgreSQL創建的大多數庫、驅動程序和框架。
這可能標志著這一旅程的結束,可以回顧一下K3s日志。在Kubernetes引導期間,日志可能會報告緩慢的查詢,如下所示:
SQL INFO[0015] Slow SQL(total time: 3s) :SELECT*FROM (SELECT(SELECTMAX(rkv.id) AS idFROMkine AS rkv),(SELECTMAX(crkv.prev_revision) AS prev_revisionFROMkine AS crkvWHEREcrkv.name = 'compact_rev_key'), kv.id AS theid, kv.name, kv.created, kv.deleted, kv.create_revision, kv.prev_revision, kv.lease, kv.value, kv.old_valueFROMkine AS kvJOIN (SELECTMAX(mkv.id) AS idFROMkine AS mkvWHEREmkv.name LIKE $1GROUP BYmkv.name) AS maxkv ON maxkv.id = kv.idWHEREkv.deleted = 0OR $2) AS lkvORDER BYlkv.theid ASCLIMIT 10001
在一臺機器上運行YugabyteDB時,這可能不是一個重要的問題,但是一旦切換到分布式設置,這樣的查詢就會成為熱點并產生瓶頸。
因此克隆了Kine源代碼,并開始探索PostgreSQL實現,尋找潛在的優化機會。
YugabyteDB的Kine優化
在這里,Magda與Franck Pachot合作,Pachot是一位精通SQL層優化的數據庫專家,對應用程序邏輯沒有或只有很少的更改。
在檢查了Kine生成的數據庫模式并將EXPLAIN ANALYZE用于某些查詢之后,Franck提出了對任何分布式SQL數據庫都有利的基本優化。
幸運的是,優化不需要對Kine應用程序邏輯進行任何更改。所要做的就是引入一些SQL級別的增強。因此,創建了一個直接支持YugabyteDB的Kine fork。
與此同時,與PostgreSQL相比,YugabyteDB的實現有三個優化:
(1)kine表的主索引已從primary index(id)更改為primary INCEX(id asc)。在默認情況下,YugabyteDB使用哈希分片在集群中均勻分布記錄。然而,Kubernetes在id列上運行了許多范圍查詢,這使得切換到范圍分片是合理的。
(2)通過在索引定義中包括id列,kine_name_prev_revision_uindex索引已被更新為覆蓋索引:
CREATE UNIQUE INDEX IF NOT EXISTS kine_name_prev_revision_uindex ON kine (name asc, prev_revision asc) INCLUDE(id);
YugabyteDB的索引分布類似于表記錄。因此,索引條目可能引用存儲在不同YugabyteDB節點上的id。為了避免節點之間額外的網絡往返,可以將id包含在二級索引中。
(3)Kine在完成Kubernetes請求的同時執行許多連接。如果查詢規劃器/優化器決定使用嵌套循環連接,那么在默認情況下,YugabyteDB查詢層將每次讀取和連接一條記錄。為了加快這個過程,可以啟用批處理嵌套循環連接。YugabyteDB的Kine實現通過在啟動時執行以下語句來實現:
ALTER DATABASE " + dbName + " set yb_bnl_batch_size=1024;
嘗試一下這個優化的YugabyteDB實現。
首先,停止之前的K3s服務,并從YugabyteDB集群中刪除Kine模式:
(1)停止并刪除K3s服務:
Shell sudo /usr/local/bin/k3s-uninstall.shsudo rm -r /etc/rancher
(2)刪除模式:
SQL psql -h 127.0.0.1 -p 5433 -U yugabytedrop table kine cascade;
接下來,啟動一個為YugabyteDB提供優化版本的Kine實例:
(1)克隆fork:
Shell git clone https://github.com/dmagda/kine-yugabytedb.git && cd kine-yugabytedb
(2)啟動Kine:
Shell go run . --endpoint "yugabytedb://yugabyte:yugabyte@127.0.0.1:5433/yugabyte"
Kine的啟動沒有任何問題。現在唯一的區別是,不是在連接字符串中指定“postgres”,而是指示“yugabytedb”以啟用優化的YugabyteDB實現。關于Kine和YugabyteDB之間的實際通信,Kine繼續使用Go的標準PostgreSQL驅動程序。
在Kine的優化版本上構建Kubernetes
最后,在這個優化版本的Kine上啟動k3。
要做到這一點,首先需要從資源中構建k3:
(1)停止上一節中啟動的Kine實例。
(2)克隆K3s存儲庫:
Shell git clone --depth 1 https://github.com/k3s-io/k3s.git && cd k3s
(3)打開go.mod文件,并在replace(..)部分的末尾添加以下行:
Go github.com/k3s-io/kine => github.com/dmagda/kine-yugabytedb v0.2.0
這條指令告訴Go使用帶有YugabyteDB實現的最新版本的Kinefork。
(4)啟用對私有倉庫和模塊的支持:
Shell go env -w GOPRIVATE=github.com/dmagda/kine-yugabytedb
(5)確保更改生效:
Shell go mod tidy
(6)準備構建K3s的完整版本:
Shell mkdir -p build/data && make download && make generate
(7)構建完整版本:
Shell SKIP_VALIDATE=true make
完成構建大約需要五分鐘。
注意:一旦停止使用這個自定義K3s構建,可以按照說明卸載它。
在優化的Kubernetes版本上運行示例工作負載
在構建完成后,可以使用Kine的優化版本啟動K3s。
(1)導航到包含構建構件的目錄:
Shell cd dist/artifacts/
(2)通過連接到本地YugabyteDB集群啟動K3s:
Shell sudo ./k3s server \--token=sample_secret_token \--datastore-endpoint="yugabytedb://yugabyte:yugabyte@127.0.0.1:5433/yugabyte"
(3)確認Kubernetes啟動成功:
Shell sudo ./k3s kubectl get nodesNAME STATUS ROLES AGE VERSIONubuntu-vm Ready control-plane,master 4m33s v1.27.4+k3s-36645e73
現在,部署一個示例應用程序,以確保Kubernetes集群不僅僅能夠自我引導:
(1)采用Kubernetes克隆一個庫的例子:
Shell git clone https://github.com/digitalocean/kubernetes-sample-apps.git
(2)部署Emojivoto應用:
Shell sudo ./k3s kubectl apply -k ./kubernetes-sample-apps/emojivoto-example/kustomize
(3)確保所有部署和服務成功啟動:
Shell sudo ./k3s kubectl get all -n emojivotoNAME READY STATUS RESTARTS AGEpod/vote-bot-565bd6bcd8-rnb6x 1/1 Running 0 25spod/web-75b9df87d6-wrznp 1/1 Running 0 24spod/voting-f5ddc8ff6-69z6v 1/1 Running 0 25spod/emoji-66658f4b4c-wl4pt 1/1 Running 0 25sNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEservice/emoji-svc ClusterIP 10.43.106.87 <none> 8080/TCP,8801/TCP 27sservice/voting-svc ClusterIP 10.43.14.118 <none> 8080/TCP,8801/TCP 27sservice/web-svc ClusterIP 10.43.110.237 <none> 80/TCP 27sNAME READY UP-TO-DATE AVAILABLE AGEdeployment.apps/vote-bot 1/1 1 1 26sdeployment.apps/web 1/1 1 1 25sdeployment.apps/voting 1/1 1 1 26sdeployment.apps/emoji 1/1 1 1 26sNAME DESIRED CURRENT READY AGEreplicaset.apps/vote-bot-565bd6bcd8 1 1 1 26sreplicaset.apps/web-75b9df87d6 1 1 1 25sreplicaset.apps/voting-f5ddc8ff6 1 1 1 26sreplicaset.apps/emoji-66658f4b4c 1 1 1 26s
(4)使用CLUSTER_IP:80調用服務/web svc以觸發應用程序邏輯:
Shell curl 10.43.110.237:80
應用程序將使用以下HTML進行響應:
HTML <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Emoji Vote</title><link rel="icon" href="/img/favicon.ico"><script async src="https://www.googletagmanager.com/gtag/js?id=UA-60040560-4"></script><script>window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag('js', new Date());gtag('config', 'UA-60040560-4');</script></head><body><div id="main" class="main"></div></body><script type="text/javascript" src="/js" async></script></html>
結語
完成工作!Kubernetes現在可以使用YugabyteDB作為其所有數據的分布式和高可用性SQL數據庫。
現在可以進入下一階段:在跨多個可用性區域和區域的真正云計算環境中部署Kubernetes和YugabyteDB,并測試解決方案如何處理各種中斷。
軟件開發構建工具
JNPF快速開發平臺是一款基于SpringBoot+Vue3的全棧開發平臺,采用微服務、前后端分離架構,基于可視化流程建模、表單建模、報表建模工具,快速構建業務應用,平臺即可本地化部署,也支持K8S部署。
應用體驗地址:https://www.jnpfsoft.com/?csdn,操作一下試試吧!
引擎式軟件快速開發模式,除了上述功能,還配置了圖表引擎、接口引擎、門戶引擎、組織用戶引擎等可視化功能引擎,基本實現頁面UI的可視化搭建。內置有百種功能控件及使用模板,使得在拖拉拽的簡單操作下,也能大限度滿足用戶個性化需求。由于JNPF平臺的功能比較完善,本文選擇這項工具進行展開,使你更加直觀看到低代碼的優勢。