【最佳實踐】高可用mongodb叢集(1分片+3副本):規劃及部署

2023-10-11 12:02:34

結合我們的生產需求,本次詳細整理了最新版本 MonogoDB 7.0 叢集的規劃及部署過程,具有較大的參考價值,基本可照搬使用。
適應資料規模為T級的場景,由於設計了分片支撐,後續如有巨量資料量需求,可分片橫向擴充套件。

■■■ 分片叢集規劃

■ Configure hostname、hosts file、ip address

vim /etc/hosts
7.7.7.11 node1
7.7.7.12 node2
7.7.7.13 node3

注:規劃、實施、運維均採用host解析的方式判定各個節點,因此需確保該組態檔需正確解析node1、node2、node3.

■ 節點的角色及埠分配

┌────node1────┬────node2────┬────node3────┬port─┐
│mongos server│mongos server│mongos server│20000│
├─────────────┼─────────────┼─────────────┼─────┤
│config server│config server│config server│21000│
│(Primary)    │(Secondary)  │(Secondary)  │     │
├─────────────┼─────────────┼─────────────┼─────┤
│shard server1│shard server1│shard server1│27001│
│(Primary)    │(Secondary)  │(Secondary)  │     │
└─────────────┴─────────────┴─────────────┴─────┘

■■■ Pre-task preparation

■ 依賴包

yum install -y libcurl openssl [3.6.23]
yum install -y xz-libs [6.0.0另需]

■ 使用者及使用者組

groupadd mongod
groupadd mongodb
useradd -g mongod -G mongodb mongod
echo "passwd"|passwd mongod --stdin

■ mongodb 下載、安裝

官方所有媒介均從這個入口下載:
https://www.mongodb.com/try/download

#20230911 最新版本,選擇合適的平臺媒介
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-7.0.1.tgz
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel80-7.0.1.tgz

mkdir -p /u01
KDR=/u01
cd ${KDR}
TGZ=mongodb-linux-x86_64-rhel70-7.0.1

#cp_unzip_chown_ln:
cp /u01/nfs/MongoDB/${TGZ}.tgz .
tar zxvf ${TGZ}.tgz
chown -R mongod:mongod ${TGZ}
ln -s ${KDR}/${TGZ}/bin/* /usr/local/bin/

■ database-tools 下載、安裝

6.0版本開始,將資料庫相關的工具單獨管理,以利於實時升級、釋出
wget https://fastdl.mongodb.org/tools/db/mongodb-database-tools-rhel70-x86_64-100.8.0.tgz
wget https://fastdl.mongodb.org/tools/db/mongodb-database-tools-rhel80-x86_64-100.8.0.tgz

KDR=/u01
cd ${KDR}
TGZ=mongodb-database-tools-rhel70-x86_64-100.8.0
【後續步驟同上】
#cp_unzip_chown_ln:

■ mongosh 下載、安裝

https://downloads.mongodb.com/compass/mongosh-2.0.0-linux-x64.tgz

KDR=/u01
cd ${KDR}
#TGZ=mongosh-1.10.6-linux-x64
TGZ=mongosh-2.0.0-linux-x64
【後續步驟同上】
#cp_unzip_chown_ln:

■ chronyd

設定時間同步

■ selinux

關閉selinux

■ firewalld

設定防火牆,確保放行這幾個埠

firewall-cmd --add-port=20000/tcp --permanent
firewall-cmd --add-port=21000/tcp --permanent
firewall-cmd --add-port=27001-27003/tcp --permanent
firewall-cmd --reload

■ 3個節點建立mongodb資料庫檔案目錄

MongoDir=/u01/mongodb
mkdir -p ${MongoDir}
chown -R mongod:mongod ${MongoDir}
cat >> /etc/profile << EOF
export MongoDir=${MongoDir}
EOF

■ 以下均用mongod使用者操作

su - mongod
echo ${MongoDir}

■ 3個節點均建立6個目錄:conf、mongos、config、shard1、shard2、shard3

mkdir -p ${MongoDir}/conf
mkdir -p ${MongoDir}/mongos/log
mkdir -p ${MongoDir}/config/data
mkdir -p ${MongoDir}/config/log
mkdir -p ${MongoDir}/shard1/data
mkdir -p ${MongoDir}/shard1/log
mkdir -p ${MongoDir}/shard2/data
mkdir -p ${MongoDir}/shard2/log
mkdir -p ${MongoDir}/shard3/data
mkdir -p ${MongoDir}/shard3/log

■ 檢查目錄結構

tree ${MongoDir} -L 2 --dirsfirst
├── conf
│   ├── config.conf
│   ├── mongos.conf
│   ├── shard1.conf
│   ├── shard2.conf
│   └── shard3.conf
├── config
│   ├── data
│   └── log
├── mongos
│   └── log
├── shard1
│   ├── data
│   └── log
├── shard2
│   ├── data
│   └── log
└── shard3
    ├── data
    └── log

■■■ config server

mongodb3.4以後要求設定伺服器也建立副本集,不然叢集搭建不成功

■ 組態檔

【3個節點執行】

cat > ${MongoDir}/conf/config.conf << EOF
processManagement:
  fork: true
  pidFilePath: ${MongoDir}/config/log/configsvr.pid
net:
  bindIpAll: true
  port: 21000
  ipv6: true
  maxIncomingConnections: 20000
storage:
  dbPath: ${MongoDir}/config/data
  wiredTiger:
    engineConfig:
      cacheSizeGB: 1
systemLog:
  destination: file
  path: ${MongoDir}/config/log/configsvr.log
  logAppend: true
sharding:
  clusterRole: configsvr
replication:
  replSetName: configs
setParameter:
  connPoolMaxConnsPerHost: 20000
EOF

■ 啟動3個 config server

mongod -f ${MongoDir}/conf/config.conf

■ 登入任意一臺設定伺服器,初始化設定副本集

mongosh node1:21000

定義config變數:
config = {_id: "configs", members: [
  {_id: 0, host: "node1:21000"},
  {_id: 1, host: "node2:21000"},
  {_id: 2, host: "node3:21000"} ]
}
其中,_id: "configs"應與組態檔中的設定一致,"members" 中的 "host" 為三個節點的 ip 和 port

初始化副本集:
rs.initiate(config)

檢視此時狀態:
rs.status()

■■■ shard server

■ shard server1

【3個節點執行】
【注意】如果資料量並不大,分片需求不明顯,可以先只建立shard server1,另外的分片2、分片3先不建立,後續根據實際需求可隨時建立。

cat > ${MongoDir}/conf/shard1.conf << EOF
processManagement:
  fork: true
  pidFilePath: ${MongoDir}/shard1/log/shard1.pid
net:
  bindIpAll: true
  port: 27001
  ipv6: true
  maxIncomingConnections: 20000
storage:
  dbPath: ${MongoDir}/shard1/data
  wiredTiger:
    engineConfig:
      cacheSizeGB: 5
systemLog:
  destination: file
  path: ${MongoDir}/shard1/log/shard1.log
  logAppend: true
sharding:
  clusterRole: shardsvr
replication:
  replSetName: shard1
security:
  keyFile: ${MongoDir}/conf/mongo.keyfile
setParameter:
  connPoolMaxConnsPerHost: 20000
  maxNumActiveUserIndexBuilds: 6
EOF

啟動3個 shard1 server:
mongod -f ${MongoDir}/conf/shard1.conf

登陸任意節點,初始化副本集:
注:初始化副本集的操作不能在仲裁節點上執行!在哪個節點初始化,則哪個節點預設是副本集的主節點。

mongosh --port 27001
使用admin資料庫,定義副本集設定,"arbiterOnly":true 代表其為仲裁節點:
use admin
#模式選擇 P/S/S
config = {_id: "shard1", members: [
    {_id: 0, host: "node1:27001"},
    {_id: 1, host: "node2:27001"},
    {_id: 2, host: "node3:27001"}
  ]
}
#模式選擇 P/S/A
config = {_id: "shard1", members: [
    {_id: 0, host: "node1:27001"},
    {_id: 1, host: "node2:27001"},
    {_id: 2, host: "node3:27001", arbiterOnly:true}
  ]
}
rs.initiate(config);
rs.status()

■ shard server2 【備用,暫不執行】

■ shard server3 【備用,暫不執行】

■■■ mongos server

【3個節點執行】
注:需先啟動 config server 和 shard server, 後啟動 mongos server (3個節點)

cat > ${MongoDir}/conf/mongos.conf << EOF
processManagement:
  fork: true
  pidFilePath: ${MongoDir}/mongos/log/mongos.pid
net:
  bindIpAll: true
  port: 20000
  ipv6: true
  maxIncomingConnections: 20000
systemLog:
  destination: file
  path: ${MongoDir}/mongos/log/mongos.log
  logAppend: true
sharding:
  configDB: configs/node1:21000,node2:21000,node3:21000
EOF

啟動3個 mongos server:
mongos -f ${MongoDir}/conf/mongos.conf

■■■ 啟用分片機制

以上設定過程可見,mongos server 只有 configsvr 設定資訊,並無 shardsvr 的資訊,因此還需設定使分片可用,否則是無法使用分片的,就是說:shardsvr 無法直接操作,只能通過 mongos server 啟用分片機制後,才能操作
問題:如果只有一個分片,還需要設定嗎?答案是:需要,原因見上。

■ 3.6.23 / 7.0.0

登陸任一 mongos server, 使用 admin 資料庫,串聯路由伺服器與分配副本集:

mongosh node1:20000
use admin
sh.addShard("shard1/node1:27001,node2:27001,node3:27001")
檢視叢集狀態:
sh.status()
sh.removeShard("shard2")

■■■ 使用分片機制

暫不涉及,後續可視需要再設定。

■■■ 使用者許可權設定

對於搭建好的mongodb分片叢集,為了安全,需啟動安全認證,使用賬號密碼登入。
預設的mongodb是不設定認證的。只要ip和埠正確就能連線,這樣是很不安全的。
mongodb官網聲稱,為了能保障mongodb的安全可以做以下幾個步驟:
1、使用新的埠,預設的27017埠如果一旦知道了ip就能連線上,不太安全
2、設定mongodb的網路環境,最好將mongodb部署到公司伺服器內網,這樣外網是存取不到的。公司內部存取使用vpn等
3、開啟安全認證。認證要同時設定伺服器之間的內部認證方式,同時要設定使用者端連線到叢集的賬號密碼認證方式
以下詳細描述如何設定安全認證。

■ node1 建立副本集認證的key檔案

用openssl生成密碼檔案,然後使用chmod來更改檔案許可權,僅為檔案所有者提供讀取許可權

cd ${MongoDir}/conf
openssl rand -out mongo.keyfile -base64 90
chmod 600 mongo.keyfile
ll mongo.keyfile
-r-------- 1 mongod mongod 122 Aug  4 08:33 mongo.keyfile

提示:所有副本集節點都必須要用同一份keyfile,一般是在一臺機器上生成,然後拷貝到其他機器上,且必須有讀的許可權,否則將來會報錯:
permissions on ${MongoDir}/conf/mongo.keyfile are too open

■ node1 修改組態檔指定keyfile

編輯組態檔,新增如下內容:

for FILE in ${MongoDir}/conf/{config,shard1,mongos}.conf
do
cat >> ${FILE} << EOF
security:
  keyFile: /u01/mongodb/conf/mongo.keyfile
EOF
done

■ node1 將修改後的組態檔和key檔案拷貝到 node2、node3

scp ${MongoDir}/conf/{config.conf,shard[1-3].conf,mongos.conf,mongo.keyfile} node2:${MongoDir}/conf
scp ${MongoDir}/conf/{config.conf,shard[1-3].conf,mongos.conf,mongo.keyfile} node3:${MongoDir}/conf

■ 重新啟動節點

依次啟動設定節點、分片節點、路由節點

■ 建立帳號和認證

使用者端mongosh,通過localhost或127.0.0.1登入任意一個mongos路由,可以執行建立操作
提示:此時相當於一個後門,只能在 admin 下新增使用者
提示:通過mongos新增的賬號資訊,只會儲存到設定節點的服務中,具體的資料節點不儲存賬號資訊,因此分片中的賬號資訊不涉及到同步問題
建議:先建立超管使用者和普通使用者,然後再開啟安全設定

建立管理員帳號:

use admin
db.createUser({user: "admin", pwd: "passwd!2#", roles: ["root"]})
db.createUser({user: "inspur", pwd: "passwd!2#", roles: ["userAdminAnyDatabase"]})
db.dropUser("inspur")
鑑權操作:
db.auth("admin", "passwd!2#")
db.auth("inspur", "passwd!2#")

建立一個普通許可權帳號:

use testdb
db.createUser({user: "liking", pwd: "passwd!2#", roles: ["readWrite"]})
db.auth("liking", "passwd!2#")

■ 用管理員帳號可檢視整體的分片情況

use admin
db.auth("admin", "passwd!2#")
sh.status()

■ 用普通帳號存取資料

use testdb
db.auth("liking", "passwd!2#")

■ 使用者端連線多個mongos的標準格式

mongosh mongodb://'admin':'passwd%212%23'@node1:20000,node2:20000,node3:20000/testdb?authSource=admin