前言
心有山水不造作,靜而不爭遠是非
7.叢集
7.1叢集常見的基本形式
叢集的目標
-
高可用:主機當機對業務無影響。
- 當機原因:網路卡、路由器、機房、CPU負載過高、記憶體溢位、自然災害等不可預期的原因導致,也稱單點問題
- 解決方案:【選主式(雙主、raft選舉)】重新建立主節點
-
單點效能限制:當單點資料量過大導致效能降低,所以需要多臺分擔共同儲存整個叢集資料,並且做好互相備份保證即使單點故障,也能在其他節點找到資料
- 解決方案:【分片式(分庫分表)】
-
資料備份容災:單點故障後,儲存的資料仍然可以在別的地方拉起
- 解決方案:【主從複製】
-
壓力分擔:避免單點壓力過高,例如單節點幾千億條資料讀取很慢,分離操作,各單點完成自己的工作完成整個工作
- 解決方案:【讀寫分離】
-
主從複製、讀寫分離可以一起實現
叢集的基礎形式
- 主從式:
- 主從複製:從節點複製主節點資料,保持一致(mysql)
- 主從排程:所有請求由主節點排程,挑一個從節點響應請求(k8s)
- 分片式:(可以看作有多套主從構成分片)
- 資料分片儲存,突破單點限制
- 分片之間互相備份,保證資料不丟失
- 客戶端分片:由客戶端計算實際請求的分片地址(mycat)
- 服務端分片:由服務端計算實際請求的分片地址(redis)
- 例:訂單表,按地區分片,按時間分表
- 選主式:
- 為了容災選主
- 為了排程選主
7.2MySQL-常見叢集形式
叢集原理
MySQL-MMM 是 Master-Master Replication Manager for MySQL(mysql 主主複製管理 器)的簡稱,是 Google 的開源專案 (Perl 指令碼)。MMM 基於 MySQL Replication 做的擴充套件架構,主要用 來監控 mysql 主主複製並做失敗轉 移。其原理是將真實資料庫節點的 IP(RIP)對映為虛擬 IP(VIP)集。 mysql-mmm 的監管端會提供多個 虛擬 IP(VIP),包括一個可寫 VIP, 多個可讀 VIP,透過監管的管理,這 些 IP 會繫結在可用 mysql 之上,當 某一臺 mysql 當機時,監管會將 VIP 遷移至其他 mysql。在整個監管過 程中,需要在 mysql 中新增相關授 權使用者,以便讓 mysql 可以支援監 理機的維護。授權的使用者包括一個mmm_monitor 使用者和一個 mmm_agent 使用者,如果想使用 mmm 的備份工具則還要添 加一個 mmm_tools 使用者。
MHA(Master High Availability)目前在 MySQL 高可用方面是一個相對成熟的解決方案, 由日本 DeNA 公司 youshimaton(現就職於 Facebook 公司)開發,是一套優秀的作為 MySQL高可用性環境下故障切換和主從提升的高可用軟體。在MySQL故障切換過程中, MHA 能做到在 0~30 秒之內自動完成資料庫的故障切換操作(以 2019 年的眼光來說太 慢了),並且在進行故障切換的過程中,MHA 能在最大程度上保證資料的一致性,以 達到真正意義上的高可用。
InnoDB Cluster 支援自動 Failover、強一致性、讀寫分離、讀庫高可用、讀請求負載均 衡,橫向擴充套件的特性,是比較完備的一套方案。但是部署起來複雜,想要解決 router 單點問題好需要新增元件,如沒有其他更好的方案可考慮該方案。 InnoDB Cluster 主 要由 MySQL Shell、MySQL Router 和 MySQL 伺服器叢集組成,三者協同工作,共同為 MySQL 提供完整的高可用性解決方案。MySQL Shell 對管理人員提供管理介面,可以 很方便的對叢集進行配置和管理,MySQL Router 可以根據部署的叢集狀況自動的初始 化,是客戶端連線例項。如果有節點 down 機,叢集會自動更新配置。叢集包含單點寫 入和多點寫入兩種模式。在單主模式下,如果主節點 down 掉,從節點自動替換上來, MySQL Router 會自動探測,並將客戶端連線到新節點。
7.3MySQL-主從同步
主機 | ip |
---|---|
mysql-master | 192.168.188.180:3317 |
mysql-slaver-01 | 192.168.188.180:3327 |
Master
執行一個mysql例項
引數說明
- -p 3307:3306:將容器的 3306 埠對映到主機的 3307 埠 -v
/mydata/mysql/master/conf:/etc/mysql
:將配置資料夾掛在到主機 -v/mydata/mysql/master/log:/var/log/mysql
:將日誌資料夾掛載到主機 -v/mydata/mysql/master/data:/var/lib/mysql
:將配置資料夾掛載到主機 -eMYSQL_ROOT_PASSWORD=root
:初始化 root 使用者的密碼
# 刪除目錄 如果需要清除環境
docker stop mysql-master
docker rm -f mysql-master
rm -rf /mydata/mysql/master/data
rm -rf /mydata/mysql/master/log
rm -rf /mydata/mysql/master/conf
# 建立目錄
mkdir -p /mydata/mysql/master/{data,log}
mkdir -p /mydata/mysql/master/conf/{conf.d,mysql.conf.d}
# 執行
docker run -p 3317:3306 --name mysql-master \
-v /mydata/mysql/master/log:/var/log/mysql \
-v /mydata/mysql/master/data:/var/lib/mysql \
-v /mydata/mysql/master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
修改 master 基本配置
# rm -f /mydata/mysql/master/conf/my.cnf
vim /mydata/mysql/master/conf/my.cnf
my.cnf
注意:skip-name-resolve 一定要加,不然連線 mysql 會超級
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
# 新增 master 主從複製部分配置
server_id=1
log-bin=mysql-bin
# 讀寫
read-only=0
# 只同步業務庫
binlog-do-db=mall_ums
binlog-do-db=mall_pms
binlog-do-db=mall_oms
binlog-do-db=mall_sms
binlog-do-db=mall_wms
binlog-do-db=mall_admin
# 不同步mysql基礎庫
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema
重啟master
docker restart mysql-master
docker logs mysql-master
Slave
執行一個mysql例項
# 刪除目錄 如果需要清除環境
docker stop mysql-slaver-01
docker rm -f mysql-slaver-01
rm -rf /mydata/mysql/slaver/data
rm -rf /mydata/mysql/slaver/log
rm -rf /mydata/mysql/slaver/conf
# 建立目錄
mkdir -p /mydata/mysql/slaver/{data,log}
mkdir -p /mydata/mysql/slaver/conf/{conf.d,mysql.conf.d}
docker run -p 3327:3306 --name mysql-slaver-01 \
-v /mydata/mysql/slaver/log:/var/log/mysql \
-v /mydata/mysql/slaver/data:/var/lib/mysql \
-v /mydata/mysql/slaver/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
修改 slave 基本配置
vim /mydata/mysql/slaver/conf/my.cnf
my.cnf
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
# 新增 master 主從複製部分配置
server-id=2
log-bin=mysql-bin
# 只讀
read-only=1
# 只同步業務庫
binlog-do-db=mall_ums
binlog-do-db=mall_pms
binlog-do-db=mall_oms
binlog-do-db=mall_sms
binlog-do-db=mall_wms
binlog-do-db=mall_admin
# 不同步mysql基礎庫
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema
重啟mysql-slaver-01
docker restart mysql-slaver-01
檢視容器
docker ps
為 master 授權使用者來他的同步資料
進入 master 容器
docker exec -it mysql-master mysql -u root -p
進入 mysql 內部
# 授權 root 可以遠端訪問( 主從無關,為了方便我們遠端連線 mysql)
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES;
# 新增用來同步的使用者
GRANT REPLICATION SLAVE ON *.* to 'backup'@'%' identified by '123456';
# 檢視 master狀態
show master status;
配置 slaver 同步 master 資料
進入 slaver 容器
docker exec -it mysql-slaver-01 mysql -u root -p
進入 mysql 內部
# 授權 root 可以遠端訪問( 主從無關,為了方便我們遠端連線 mysql)
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES;
# 設定主庫連線
# MASTER_LOG_FILE是show master status;查master的File欄位
CHANGE MASTER TO MASTER_HOST='192.168.188.180',
MASTER_USER='backup',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=0,
MASTER_PORT=3317;
# 啟動從庫同步
start slave;
# 檢視從庫狀態
show slave status;
檢視從庫狀態
show slave status\G;
測試
登入mysql-master
,建立測試mall_admin
這裡建立的表名字只能是my.cnf
配置的binlog-do-db
docker exec -it mysql-master mysql -u root -p
DROP DATABASE IF EXISTS mall_admin;
CREATE DATABASE mall_admin;
USE mall_admin;
CREATE TABLE IF NOT EXISTS test_table (
id INT AUTO_INCREMENT PRIMARY KEY, -- 自增主鍵列
name VARCHAR(100) -- 名稱列,不能為空
);
INSERT INTO test_table (name) VALUES ('Alice');
登入mysql-slaver-01
,發現庫和表成功同步
docker exec -it mysql-slaver-01 mysql -u root -p
show databases;
USE mall_admin;
SELECT * FROM test_table;
主庫再刪除,從庫已同步
DROP DATABASE mall_admin;
7.4ShardingSphere-簡介
官網地址:https://shardingsphere.apache.org/document/current/cn/quick-start/shardingsphere-jdbc-quick-start/
7.5ShardingSphere-分庫分表&讀寫分離配置
下載地址:https://www.apache.org/dyn/closer.lua/shardingsphere/5.5.0/apache-shardingsphere-5.5.0-shardingsphere-proxy-bin.tar.gz
解壓
下載mysql
驅動包
下載地址:https://shardingsphere.apache.org/document/current/cn/quick-start/shardingsphere-proxy-quick-start/#操作步驟
mysql-connector-java-5.1.49.jar
放到apache-shardingsphere\lib
目錄下
配置認證授權
https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-proxy/yaml-config/authority/#引數解釋
配置apache-shardingsphere\conf
的global.yaml
authority:
users:
- user: root@%
password: root
- user: sharding
password: sharding
privilege:
type: ALL_PERMITTED
配置database-sharding.yaml
配置database-readwrite-splitting.yaml
新增database-readwrite-splitting-1.yaml
在master
節點 建立demo_ds_0
、demo_ds_1
CREATE DATABASE `demo_ds_0` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci */;
CREATE DATABASE `demo_ds_1` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci */;
修改master
和slaver
的my.cnf
vim /mydata/mysql/master/conf/my.cnf
vim /mydata/mysql/slaver/conf/my.cnf
把demo_ds_0
、demo_ds_1
新增到主從同步
binlog-do-db=demo_ds_0
binlog-do-db=demo_ds_1
啟動ShardingSphere
start.bat 3388
在3388連結下建立表
CREATE TABLE `t_order` (
`order_id` bigint(20) NOT NULL,
`user_id` int(11) NOT NULL,
`status` varchar(50) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `t_order_item` (
`order_item_id` bigint(20) NOT NULL,
`order_id` bigint(20) NOT NULL,
`user_id` int(11) NOT NULL,
`content` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`status` varchar(50) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`order_item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
新增測試資料
insert into t_order(user_id,status) values(1,2);
insert into t_order(user_id,status) values(2,2);
insert into t_order(user_id,status) values(3,2);
7.6Redis-Cluster基本原理
7.6.1Redis叢集形式
1.資料分割槽方案
1.1客戶端分割槽
客戶端分割槽方案 的代表為 Redis Sharding,Redis Sharding 是 Redis Cluster 出來之前,業 界普遍使用的 Redis 多例項叢集 方法。Java 的 Redis 客戶端驅動庫 Jedis,支援 Redis Sharding 功能,即 ShardedJedis 以及 結合快取池 的 ShardedJedisPool。
優點 :
- 不使用 第三方中介軟體,分割槽邏輯 可控,配置 簡單,節點之間無關聯,容易 線性擴充套件,靈 活性強。
缺點 :
- 客戶端 無法 動態增刪 服務節點,客戶端需要自行維護 分發邏輯,客戶端之間 無連線共享, 會造成 連線浪費。
1.2代理分割槽
1.3redsi-cluster
2.高可用方式
2.1Sentinel( 哨兵機制)支援高可用
前面介紹了主從機制,但是從運維角度來看,主節點出現了問題我們還需要透過人工干預的 方式把從節點設為主節點,還要通知應用程式更新主節點地址,這種方式非常繁瑣笨重, 而 且主節點的讀寫能力都十分有限,有沒有較好的辦法解決這兩個問題,哨兵機制就是針對第 一個問題的有效解決方案,第二個問題則有賴於叢集!哨兵的作用就是監控 Redis 系統的運 行狀況,其功能主要是包括以下三個
- 監控(Monitoring): 哨兵(sentinel) 會不斷地檢查你的 Master 和 Slave 是否運作正常。
- 提醒(Notification): 當被監控的某個 Redis 出現問題時, 哨兵(sentinel) 可以透過 API 向管理員或者其他應用程式傳送通知。
- 自動故障遷移(Automatic failover): 當主資料庫出現故障時自動將從資料庫轉換為主數 據庫。
哨兵的原理 Redis 哨兵的三個定時任務,Redis 哨兵判定一個 Redis 節點故障不可達主要就是透過三個定 時監控任務來完成的:
- 每隔 10 秒每個哨兵節點會向主節點和從節點傳送"info replication" 命令來獲取最新的 拓撲結構
- 每隔 2 秒每個哨兵節點會向 Redis 節點的_sentinel_:hello 頻道傳送自己對主節點是否故 障的判斷以及自身的節點資訊,並且其他的哨兵節點也會訂閱這個頻道來了解其他哨兵 節點的資訊以及對主節點的判斷
- 每隔 1 秒每個哨兵會向主節點、從節點、其他的哨兵節點傳送一個 “ping” 命令來做心 跳檢測
如果在定時 Job3 檢測不到節點的心跳,會判斷為“主觀下線”。如果該節點還是主節點那麼 還會通知到其他的哨兵對該主節點進行心跳檢測,這時主觀下線的票數超過了數 時,那麼這個主節點確實就可能是故障不可達了,這時就由原來的主觀下線變為了“客觀下 線”。
故障轉移和 Leader 選舉 如果主節點被判定為客觀下線之後,就要選取一個哨兵節點來完成後面的故障轉移工作,選 舉出一個 leader,這裡面採用的選舉演算法為 Raft。選舉出來的哨兵 leader 就要來完成故障轉 移工作,也就是在從節點中選出一個節點來當新的主節點,這部分的具體流程可參考引用.
2.2Redis-Cluster
https://redis.io/topics/cluster-tutorial/
7.6.2Redis-Cluster
https://redis.io/topics/cluster-tutorial/
Redis 的官方多機部署方案,Redis Cluster。一組 Redis Cluster 是由多個 Redis 例項組成,官 方推薦我們使用 6 例項,其中 3 個為主節點,3 個為從結點。一旦有主節點發生故障的時候, Redis Cluster 可以選舉出對應的從結點成為新的主節點,繼續對外服務,從而保證服務的高 可用性。那麼對於客戶端來說,知道知道對應的 key 是要路由到哪一個節點呢?Redis Cluster 把所有的資料劃分為 16384 個不同的槽位,可以根據機器的效能把不同的槽位分配給不同 的 Redis 例項,對於 Redis 例項來說,他們只會儲存部分的 Redis 資料,當然,槽的資料是 可以遷移的,不同的例項之間,可以透過一定的協議,進行資料遷移。
1.槽
Redis 叢集的功能限制;Redis 叢集相對 單機 在功能上存在一些限制,需要 開發人員 提前 瞭解,在使用時做好規避。JAVA CRC16 校驗演算法
- key 批次操作 支援有限。
- 類似 mset、mget 操作,目前只支援對具有相同 slot 值的 key 執行 批次操作。 對於 對映為不同 slot 值的 key 由於執行 mget、mget 等操作可能存在於多個節 點上,因此不被支援。
- key 事務操作 支援有限。
- 只支援 多 key 在 同一節點上 的 事務操作,當多個 key 分佈在 不同 的節點上 時 無法 使用事務功能。
- key 作為 資料分割槽 的最小粒度
- 不能將一個 大的鍵值 物件如 hash、list 等對映到 不同的節點。
- 不支援 多資料庫空間
- 單機 下的 Redis 可以支援 16 個資料庫(db0 ~ db15),叢集模式 下只能使用 一 個 資料庫空間,即 db0。
- 複製結構 只支援一層
- 從節點 只能複製 主節點,不支援 巢狀樹狀複製 結構。
- 命令大多會重定向,耗時多
2.一致性 hash
一致性雜湊 可以很好的解決 穩定性問題,可以將所有的 儲存節點 排列在 收尾相接 的 Hash 環上,每個 key 在計算 Hash 後會 順時針 找到 臨接 的 儲存節點 存放。而當有節 點 加入 或 退出 時,僅影響該節點在 Hash 環上 順時針相鄰 的 後續節點。
Hash 傾斜
如果節點很少,容易出現傾斜,負載不均衡問題。一致性雜湊演算法,引入了虛擬節點,在整 個環上,均衡增加若干個節點。比如 a1,a2,b1,b2,c1,c2,a1 和 a2 都是屬於 A 節點 的。解決 hash 傾斜問題。
7.7Redis-Cluster叢集搭建
安裝redis
下載redis:5.0.7
映象
docker pull redis:5.0.7
執行6個redis
for port in $(seq 7001 7006); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port ${port}
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 192.168.188.180
cluster-announce-port ${port}
cluster-announce-bus-port 1${port}
appendonly yes
EOF
docker run -p ${port}:${port} -p 1${port}:1${port} --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d redis:5.0.7 redis-server /etc/redis/redis.conf
done
使用 redis 建立叢集
# 進入 Redis 容器
docker exec -it redis-7001 bash
# 執行 redis-cli 建立 Redis 叢集的命令
redis-cli --cluster create 192.168.188.180:7001 192.168.188.180:7002 192.168.188.180:7003 192.168.188.180:7004 192.168.188.180:7005 192.168.188.180:7006 --cluster-replicas 1
# 主
7001 76abe09d843b39c73891b8c5ce17ffa42b0fcbed
# 從
7006 2fe7a57c12444ed5eaba3d68f311464c350e59fa
# 主
7002 eef7fc312c11d3001485b0052e97a8362a8cd32e
# 從
7004 3d1b3b7f50eed63a0464fcf6cca7307744bd34ca
# 主
7003 a7d95522dafbc173d16149783867442b5fbc6ccf
# 從
7005 aaeb00b6025fe0b36e5d30d46778c06a14e87c21
測試
隨便進入某個redis
容器
docker exec -it redis-7002 /bin/bash
使用 redis-cli 的 cluster 方式進行連線
redis-cli -c -h 192.168.188.180 -p 7006
獲取叢集資訊
cluster info
獲取叢集節點
cluster nodes
7.8ElasticSearch-叢集原理
叢集原理
https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html
https://www.elastic.co/guide/cn/elasticsearch/guide/current/distributed-cluster.html
elasticsearch 是天生支援叢集的,他不需要依賴其他的服務發現和註冊的元件,如 zookeeper 這些,因為他內建了一個名字叫 ZenDiscovery 的模組,是 elasticsearch 自己實現的一套用 於節點發現和選主等功能的元件,所以 elasticsearch 做起叢集來非常簡單,不需要太多額外 的配置和安裝額外的第三方元件。
1.單節點
- 一個執行中的 Elasticsearch 例項稱為一個節點,而叢集是由一個或者多個擁有相同 cluster.name 配置的節點組成, 它們共同承擔資料和負載的壓力。當有節點加入叢集 中或者從叢集中移除節點時,叢集將會重新平均分佈所有的資料。
- 當一個節點被選舉成為 主節點時, 它將負責管理叢集範圍內的所有變更,例如增加、 刪除索引,或者增加、刪除節點等。 而主節點並不需要涉及到文件級別的變更和搜尋 等操作,所以當叢集只擁有一個主節點的情況下,即使流量的增加它也不會成為瓶頸。 任何節點都可以成為主節點。我們的示例叢集就只有一個節點,所以它同時也成為了主 節點。
- 作為使用者,我們可以將請求傳送到 叢集中的任何節點 ,包括主節點。 每個節點都知 道任意文件所處的位置,並且能夠將我們的請求直接轉發到儲存我們所需文件的節點。 無論我們將請求傳送到哪個節點,它都能負責從各個包含我們所需文件的節點收集回數 據,並將最終結果返回給客戶端。 Elasticsearch 對這一切的管理都是透明的。
2.叢集健康
Elasticsearch 的叢集監控資訊中包含了許多的統計資料,其中最為重要的一項就是 叢集健 康 , 它在 status 欄位中展示為 green 、 yellow 或者 red 。
GET /_cluster/health
status 欄位指示著當前叢集在總體上是否工作正常。它的三種顏色含義如下:
- green:所有的主分片和副本分片都正常執行。
- yellow:所有的主分片都正常執行,但不是所有的副本分片都正常執行。
- red:有主分片沒能正常執行。
3.分片
- 一個 分片 是一個底層的 工作單元 ,它僅儲存了全部資料中的一部分。我們的文件被 儲存和索引到分片內,但是應用程式是直接與索引而不是與分片進行互動。分片就認為 是一個資料區
- 一個分片可以是 主 分片或者 副本 分片。索引內任意一個文件都歸屬於一個主分片, 所以主分片的數目決定著索引能夠儲存的最大資料量。
- 在索引建立的時候就已經確定了主分片數,但是副本分片數可以隨時修改。
- 讓我們在包含一個空節點的叢集內建立名為 blogs 的索引。 索引在預設情況下會被分 配 5 個主分片, 但是為了演示目的,我們將分配 3 個主分片和一份副本(每個主分片 擁有一個副本分片):
PUT /blogs{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}}
此時叢集的健康狀況為 yellow 則表示全部 主分片都正常執行(叢集可以正常服務所有請 求),但是 副本 分片沒有全部處在正常狀態。 實際上,所有 3 個副本分片都是 unassigned —— 它們都沒有被分配到任何節點。在同一個節點上既儲存原始資料又儲存副本是沒有意 義的,因為一旦失去了那個節點,我們也將丟失該節點上的所有副本資料。 當前我們的叢集是正常執行的,但是在硬體故障時有丟失資料的風險。
4.新增節點
當你在同一臺機器上啟動了第二個節點時,只要它和第一個節點有同樣的 cluster.name 配 置,它就會自動發現叢集並加入到其中。 但是在不同機器上啟動節點的時候,為了加入到 同一叢集,你需要配置一個可連線到的單播主機列表。 詳細資訊請檢視最好使用單播代替 組播
此時,cluster-health 現在展示的狀態為 green ,這表示所有 6 個分片(包括 3 個主分片和 3 個副本分片)都在正常執行。我們的叢集現在不僅僅是正常執行的,並且還處於 始終可 用 的狀態。
5.水平擴容-啟動第三個節點
Node 1 和 Node 2 上各有一個分片被遷移到了新的 Node 3 節點,現在每個節點上都擁 有 2 個分片,而不是之前的 3 個。 這表示每個節點的硬體資源(CPU, RAM, I/O)將被更少 的分片所共享,每個分片的效能將會得到提升。
在執行中的叢集上是可以動態調整副本分片數目的,我們可以按需伸縮叢集。讓我們把副本 數從預設的 1 增加到 2
PUT /blogs/_settings
{
"number_of_replicas" : 2
}
blogs 索引現在擁有 9 個分片:3 個主分片和 6 個副本分片。 這意味著我們可以將叢集擴 容到 9 個節點,每個節點上一個分片。相比原來 3 個節點時,叢集搜尋效能可以提升3 倍。
6.應對故障
- 我們關閉的節點是一個主節點。而叢集必須擁有一個主節點來保證正常工作,所以發生 的第一件事情就是選舉一個新的主節點: Node 2 。
- 在我們關閉 Node 1 的同時也失去了主分片 1 和 2 ,並且在缺失主分片的時候索引 也不能正常工作。 如果此時來檢查叢集的狀況,我們看到的狀態將會為 red :不是所 有主分片都在正常工作。
- 幸運的是,在其它節點上存在著這兩個主分片的完整副本, 所以新的主節點立即將這 些分片在 Node 2 和 Node 3 上對應的副本分片提升為主分片, 此時叢集的狀態將會 為 yellow 。 這個提升主分片的過程是瞬間發生的,如同按下一個開關一般。
- 為什麼我們叢集狀態是 yellow 而不是 green 呢? 雖然我們擁有所有的三個主分片, 但是同時設定了每個主分片需要對應 2 份副本分片,而此時只存在一份副本分片。 所 以叢集不能為 green 的狀態,不過我們不必過於擔心:如果我們同樣關閉了 Node 2 , 我們的程式 依然 可以保持在不丟任何資料的情況下執行,因為 Node 3 為每一個分 片都保留著一份副本。
- 如果我們重新啟動 Node 1 ,叢集可以將缺失的副本分片再次進行分配。如果 Node 1依然擁有著之前的分片,它將嘗試去重用它們,同時僅從主分片複製發生了修改的資料 檔案。
7.問題與解決
1、主節點
主節點負責建立索引、刪除索引、分配分片、追蹤叢集中的節點狀態等工作。Elasticsearch 中的主節點的工作量相對較輕,使用者的請求可以發往叢集中任何一個節點,由該節點負責分 發和返回結果,而不需要經過主節點轉發。而主節點是由候選主節點透過 ZenDiscovery 機 制選舉出來的,所以要想成為主節點,首先要先成為候選主節點。
2、候選主節點
在 elasticsearch 叢集初始化或者主節點當機的情況下,由候選主節點中選舉其中一個作為主 節點。指定候選主節點的配置為:node.master: true。 當主節點負載壓力過大,或者集中環境中的網路問題,導致其他節點與主節點通訊的時候, 主節點沒來的及響應,這樣的話,某些節點就認為主節點當機,重新選擇新的主節點,這樣 的話整個叢集的工作就有問題了,比如我們叢集中有 10 個節點,其中 7 個候選主節點,1 個候選主節點成為了主節點,這種情況是正常的情況。但是如果現在出現了我們上面所說的 主節點響應不及時,導致其他某些節點認為主節點當機而重選主節點,那就有問題了,這剩 下的 6 個候選主節點可能有 3 個候選主節點去重選主節點,最後叢集中就出現了兩個主節點 的情況,這種情況官方成為“腦裂現象”; 叢集中不同的節點對於 master 的選擇出現了分歧,出現了多個 master 競爭,導致主分片 和副本的識別也發生了分歧,對一些分歧中的分片標識為了壞片。
3、資料節點
資料節點負責資料的儲存和相關具體操作,比如 CRUD、搜尋、聚合。所以,資料節點對機 器配置要求比較高,首先需要有足夠的磁碟空間來儲存資料,其次資料操作對系統 CPU、 Memory 和 IO 的效能消耗都很大。通常隨著叢集的擴大,需要增加更多的資料節點來提高 可用性。指定資料節點的配置:node.data: true。 elasticsearch 是允許一個節點既做候選主節點也做資料節點的,但是資料節點的負載較重, 所以需要考慮將二者分離開,設定專用的候選主節點和資料節點,避免因資料節點負載重導 致主節點不響應。
4、客戶端節點
客戶端節點就是既不做候選主節點也不做資料節點的節點,只負責請求的分發、彙總等等, 但是這樣的工作,其實任何一個節點都可以完成,因為在 elasticsearch 中一個叢集內的節點 都可以執行任何請求,其會負責將請求轉發給對應的節點進行處理。所以單獨增加這樣的節 點更多是為了負載均衡。指定該節點的配置為: node.master: false node.data: false
5、腦裂”問題可能的成因
1.網路問題:叢集間的網路延遲導致一些節點訪問不到 master,認為 master 掛掉了從而選 舉出新的 master,並對 master 上的分片和副本標紅,分配新的主分片
2.節點負載:主節點的角色既為 master 又為 data,訪問量較大時可能會導致 ES 停止響應造 成大面積延遲,此時其他節點得不到主節點的響應認為主節點掛掉了,會重新選取主節點。
3.記憶體回收:data 節點上的 ES 程序佔用的記憶體較大,引發 JVM 的大規模記憶體回收,造成 ES 程序失去響應。
- 腦裂問題解決方案:
- 角色分離:即 master 節點與 data 節點分離,限制角色;資料節點是需要承擔儲存 和搜尋的工作的,壓力會很大。所以如果該節點同時作為候選主節點和資料節點, 那麼一旦選上它作為主節點了,這時主節點的工作壓力將會非常大,出現腦裂現象 的機率就增加了。
- 減少誤判:配置主節點的響應時間,在預設情況下,主節點 3 秒沒有響應,其他節 點就認為主節點當機了,那我們可以把該時間設定的長一點,該配置是: discovery.zen.ping_timeout: 5
- 選舉觸發:discovery.zen.minimum_master_nodes:1(預設是 1),該屬性定義的是 為了形成一個叢集,有主節點資格並互相連線的節點的最小數目。
- 一 個 有 10 節 點 的 集 群 , 且 每 個 節 點 都 有 成 為 主 節 點 的 資 格 , discovery.zen.minimum_master_nodes 引數設定為 6。
- 正常情況下,10 個節點,互相連線,大於 6,就可以形成一個叢集。
- 若某個時刻,其中有 3 個節點斷開連線。剩下 7 個節點,大於 6,繼續執行之 前的叢集。而斷開的 3 個節點,小於 6,不能形成一個叢集。
- 該引數就是為了防止”腦裂”的產生。
- 建議設定為(候選主節點數 / 2) + 1,
8.叢集結構
以三臺物理機為例。在這三臺物理機上,搭建了 6 個 ES 的節點,三個 data 節點,三個 master 節點(每臺物理機分別起了一個 data 和一個 master),3 個 master 節點,目的是達到(n/2) +1 等於 2 的要求,這樣掛掉一臺 master 後(不考慮 data),n 等於 2,滿足引數,其他兩 個 master 節點都認為 master 掛掉之後開始重新選舉,
master 節點上
node.master = true
node.data = false
discovery.zen.minimum_master_nodes = 2
data 節點上
node.master = false
node.data = true
7.9ElasticSearch-叢集搭建
設定max_map_count
vm.max_map_count
是一個核心引數,表示一個程序可以擁有的最大記憶體對映區域數量。將其設定為 262144
增加了該限制,這在需要大量記憶體對映的應用程式(如某些資料庫或大型應用程式)中可能會有所幫助。
所有之前先執行
sysctl -w vm.max_map_count=262144
我們只是測試,所以臨時修改。永久修改使用下面
#防止 JVM 報錯
echo vm.max_map_count=262144 >> /etc/sysctl.conf
sysctl -p
準備 docker 網路
建立一個新的 bridge 網路
docker network create --driver bridge --subnet=172.19.0.0/16 --gateway=172.19.0.1 mynet
檢視網路資訊,以後使用--network=mynet --ip 172.18.12.x
指定 ip
docker network inspect mynet
建立Master節點
for port in $(seq 1 3); do
mkdir -p /mydata/elasticsearch/master-${port}/config
mkdir -p /mydata/elasticsearch/master-${port}/data
chmod -R 777 /mydata/elasticsearch/master-${port}
cat << EOF >/mydata/elasticsearch/master-${port}/config/elasticsearch.yml
cluster.name: my-es # 叢集的名稱,同一個叢集該值必須設定成相同的
node.name: es-master-${port} # 該節點的名字
node.master: true # 該節點有機會成為 master 節點
node.data: false # 該節點可以儲存資料
network.host: 0.0.0.0
http.host: 0.0.0.0 # 所有 http 均可訪問
http.port: 920${port}
transport.tcp.port: 930${port}
# discovery.zen.minimum_master_nodes: 2 # 設定這個引數來保證叢集中的節點可以知道其他 N 個有 master 資格的節點。官方推薦(N/2)+1
discovery.zen.ping_timeout: 10s # 設定叢集中自動發現其他節點時 ping 連線的超時時間
discovery.seed_hosts: ["172.19.12.21:9301", "172.19.12.22:9302", "172.19.12.23:9303"] # 設定叢集中的 Master 節點的初始列表,可以透過這些節點來自動發現其他新加入叢集的節點,es7 的新增配置
cluster.initial_master_nodes: ["172.19.12.21"] # 新叢集初始時的候選主節點,es7 的新增配置
EOF
docker run --name elasticsearch-node-${port} \
-p 920${port}:920${port} -p 930${port}:930${port} \
--network=mynet --ip 172.19.12.2${port} \
-e ES_JAVA_OPTS="-Xms300m -Xmx300m" \
-v /mydata/elasticsearch/master-${port}/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/master-${port}/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/master-${port}/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2
done
建立Data-Node節點
for port in $(seq 4 6); do
mkdir -p /mydata/elasticsearch/node-${port}/config
mkdir -p /mydata/elasticsearch/node-${port}/data
chmod -R 777 /mydata/elasticsearch/node-${port}
cat << EOF >/mydata/elasticsearch/node-${port}/config/elasticsearch.yml
cluster.name: my-es # 叢集的名稱,同一個叢集該值必須設定成相同的
node.name: es-node-${port} # 該節點的名字
node.master: false # 該節點有機會成為 master 節點
node.data: true # 該節點可以儲存資料
network.host: 0.0.0.0
# network.publish_host: 192.168.56.10 # 互相通訊 ip,要設定為本機可被外界訪問的 ip,否則無法通訊
http.host: 0.0.0.0 # 所有 http 均可訪問
http.port: 920${port}
transport.tcp.port: 930${port}
# discovery.zen.minimum_master_nodes: 2 # 設定這個引數來保證叢集中的節點可以知道其他 N 個有 master 資格的節點。官方推薦(N/2)+1
discovery.zen.ping_timeout: 10s # 設定叢集中自動發現其他節點時 ping 連線的超時時間
discovery.seed_hosts: ["172.19.12.21:9301", "172.19.12.22:9302", "172.19.12.23:9303"] # 設定叢集中的 Master 節點的初始列表,可以透過這些節點來自動發現其他新加入叢集的節點,es7 的新增配置
cluster.initial_master_nodes: ["172.19.12.21"] # 新叢集初始時的候選主節點,es7 的新增配置
EOF
docker run --name elasticsearch-node-${port} \
-p 920${port}:920${port} -p 930${port}:930${port} \
--network=mynet --ip 172.19.12.2${port} \
-e ES_JAVA_OPTS="-Xms300m -Xmx300m" \
-v /mydata/elasticsearch/node-${port}/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/node-${port}/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/node-${port}/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2
done
測試叢集
http://192.168.188.180:9201/_nodes/process?pretty 檢視節點狀況
http://192.168.188.180:9201/_cluster/stats?pretty 檢視叢集狀態
http://192.168.188.180:9201/_cluster/health?pretty 檢視叢集健康狀況
http://192.168.188.180:9202/_cat/nodes 檢視各個節點資訊
$ curl localhost:9200/_cat
/_cat/allocation
/_cat/shards
/_cat/shards/{index}
/_cat/master
/_cat/nodes
/_cat/indices
/_cat/indices/{index}
/_cat/segments
/_cat/segments/{index}
/_cat/count
/_cat/count/{index}
/_cat/recovery
/_cat/recovery/{index}
/_cat/health
/_cat/pending_tasks
/_cat/aliases
/_cat/aliases/{alias}
/_cat/thread_pool
/_cat/plugins
/_cat/fielddata
/_cat/fielddata/{fields}
/_cat/nodeattrs
/_cat/repositories
/_cat/snapshots/{repository}
7.10RabbitMQ-映象叢集搭建
7.10.1叢集形式
RabbiMQ 是用 Erlang 開發的,叢集非常方便,因為 Erlang 天生就是一門分散式語言,但其 本身並不支援負載均衡。
RabbitMQ 叢集中節點包括記憶體節點(RAM)、磁碟節點(Disk,訊息持久化),叢集中至少有 一個 Disk 節點。
- 普通模式(預設)
對於普通模式,叢集中各節點有相同的佇列結構,但訊息只會存在於叢集中的一個節 點。對於消費者來說,若訊息進入 A 節點的 Queue 中,當從 B 節點拉取時,RabbitMQ 會 將訊息從 A 中取出,並經過 B 傳送給消費者。 應用場景:該模式各適合於訊息無需持久化的場合,如日誌佇列。當佇列非持久化,且 建立該佇列的節點當機,客戶端才可以重連叢集其他節點,並重新建立佇列。若為持久化, 只能等故障節點恢復。
- 映象模式
與普通模式不同之處是訊息實體會主動在映象節點間同步,而不是在取資料時臨時拉 取,高可用;該模式下,mirror queue 有一套選舉演算法,即 1 個 master、n 個 slaver,生產 者、消費者的請求都會轉至 master。
應用場景:可靠性要求較高場合,如下單、庫存佇列。
缺點:若映象佇列過多,且訊息體量大,叢集內部網路頻寬將會被此種同步通訊所消 耗。
(1)映象叢集也是基於普通叢集,即只有先搭建普通叢集,然後才能設定映象佇列。
(2)若消費過程中,master 掛掉,則選舉新 master,若未來得及確認,則可能會重複消費。
7.10.2搭建叢集
搭建叢集
建立目錄
mkdir /mydata/rabbitmq
cd rabbitmq/
mkdir rabbitmq01 rabbitmq02 rabbitmq03
執行rabbitmq01
、rabbitmq02
、rabbitmq03
docker run -d --hostname rabbitmq01 --name rabbitmq01 \
-v /mydata/rabbitmq/rabbitmq01:/var/lib/rabbitmq \
-p 15673:15672 -p 5673:5672 \
-e RABBITMQ_ERLANG_COOKIE='peng' \
rabbitmq:management
docker run -d --hostname rabbitmq02 --name rabbitmq02 \
-v /mydata/rabbitmq/rabbitmq02:/var/lib/rabbitmq \
-p 15674:15672 -p 5674:5672 \
-e RABBITMQ_ERLANG_COOKIE='peng' \
--link rabbitmq01:rabbitmq01 \
rabbitmq:management
docker run -d --hostname rabbitmq03 --name rabbitmq03 \
-v /mydata/rabbitmq/rabbitmq03:/var/lib/rabbitmq \
-p 15675:15672 -p 5675:5672 \
-e RABBITMQ_ERLANG_COOKIE='peng' \
--link rabbitmq01:rabbitmq01 \
--link rabbitmq02:rabbitmq02 \
rabbitmq:management
節點加入叢集
進入rabbitmq01
docker exec -it rabbitmq01 /bin/bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
exit
進入rabbitmq02
docker exec -it rabbitmq02 /bin/bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbit@rabbitmq01
rabbitmqctl start_app
exit
進入rabbitmq03
docker exec -it rabbitmq03 bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbit@rabbitmq01
rabbitmqctl start_app
exit
實現映象叢集
在 cluster 中任意節點啟用策略,策略會自動同步到叢集節點 rabbitmqctl set_policy-p/ha-all"^"’{“ha-mode”:“all”}’ 策略模式 all 即複製到所有節點,包含新增節點,策略正規表示式為 “^” 表示所有匹配所有佇列名稱。“^hello”表示只匹配名為 hello 開始的佇列。
docker exec -it rabbitmq01 bash
rabbitmqctl set_policy -p / ha "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}'
#檢視 vhost/下面的所有 policy
rabbitmqctl list_policies -p /;
測試
在http://192.168.188.180:15673/#/queues
建立節點,剩下2個從節點自動同步
8.k8s部署
8.1如何在k8s上部署有狀態應用
可以使用 kubesphere,快速搭建 MySQL 環境。
-
有狀態服務抽取配置為 ConfigMap
-
有狀態服務必須使用 pvc 持久化資料
-
服務叢集內訪問使用 DNS
8.2k8s部署MySQL
常用命令
# 建立目錄
mkdir -p /mydata/mysql/master/{data,log}
mkdir -p /mydata/mysql/master/conf/{conf.d,mysql.conf.d}
# 執行
docker run -p 3317:3306 --name mysql-master \
-v /mydata/mysql/master/log:/var/log/mysql \
-v /mydata/mysql/master/data:/var/lib/mysql \
-v /mydata/mysql/master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
kubectl get statefulsets -n peng-mall
kubectl edit statefulset mysql-master-v1 -n peng-mall
kubectl get pods -n peng-mall
8.2.1部署mysql主節點
安裝
- 建立配置
mysql-master-cnf
- 建立儲存卷
mysql-master-pvc
- 建立有狀態服務
建立配置mysql-master-cnf
基本資訊
配置設定
my.cnf
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
# 新增 master 主從複製部分配置
server_id=1
log-bin=mysql-bin
# 讀寫
read-only=0
# 只同步業務庫
binlog-do-db=mall_ums
binlog-do-db=mall_pms
binlog-do-db=mall_oms
binlog-do-db=mall_sms
binlog-do-db=mall_wms
binlog-do-db=mall_admin
# 不同步mysql基礎庫
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema
建立儲存卷mysql-master-pvc
基本資訊
儲存卷設定
建立有狀態服務
基本資訊
映象設定
如果一直查詢不出來mysql:5.7
,使用命令列工具docker search mysql:5.7
查詢一下,我學習的這幾個月docker地址老是被牆
解決辦法:
docker search
不能使用映象加速,但是pull可以下載映象,提前把mysql:5.7映象下載下來
分享我的daemon.json
,如果後面還不能用,自己上網再查詢即可
cat << EOF > /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": [
"https://dockerproxy.cn",
"https://docker.rainbond.cc",
"https://docker.udayun.com",
"https://docker.211678.top",
"https://hub.rat.dev",
"https://docker.wanpeng.top",
"https://doublezonline.cloud",
"https://docker.mrxn.net",
"https://lynn520.xyz",
"https://ginger20240704.asia",
"https://docker.wget.at",
"https://dislabaiot.xyz",
"https://dockerpull.com",
"https://docker.fxxk.dedyn.io",
"https://docker.m.daocloud.io"
],
"live-restore": true,
"log-driver": "json-file",
"log-opts": {"max-size": "500m", "max-file": "3"},
"storage-driver": "overlay2"
}
EOF
然後重啟
sudo systemctl daemon-reload
sudo systemctl restart docker
我這裡三個節點都下載了mysql:5.7
,你也不知道mysql
會安裝在那個子節點上
服務設定資源、埠
映象下載完成後記得選擇優先使用本地映象
環境配置,設定資料庫密碼,這裡的mysql-secret
之前都配置過了
掛載儲存
注意我這裡配置了1個儲存卷和3個配置檔案
/var/lib/mysql
/etc/mysql
/etc/mysql/conf.d
/etc/mysql/mysql.conf.d
按理說只需要配置/etc/mysql
,但我這裡執行時會報錯,說是找不到/etc/mysql/conf.d
和/etc/mysql/mysql.conf.d
,所以直接在這2個路徑下也新增配置檔案
mysqld: Can't read dir of '/etc/mysql/conf.d/
高階設定
8.2.2部署mysql子節點
安裝
- 建立配置
mysql-slave-01-cnf
- 建立儲存卷
mysql-slave-01-pvc
- 建立有狀態服務
建立配置mysql-slave-01-cnf
基本資訊
配置設定
配置項
my.cnf
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
# 新增 master 主從複製部分配置
server-id=2
log-bin=mysql-bin
# 只讀
read-only=1
# 只同步業務庫
binlog-do-db=mall_ums
binlog-do-db=mall_pms
binlog-do-db=mall_oms
binlog-do-db=mall_sms
binlog-do-db=mall_wms
binlog-do-db=mall_admin
# 不同步mysql基礎庫
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema
建立完成
建立儲存卷mysql-slave-01-pvc
基本資訊
儲存卷設定
點選建立
建立完成
建立有狀態服務
基本資訊
映象
資源配置
環境變數
掛在儲存,注意我們掛載的是子節點的儲存卷**mysql-slave-01-pvc**
和配置檔案mysql-slave-01-cnf
/var/lib/mysql
/etc/mysql
/etc/mysql/conf.d
/etc/mysql/mysql.conf.d
高階設定
建立完成
8.2.3配置mysql主從
進入mysql-master(mysql主節點)
容器組
進入容器
為 master 授權使用者來他的同步資料
進入 master 容器
mysql -u root -p
進入 mysql 內部
# 授權 root 可以遠端訪問( 主從無關,為了方便我們遠端連線 mysql)
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES;
# 新增用來同步的使用者
GRANT REPLICATION SLAVE ON *.* to 'backup'@'%' identified by '123456';
# 檢視 master狀態
show master status;
記住mysql-bin.000004
這個地址,一會同步從庫的時候要從mysql-bin.000004
同步
配置 slaver 同步 master 資料
進入從庫容器組mysql-slave-01-v1-0
進入 slaver 容器
mysql -u root -p
mysql-master
域名是mysql-master.peng-mall
,資料同步位置是mysql-bin.000004
,埠號是3306
,所以同步命令
CHANGE MASTER TO MASTER_HOST='mysql-master.peng-mall',
MASTER_USER='backup',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.000004',
MASTER_LOG_POS=0,
MASTER_PORT=3306;
進入mysql
內部
# 授權 root 可以遠端訪問( 主從無關,為了方便我們遠端連線 mysql)
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;
FLUSH PRIVILEGES;
# 設定主庫連線
# MASTER_LOG_FILE是show master status;查master的File欄位
CHANGE MASTER TO MASTER_HOST='mysql-master.peng-mall',
MASTER_USER='backup',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.000004',
MASTER_LOG_POS=0,
MASTER_PORT=3306;
# 啟動從庫同步
start slave;
# 檢視從庫狀態
show slave status\G;
從庫配置完成
8.2.4測試
進入容器mysql-master-v1-0
建立資料庫mall_admin
再次進入容器mysql-slave-01-v1-0
,發現資料庫mall_admin
已同步從庫
mysql -u root -p
DROP DATABASE IF EXISTS mall_admin;
CREATE DATABASE mall_admin;
SHOW DATABASES;
USE mall_admin;
CREATE TABLE IF NOT EXISTS test_table (
id INT AUTO_INCREMENT PRIMARY KEY, -- 自增主鍵列
name VARCHAR(100) -- 名稱列,不能為空
);
INSERT INTO test_table (name) VALUES ('Alice');
8.3k8s部署Redis
安裝:
- 建立配置
redis-conf
- 建立儲存卷
redis-pvc
- 建立有狀態服務
建立配置redis-conf
redis-conf
配置設定
redis-conf
appendonly yes
建立儲存卷redis-pvc
redis-pvc
基本資訊
儲存卷設定
建立完成
建立有狀態服務
redis:5.0.7
# 或者
redis:latest
資源、埠配置
6379
新增啟動命令
redis-server
/etc/redis/redis.conf
可以提前在主節點使用docker pull redis:5.0.7
拉取映象,這裡建議設定優先使用本地映象
掛載儲存
配置指定的配置檔案
/etc/redis
redis.conf
redis
儲存卷和配置檔案配置完成
/data
建立完成
pod
一直處於ContainerCreating
狀態,沒有可忽略
pod
一直處於ContainerCreating
狀態,如果之前我們在主節點下載了redis:5.0.7
,可以在主節點打包,然後從主節點複製到子節點
也可以從有映象的地方打包,然後直接複製到子節點
# 打包
docker save -o /root/k8s/redis_5.0.7.tar redis:5.0.7
# 複製
scp /root/k8s/redis_5.0.7.tar root@k8s-03:/root/k8s/
然後到k8s-03
子節點
cd k8s/
# 解壓映象
docker load -i /root/k8s/redis_5.0.7.tar
在這裡可以確定redis
安裝在了那個子節點
測試
redis-cli
set aa bb
get aa
8.4k8s部署ElasticSearch&Kibana
8.4.1部署ElasticSearch
安裝
- 建立
elasticsearch-conf
- 建立
elasticsearch-pvc
- 建立有狀態服務
elasticsearch
建立elasticsearch-conf
elasticsearch-conf
基本資訊
配置設定
http.host = 0.0.0.0
discovery.type = single-node
ES_JAVA_OPTS = -Xms512m -Xmx512m
建立elasticsearch-pvc
elasticsearch-pvc
基本資訊
儲存卷設定
建立有狀態服務elasticsearch
elasticsearch:7.12.1
# 或者 我這裡下載了這2個映象
docker.elastic.co/elasticsearch/elasticsearch:7.12.1
配置資源、埠
9200
9300
配置環境變數
配置儲存卷
/usr/share/elasticsearch/data
建立
測試
使用admin登入
訪問elasticsearch
curl http://elasticsearch.peng-mall:9200
8.4.2部署Kibana
建立無狀態服務
基本資訊
kibana
設定映象
kibana:7.12.1
配置埠5601
配置環境變數
ELASTICSEARCH_URL = http://elasticsearch.peng-mall:9200
不需要掛載儲存
高階設定
kibana
部署完成,我們訪問他的埠
測試,訪問自己虛擬機器的30027
埠,能夠傳送請求代表部署成功
http://192.168.188.181:30027/app/dev_tools#/console
8.5k8s部署RabbitMQ
安裝:
- 建立儲存卷
rabbitmq-pvc
- 建立有狀態服務
rabbitmq
建立儲存卷rabbitmq-pvc
建立儲存卷-基本資訊
rabbitmq-pvc
儲存卷設定
建立有狀態服務rabbitmq
基本資訊
rabbitmq
容器映象
rabbitmq:3.8-management
配置資源和埠
ports:
- "5672:5672" # 對映主機的5672埠到容器的5672埠
- "15672:15672" # 對映主機的15672埠到容器的15672埠(管理介面)
掛載儲存
設定儲存卷
/var/lib/rabbitmq
高階設定
有時候映象下載不下來,可以先下載,在設定映象的時候設定優先選擇本地映象即可
部署完成
8.6k8s部署Nacos
8.6.1部署mysql8
services:
mysql:
image: mysql:latest
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: root # MySQL 根使用者密碼
MYSQL_DATABASE: nacos # 預設建立的資料庫
MYSQL_PASSWORD: root # MySQL 使用者密碼
TZ: Asia/Shanghai
ports:
- "3306:3306" # 對映主機的3306埠到容器的3306埠
volumes:
# - mysql_data:/var/lib/mysql # 持久化 MySQL 資料到名為 mysql_data 的卷
- ./mysql/data:/var/lib/mysql
- ./mysql/conf:/etc/mysql/conf.d
# - ./root/mysql/init:/docker-entrypoint-initdb.d
networks:
- peng-net # 指定連線的網路
建立mysql8-conf
mysql8-conf
建立mysql8-cnf
鍵
mysql8.cnf
值
[client]
default_character_set=utf8mb4
[mysql]
default_character_set=utf8mb4
[mysqld]
character_set_server=utf8mb4
collation_server=utf8mb4_unicode_ci
init_connect='SET NAMES utf8mb4'
這樣就建立完成了mysql8
的環境變數和配置
建立mysql8-pvc
mysql8-pvc
建立有狀態服務
mysql8
設定映象
mysql:latest
配置資源和埠
tcp-3306 3306 3306
配置環境變數,選擇mysql8-conf
mysql8-conf
配置掛載儲存
mysql8-pvc /var/lib/mysql
mysql8-cnf /etc/mysql/conf.d
高階設定
部署nacos需要的資料
# 將nacos.sql複製到容器內
kubectl cp /root/k8s/nacos.sql peng-mall/mysql8-v1-0:/tmp/nacos.sql
# 進入容器
kubectl exec -it mysql8-v1-0 -n peng-mall -- /bin/bash
# 登入mysql
mysql -u root -p
# 執行
source /tmp/nacos.sql;
# 退出mysql
exit;
# 刪除
rm /tmp/nacos.sql
# 退出容器
exit;
mysql映象一直不能自動下載,如果主節點有mysql:latest
,可以打包,然後複製到子節點重新載入
在k8s-01
打包mysql:latest
# 打包
docker save -o /root/k8s/mysql_latest.tar mysql:latest
# 複製到k8s-02
scp /root/k8s/mysql_latest.tar root@k8s-02:/root/k8s
在k8s-01
docker load -i /root/k8s/mysql_latest.tar
8.6.2部署nacos
nacos:
image: nacos/nacos-server:v2.1.0-slim
container_name: nacos
environment:
- PREFER_HOST_MODE=hostname # 使用主機名作為偏好模式
- MODE=standalone
- SPRING_DATASOURCE_PLATFORM=mysql
- MYSQL_SERVICE_HOST=192.168.188.180 # MySQL 服務主機名
- MYSQL_SERVICE_DB_NAME=nacos # Nacos 使用的資料庫名
- MYSQL_SERVICE_PORT=3306 # MySQL 服務埠
- MYSQL_SERVICE_USER=root # MySQL 使用者名稱
- MYSQL_SERVICE_PASSWORD=root # MySQL 使用者密碼
- MYSQL_SERVICE_DB_PARAM=characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
# - NACOS_AUTH_ENABLE=true # 啟用 Nacos 認證
ports:
- "8848:8848" # 對映主機的8848埠到容器的8848埠
- "9848:9848"
- "9849:9849"
depends_on:
- mysql # 啟動順序,先啟動 mysql 服務
volumes:
- nacos_data:/home/nacos/init.d # 持久化 Nacos 資料到名為 nacos_data 的卷
networks:
- peng-net
基本資訊
nacos-conf
配置設定
注意MYSQL_SERVICE_HOST
配置的是mysql8
服務的DNS
mysql8.peng-mall
建立有狀態服務
nacos
映象設定
nacos/nacos-server:v2.1.0-slim
配置資源和埠
- "8848:8848"
- "9848:9848"
- "9849:9849"
環境變數
儲存卷
nacos-pvc
/home/nacos/init.d
高階設定
8.7k8s部署Zipkin
zipkin:
image: openzipkin/zipkin
container_name: zipkin
environment:
STORAGE_TYPE: elasticsearch
ES_HOST: elasticsearch
ES_PORT: 9200
ES_INDEX: zipkin
ports:
- "9411:9411" # 對映主機的9411埠到容器的9411埠
networks:
建立zipkin-conf
ES_HOST
是部署elasticsearch
後的域名
elasticsearch.peng-mall
建立無狀態服務zipkin
zipkin
映象設定
openzipkin/zipkin
資源、埠配置
9411
環境配置
不需要配置掛載儲存
高階設定
允許外網訪問,選擇NodePort
測試訪問http://192.168.188.181:30922/zipkin/
8.8k8s部署Sentinel
sentinel:
image: bladex/sentinel-dashboard
container_name: sentinel
ports:
- "8858:8858" # 對映主機的8858埠到容器的8858埠
networks:
- peng-net # 指定連線的網路
建立無狀態服務sentinel
sentinel
映象設定
bladex/sentinel-dashboard
資源、埠配置
8858
無掛載儲存
高階設定
開啟外網訪問,選擇NodePort
測試訪問http://192.168.188.181:30630/#/login
8.9k8s部署應用的流程
8.10生產環境配置抽取
8.10.1檢視服務域名內部是否可以訪問
使用admin
賬號登入,開啟kubectl
sentinel
不可以訪問域名
zipkin
不可以訪問域名
nacos
可以訪問域名
mysql8
可以訪問域名
rabbitmq
可以訪問域名
kibana
不可以訪問域名
elasticsearch
可以訪問域名
redis
可以訪問域名
8.10.3sentinel服務指定工作負載
選擇指定工作負載
基本資訊
sentinel-service
選擇EndPoint IP
訪問
點選指定工作負載,選擇sentinel
繫結8858
埠
開啟會話保持,然後建立
測試sentinel-service
內部是否可以訪問
8.10.3zipkin服務指定工作負載
選擇指定工作負載
基本資訊
zipkin-service
選擇EndPoint IP
訪問
點選指定工作負載,選擇zipkin
繫結9411
埠
http-zipkin 9411 9411
開啟會話保持,然後建立
測試zipkin-service
內部是否可以訪問
8.10.4mysql8服務指定工作負載
mysql8
安裝後,我們需要初始化資料庫
給mysql8
建立工作負載
基本資訊
mysql8-node-port
複製設定
選擇指定工作負載,選擇mysql8-v1
設定埠
http-3306 3306 3306
高階設定
選擇外網訪問,選擇NodePort
,選擇開啟會話保持
連線mysql8-node-port
,IP
任意一個k8s
節點ip
都可以,埠是隨機暴露的埠
然後匯入所有的資料,nacos
服務需要連線資料庫,如果之前沒匯入,這裡要匯入
mall_admin
mall_oms
mall_pms
mall_sms
mall_ums
mall_wms
nacos
# 不使用可以不建立
seata
mysql
編碼
utf8mb4
utf8mb4_unicode_ci
8.10.5nacos服務指定工作負載
如果我們要使用nacos控制檯檢視服務狀態,需要為nacos建立工作負載,允許外部訪問
基本資訊
建立ncaos
工作負載
nacos-node-port
服務設定
選擇指定工作負載,選擇nacos-v1
埠
http-8848 8848 8848
高階設定
選擇外網訪問,選擇NodePort
,選擇開啟會話保持
進入nacos-node-port
檢視訪問埠32750
,然後訪問http://192.168.188.181:32750
8.10.6生產環境配置
所有服務的地址
服務 | 域名 |
---|---|
zipkin | zipkin-service.peng-mall:9411 |
sentinel | sentinel-service.peng-mall:8858 |
mysql8 | mysql8.peng-mall:3306 |
nacos | nacos.peng-mall:8848 |
rabbitmq | rabbitmq.peng-mall:5672 |
kibana | kibana.peng-mall:5601 |
elasticsearch | elasticsearch.peng-mall:9200 |
redis | redis.peng-mall:6379 |
給所有的服務新增生產環境配置檔案application-prod.yaml
我這裡以商品服務gulimall-order
為例,然後更新對應的服務地址
這裡需要留意的是我們不考慮強一致性的seata
事務解決辦法,而且我們沒有在k8s
上部署seata
,這裡把seata服務關閉了
8.11建立微服務Dockfile
所有服務的application-prod.yaml
的啟動埠都改成8080
因為每個服務都一個獨立的容器,他們在容器內部執行8080
沒有問題,對外對映的埠不一樣即可
所有的服務新增Dockerfile
,內容如下
- FROM: 指定基礎映象。在這裡,使用的是 Java 8 的官方 Docker 映象。這意味著構建的映象將基於這個 Java 8 映象。
- EXPOSE: 告訴 Docker 容器內部的應用會使用 8080 埠進行通訊。這並不會直接開放埠,只是為文件和將來的網路配置提供參考。
- VOLUME: 建立一個掛載點,容器執行時會將
/tmp
目錄標記為持久化儲存。這樣,在容器重啟時,儲存在/tmp
中的資料不會丟失。 - ADD: 將構建上下文中的檔案(在這個例子中是
target
目錄下的.jar
檔案)複製到容器中的/app.jar
路徑。這一命令不僅可以複製檔案,還可以自動解壓歸檔檔案。 - RUN: 在構建映象時執行命令。在這裡,它用於建立或更新
/app.jar
檔案的時間戳。這一命令通常用於確保該檔案在容器執行時被重新載入。 - ENTRYPOINT: 設定容器啟動時執行的命令。在這裡,指定了使用 Java 命令來執行
/app.jar
,並傳遞引數--spring.profiles.active=prod
,這意味著 Spring 應用將以prod
(生產)配置檔案啟動。
FROM java:8
EXPOSE 8080
VOLUME /tmp
ADD target/*.jar /app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java", "-jar", "/app.jar", "--spring.profiles.active=prod"]
8.12建立微服務k8s部署描述檔案
8.12.1Deployment
官方demo地址:https://github.com/kubesphere/devops-java-sample/tree/master/deploy/prod-ol
選擇sentinel-service
,選擇工作負載,點選該服務
選擇編輯檔案,複製sentinel-service
的配置
把所有app: sentinel
替換為自己的微服務名稱app: gulimall-auth-service
app: sentinel
app: gulimall-auth-service
8.12.2Service
官方demo
地址:https://github.com/kubesphere/devops-java-sample/blob/master/deploy/prod-ol/devops-sample-svc.yaml
選擇一個無狀態服務,這裡選擇的是sentinel
,選擇編輯配置檔案,把配置檔案複製出來進行修改
把所有app: sentinel
替換為自己的微服務名稱app: gulimall-auth-service
app: sentinel
app: gulimall-auth-service
把所有 name: sentinel
替換為自己的微服務名稱name: gulimall-auth-service
name: sentinel
name: gulimall-auth-service
8.12.3完整配置
kind: Deployment
apiVersion: apps/v1
metadata:
name: gulimall-auth-service
namespace: peng-mall
labels:
app: gulimall-auth-service
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: gulimall-auth-service
version: v1
template:
metadata:
labels:
app: gulimall-auth-service
version: v1
spec:
containers:
- name: gulimall-auth-service
image: $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$TAG_NAME
ports:
- containerPort: 8080
protocol: TCP
resources:
limits:
cpu: 1000m
memory: 500Mi
requests:
cpu: 10m
memory: 10Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent
restartPolicy: Always
terminationGracePeriodSeconds: 30
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
revisionHistoryLimit: 10
progressDeadlineSeconds: 600
---
kind: Service
apiVersion: v1
metadata:
name: gulimall-auth-service
namespace: peng-mall
labels:
app: gulimall-auth-serviceinel
version: v1
spec:
ports:
- name: http
port: 8080
protocol: TCP
targetPort: 8080
nodePort: 20001
selector:
app: gulimall-auth-serviceinel
type: NodePort
sessionAffinity: None
8.12.4為所有服務新增deploy
把gulimall-auth-service
的deploy
資料夾複製到所有服務
把所有app: sentinel
替換為自己的微服務名稱app: 微服務名稱
app: sentinel
app: 微服務名稱
把所有 name: sentinel
替換為自己的微服務名稱name: 微服務名稱
name: sentinel
name: 微服務名稱
修改埠號,從200001開始+2
8.13理解targetPort、Port、NodePort
targetPort:
- 這是指向容器內部服務的埠。當服務接收到請求時,它會將請求轉發到指定的
targetPort
。 - 可以是容器內部的埠號,也可以是名稱(如 "http" 或 "mysql"),表示容器內定義的埠。
port:
- 這是服務在 Kubernetes 中暴露的埠,外部的請求透過這個埠訪問服務。
port
是服務的虛擬埠,通常用於叢集內部的通訊。
nodePort:
- 這是一個可選欄位,用於將服務暴露給外部流量。Kubernetes 會在每個節點的指定埠上監聽並轉發請求到
port
。 nodePort
的值必須在 30000 到 32767 之間(預設情況下)。外部請求可以透過NodeIP:nodePort
訪問服務。
8.14備份
商城執行的基本程式都搭建完成的話記得備份
創作不易,感謝支援。