探索雲原生技術之基石——Docker容器
文章目錄
什麼是雲原生
什麼是 Docker
MySQL 主從複製(1 主 1 從)
-
Master 節點配置
-
Slave 節點配置
-
測試主從同步
-
主從同步失敗問題(Slave_SQL_Running:No)
-
Slave_SQL_Running:No 的解決辦法
Redis 集羣(3 主 6 從)
-
10 億條數據怎麼進行緩存
-
哈希取餘算法(小廠採用)
-
一致性 hash 算法(中大廠採用)
-
hash 槽算法(大廠採用、和 Redis 集羣也是採用這種)
-
快速搭建 Redis Cluster(3 主 6 從)
-
快速生成 9 個容器實例
-
查看容器實例是否全部啓動
-
配置主從
-
以集羣的方式進入 Redis 客戶端
-
操作 set 命令
-
查看集羣節點信息
-
查看集羣狀態
-
主從切換
-
主從擴容
-
主從縮容
什麼是雲原生
Pivotal 公司的 Matt Stine 於 2013 年首次提出雲原生(Cloud-Native)的概念;2015 年,雲原生剛推廣時,Matt Stine 在《遷移到雲原生架構》一書中定義了符合雲原生架構的幾個特徵:12 因素、微服務、自敏捷架構、基於 API 協作、扛脆弱性;到了 2017 年,Matt Stine 在接受 InfoQ 採訪時又改了口風,將雲原生架構歸納爲模塊化、可觀察、可部署、可測試、可替換、可處理 6 特質;而 Pivotal 最新官網對雲原生概括爲 4 個要點:DevOps + 持續交付 + 微服務 + 容器。
總而言之,符合雲原生架構的應用程序應該是:採用開源堆棧(K8S+Docker)進行容器化,基於微服務架構提高靈活性和可維護性,藉助敏捷方法、DevOps 支持持續迭代和運維自動化,利用雲平臺設施實現彈性伸縮、動態調度、優化資源利用率。
什麼是 Docker
-
Docker 是一個開源的應用容器引擎,基於 Go 語言開發。
-
Docker 可以讓開發者打包他們的應用以及依賴包到一個輕量級、可移植的容器中,然後發佈到任何流行的 Linux 機器上,也可以實現虛擬化。
-
容器是完全使用沙箱機制(容器實例相互隔離),容器性能開銷極低(高性能)。
總而言之:
Docker 是一個高性能的容器引擎;
可以把本地源代碼、配置文件、依賴、環境通通打包成一個容器即可以到處運行;
使用 Docker 安裝軟件十分方便,而且安裝的軟件十分精簡,方便擴展。
MySQL 主從複製(1 主 1 從)
Master 節點配置
- 運行一個 mysql 容器實例。作爲 Master 節點
- 創建 my.cnf 文件(也就是 mysql 的配置文件)
- 將內容粘貼進 my.cnf 文件
- 重啓該 mysql 容器實例
- 進入容器內部,並登陸 mysql
- 在 Master 節點的 MySQL 中創建用戶和分配權限
在主數據庫創建的該帳號密碼只是用來進行同步數據。
Slave 節點配置
- 運行一個 MySQL 容器實例,作爲 slave 節點(從節點)
- 創建 my.cnf 文件(也就是 mysql 的配置文件)
- 將內容粘貼進 my.cnf 文件
- 重啓該 mysql 容器實例
- 查看容器實例是否都是 up
[root@aubin ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2c4136668536 mysql:5.7 "docker-entrypoint.s…" 3 minutes ago Up 9 seconds 33060/tcp, 0.0.0.0:3308->3306/tcp, :::3308->3306/tcp mysql-slave
20fc7174d1a7 mysql:5.7 "docker-entrypoint.s…" 15 hours ago Up 8 minutes 33060/tcp, 0.0.0.0:3307->3306/tcp, :::3307->3306/tcp mysql-master
- 進入 Master 節點查看主從同步狀態
- 進入從機 MySQL
- 在從數據庫(slave)配置主從同步(重點)
在 Master 節點中找到 ens33 的 ip 地址並放到下面的 master_host 中(記住這個 ip 是 Master 數據庫的服務器 ip,不是從數據庫的):
記住下面這個命令要在從(slave)數據庫執行:
change master to master_host='192.168.184.132',master_user='slave',
master_password='123456',master_port=3307,master_log_file='order-
mysql-bin.000001',master_log_pos=617,master_connect_retry=30;
配置參數解析
-
master_host:主數據庫(Master)的 ip 地址
-
master_user:在 Master 數據庫中創建的用來進行同步的帳號
-
master_password:在 Master 數據庫中創建的用來進行同步的帳號的密碼
-
master_port:Master 數據庫的 MySQL 端口號,這裏是 3307
-
master_log_file:MySQL 的 binlog 文件名
-
master_log_pos:binlog 讀取位置
- 在從數據庫(slave)查看主從同步狀態:
我們找到裏面的 Slave_IO_Running: No,Slave_SQL_Running: No 屬性,發現都是 No 的狀態,證明主從同步還沒有開始。。。
- 在從數據庫(slave)正式開啓主從同步
- 再次在從數據庫中查看主從同步狀態
我們可以看到已經都爲 yes 了,說明主從同步已經開啓。
測試主從同步
在 Master 數據庫執行:
- 創建數據庫
- 使用數據庫
- 創建表(表是我從之前寫的項目中拿的)
- 插入數據
- 查詢數據庫表(在 Master 數據庫執行)
- 切換從數據庫機器(在 slave 數據庫執行)
- 查詢數據庫表(在 slave 數據庫執行)
- Docker+MySQL 主從同步搞定!
也可以用 Navicat 去連接這兩個數據庫。如果 Navicat 出現連接不了 docker 的 mysql,則可以:
方法一:關閉防火牆(測試環境用,生產環境不可以用)
方法二:開放防火牆對應端口,比如 master 數據庫的 3307 和 slave 數據庫的 3308(生產環境用這個)
主從同步失敗問題(Slave_SQL_Running:No)
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.184.132
Master_User: slave
Master_Port: 3307
Connect_Retry: 30
Master_Log_File: order-mysql-bin.000001
Read_Master_Log_Pos: 3752
Relay_Log_File: 2c4136668536-relay-bin.000002
Relay_Log_Pos: 326
Relay_Master_Log_File: order-mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: No
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 1007
Last_Error: Error 'Can't create database 'mall';
database exists' on query. Default database:
'mall'. Query: 'create database mall'
-
Slave_SQL_Running 爲 No 的狀態,那麼這是爲什麼呢?
-
可以看到 Last_Error: Error ‘Can’t create database ‘mall’; database exists’ on query. Default database: ‘mall’. Query: ‘create database mall’
-
原因是主數據庫(Master)和從數據庫(slave)不一致造成的,我在從數據庫執行了命令導致數據不一致,最終導致主從複製失敗。
Slave_SQL_Running:No 的解決辦法
1:把主數據庫和從數據庫變成一模一樣,也就是把多餘的數據庫和表刪除掉,變成默認的 mysql 狀態。(切記生產環境下要做好數據備份!!!)
2:結束同步:
3:再次開啓同步:
4:搞定!
Redis 集羣(3 主 6 從)
10 億條數據怎麼進行緩存
-
這麼大量的數據放在一個 Redis 裏面顯然是不行的,所以我們必須進行搭建分佈式的 Redis 集羣進行存儲。
-
那麼我們如何確定每一條數據存放在哪一個 Redis 中呢?我們有如下三種方法。
哈希取餘算法(小廠採用)
過程
1:假設一共有 5 臺 Redis 服務器,編號分別爲:0 1 2 3 4,服務器臺數爲 count=5
2:先把 key(關鍵字)進行哈希後產生一個哈希值爲 val,假設這個 val 爲 22
3:再用哈希取餘算法公式:val%count,也就是 22%5=2
4:那麼就定位到 3 號(0 爲 1 號機器),那麼該數據就插入 3 號 Redis 機器中
缺點:
1:Redis 節點擴容十分麻煩,如果此時從 5 臺機器變成 10 臺,那麼我們需要去修改哈希取餘算法的公式,不利於擴展。
2:又或者是縮容也十分麻煩,如果有一臺服務器宕機了,在線機器從 5->4 臺,那麼也需要去修改哈希取餘算法公式。
一致性 hash 算法(中大廠採用)
圖解:
先虛擬一個哈希環, 記錄我們機器的 ip 的 hash 對應到哈希環中:
將對象的關鍵字 key 進行 hash,順時針尋找我們的機器,如果機器還在線就插入:
過程
1:虛擬一個哈希環(類似於大小爲 2^32 的數組 arr),即 0 ~ (2^32)-1 的空間中。
2:對我們所有的 Redis 節點所在的服務器 IP 或者主機名進行 hash,得到的這個 hash 值記錄下來。
3:先把 key(關鍵字)進行 hash 後產生一個 hash 值爲 val
4:把這個 val 當成數組的下標進行遍歷(也就是從這個位置順時針遍歷哈希環)一旦遇到 Redis 節點的 hash 值則進行插入,如果該節點宕機了則插入失敗,這個時候我們就會跳過這個 Redis 節點繼續順時針搜索合適的節點,直到插入成功或者遍歷完整個哈希環(當然此時是最壞情況)。
5:如果有新增的節點就按照第 2 步操作即可
6:如果 Redis 節點被刪除或者宕機了,就移除這個記錄的節點即可。
優點:
方便擴容和縮容,不需要和哈希取餘算法一樣更改算法公式,擴展性很好。
是因爲哈希環的大小是 2^32,幾乎涵蓋了所有 hash 值的可能。
缺點:
-
缺點也是十分明顯的,當我們的 Redis 節點過少時,會造成數據傾斜問題。這種問題也是十分致命的。
-
因此該算法小廠不適合用,中大廠在多節點的情況下采用效果會更好。
hash 槽算法(大廠採用、和 Redis 集羣也是採用這種)
1:由於一致性 hash 算法會導致數據傾斜問題,而 hash 槽可以避免這個問題。
2:Redis 的 hash 槽大小固定爲:16384 個。
3:將 hash 槽均勻分配到各個 Master 節點上(注意:slave 節點不會被分配)
4:假如有三個 Redis 節點,則會分配成 5461:5462:5461
-
Redis 的 1 號節點:負責 0-5460 號槽位
-
Redis 的 2 號節點:負責 5461-10922 號槽位
-
Redis 的 3 號節點:負責 10923-16383 號槽位
5:將關鍵字(key)進行 hash 取值,並且映射到對應的 hash 槽位上。
6:如果需要擴容或者縮容,只需要重新分配槽位即可。
快速搭建 Redis Cluster(3 主 6 從)
搭建的集羣爲:3 主 6 從。
其中內部是 1 個 Master 主節點對應 2 個 slave 從節點
快速生成 9 個容器實例
- 由於我們搭建 3 主 6 從,所以需要 9 個 Redis 容器實例。這裏的 Redis 都是最新版,如果需要改變版本,只需要把下面的版本換成你需要指定的版本即可。
查看容器實例是否全部啓動
配置主從
-
隨便進入一個 Redis 容器(我們這裏選擇 redis-node-2,其實都行),執行下面命令
-
下面的 ip 需要修改成 Redis 所在的服務器的 ip。
-
如果需要輸入內容,則輸入:yes
-
–cluster-replicas 2:意味着 Master 和 slave 是以 1 比 2 的形式生成。
-
Redis 集羣至少需要 3 個 Master 節點,意味着每個 Master 對應 replicas 爲 2 個 slave 節點。
-
如果–cluster-replicas 1,那麼就是說 1 個 Master 節點對應 1 個 slave 節點。
以集羣的方式進入 Redis 客戶端
-
只需要多加一個 - c 即表示集羣方式進入客戶端。
-
別忘了指定端口號。因爲 Redis 默認是 6379 端口!!!!!
-
如果搭建了 Redis 集羣,而不使用 Redis 集羣的方式進入客戶端會怎樣?
-
上面說過,Redis 集羣是通過 hash 槽進行存儲 kv 鍵值對數據的,這種情況下,當我們進入 1 號 Redis 節點進行 set 值,如果剛好這個 set 的 key 的 hash 值剛好分配到我們當前所在的 1 號節點,那麼就可以插入成功。
-
如果這個 key 的 hash 值分配到其他節點比如 2,3 號這些節點,則會插入失敗。因爲這個連接沒有用集羣的方式進入客戶端。
-
只有我們使用集羣的方式進入客戶端才能隨意插入數據,否則只能看緣分插入!!!!!!!!
操作 set 命令
- 可以看到 Redis 集羣底層都是通過 hash 槽算法分區。
查看集羣節點信息
查看集羣狀態
主從切換
- 我們可以看到 6381、6382、6383 是 Master 節點。
-
可以看出 6381 的從節點是:6389、6386
-
把 6381 的容器實例給 stop 掉。
- 先過一會,再次查看集羣節點
192.168.184.132:6383> CLUSTER NODES
c9d7f4ed642fa2fde013f2b060476b542b9af76e 192.168.184.132:6385
@16385 slave af28288480e3398b18402e4475c9ae52c39ea776 0
1651767445299 3 connected
9ef7a5bb156de64a969688eade8535399983dd00 192.168.184.132:6389
@16389 slave 29a79c9f9a007bf80fdfc2ffaaf1cf27d29396c2 0
1651767443000 10 connected
888158ad30d9a173175b115974b9d1cc5b39736e 192.168.184.132:6381
@16381 master,fail - 1651767320800 1651767314000 1 disconnected
1ff5a2a15526e3d7984b231cf7e47f8f442e4a9e 192.168.184.132:6382
@16382 master - 0 1651767444000 2 connected 5461-10922
29a79c9f9a007bf80fdfc2ffaaf1cf27d29396c2 192.168.184.132:6386
@16386 master - 0 1651767444000 10 connected 0-5460
92d06bfb428a1358149c209c336152cae3304c66 192.168.184.132:6388
@16388 slave af28288480e3398b18402e4475c9ae52c39ea776 0
1651767443000 3 connected
af28288480e3398b18402e4475c9ae52c39ea776 192.168.184.132:6383
@16383 myself,master - 0 1651767443000 3 connected 10923-16383
5b20d04646f7f38eb57266b81749e565825ab6e5 192.168.184.132:6387
@16387 slave 1ff5a2a15526e3d7984b231cf7e47f8f442e4a9e 0
1651767444284 2 connected
a11993ddc7a726e3ad476858fb53bdc97d4834b8 192.168.184.132:6384
@16384 slave 1ff5a2a15526e3d7984b231cf7e47f8f442e4a9e 0
1651767446319 2 connected
我們可以看到以前 6381 的從節點 6386 變成了 Master 節點。說明已經進行主從切換了。
- 如果此時重新啓動 6381 的容器
docker start redis-node-1
192.168.184.132:6383> CLUSTER NODES
c9d7f4ed642fa2fde013f2b060476b542b9af76e 192.168.184.132:6385
@16385 slave af28288480e3398b18402e4475c9ae52c39ea776 0
1651767586000 3 connected
9ef7a5bb156de64a969688eade8535399983dd00 192.168.184.132:6389
@16389 slave 29a79c9f9a007bf80fdfc2ffaaf1cf27d29396c2 0
1651767586183 10 connected
888158ad30d9a173175b115974b9d1cc5b39736e 192.168.184.132:6381
@16381 slave 29a79c9f9a007bf80fdfc2ffaaf1cf27d29396c2 0
1651767582247 10 connected
1ff5a2a15526e3d7984b231cf7e47f8f442e4a9e 192.168.184.132:6382
@16382 master - 0 1651767586000 2 connected 5461-10922
29a79c9f9a007bf80fdfc2ffaaf1cf27d29396c2 192.168.184.132:6386
@16386 master - 0 1651767588204 10 connected 0-5460
92d06bfb428a1358149c209c336152cae3304c66 192.168.184.132:6388
@16388 slave af28288480e3398b18402e4475c9ae52c39ea776 0
1651767586000 3 connected
af28288480e3398b18402e4475c9ae52c39ea776 192.168.184.132:6383
@16383 myself,master - 0 1651767587000 3 connected 10923-16383
5b20d04646f7f38eb57266b81749e565825ab6e5 192.168.184.132:6387
@16387 slave 1ff5a2a15526e3d7984b231cf7e47f8f442e4a9e 0
1651767585000 2 connected
a11993ddc7a726e3ad476858fb53bdc97d4834b8 192.168.184.132:6384
@16384 slave 1ff5a2a15526e3d7984b231cf7e47f8f442e4a9e 0
1651767587192 2 connected
我們可以看到 6381 變成了從節點(slave),主節點(Master)是 6386。
主從擴容
-
啓動三個 Redis 容器實例,分別爲 6390、6391、6392
-
目的是配置 6390 爲 Master 節點加入集羣,6391 和 6392 爲 6390 的 Slave 節點
- 查看 docker 實例是否全部啓動
-
首先將主節點 6390(Master)添加進集羣中。
-
192.168.184.132:6390:是你想要加入的 Redis 節點 ip + 端口號
-
192.168.184.132:6383:隨便一個集羣中的 Master 節點的 ip + 端口(這個 Master 代表着整個集羣,必須得是 Master 節點)
- 檢查一下集羣
發現 6390 已經成功加入到集羣,並且是 Master 節點,但是沒有被分配槽位,slots 爲 0。需要分配槽位纔有用
- 重新分配槽位,下面的 6386 也是 Master 節點,哪個 Master 節點都行
-
因爲我們是 4 個 Master 節點,所以是 16384/4=4096,所以輸入:4096
-
再輸入新加入的 6390Master 節點的容器 id,輸入:a25da2e5be0487b3109b23e807b2d4c9c23e5a1a
-
再輸入:all ,回車
-
輸入:yes
-
檢查一下集羣:
-
搞定,擴容成功。
-
添加 6390 的從節點(6391 和 6392)
-
xxxxx1 和 xxxxx2 替換成:6390(也就是想加入的 Master 節點)的 id
- 再次檢查集羣
主從縮容
-
目的是移除 6390(Master)和 6391、6392(Slave)。
-
刪除從節點 6391。xxx1 替換成:6391 的容器 id
- 刪除從節點 6392。xxx2 替換成:6392 的容器 id
-
刪除 Master 節點 6390 之前,必須先把槽位給其他 Master 節點。
-
xxxxxx1:隨便一個 Master 節點,我們這裏指定 6386
-
輸入刪除的槽位數:因爲 6390 的槽位是 4096 個,所以輸入:4096
-
再輸入誰來接收這些殘留下來的槽位的容器 id,我們這裏把 4096 個都給 6383,所以輸入 6383 的容器 id:af28288480e3398b18402e4475c9ae52c39ea776(哪個 Master 節點都行)
-
再輸入刪除的這個 Master 節點的 id,也就是 6390 的容器 id:a25da2e5be0487b3109b23e807b2d4c9c23e5a1a
-
再輸入:done
-
再輸入:yes
此時 6390 的槽位已經全部給了 6383,這個時候可以刪除 6390 節點了。xxx1 爲 6390 的容器 id
- 再次檢查一下集羣
- 主從縮容搞定了。
來源:
https://blog.csdn.net/weixin_50071998/article/details/124751540
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/TKxDtU-z8qtf_oI0GX0eSQ