分佈式專題-分佈式緩存技術之MongoDB05-MongoDB高可用及新特性

前言

前面的章節,關於分佈式緩存技術,我們分析了《分佈式緩存技術之Redis的使用以及原理》、在MongoDB這最後一節裏,來說說MongoDB高可用方案以及4.0新特性。

關於MongoDB,一共五小節內容,分別是:

MongoDB在4.0升級改造以後,支持事務,且對於集羣策略進行優化…

筆者使用的mongodb版本是:
在這裏插入圖片描述
更多細節,就在本節與大家一起學習交流!

MongoDB用戶管理

在前面的章節,細心的讀者可能會注意到,在所有連接MongoDB的操作中,並沒有涉及到用戶名密碼的權限校驗,這樣對於一個數據庫而言怎麼能行呢?接下來看看MongoDB的用戶管理~

添加用戶

爲testdb 添加 tom 用戶

use testdb

db.createUser({user:"tom",pwd:"123",roles:[{role:"dbAdmin",db:"testdb"}]})

在這裏插入圖片描述
具體角色有什麼呢?通過命令查看一下:
在這裏插入圖片描述

角色 權限說明
read 允許用戶讀取指定數據庫
readWrite 允許用戶讀寫指定數據庫
dbAdmin 允許用戶在指定數據庫中執行管理函數,如索引創建、刪除,查看統計或訪問 system.profile
userAdmin 允許用戶向 system.users 集合寫入,可以找指定數據庫裏創建、刪除和管理用戶
clusterAdmin 只在 admin 數據庫中可用,賦予用戶所有分片和複製集相關函數的管理權限
readAnyDatabase 只在 admin 數據庫中可用,賦予用戶所有數據庫的讀權限
readWriteAnyDatabase 只在 admin 數據庫中可用,賦予用戶所有數據庫的讀寫權限
userAdminAnyDatabase 只在 admin 數據庫中可用,賦予用戶所有數據庫的 userAdmin 權限
dbAdminAnyDatabase 只在 admin 數據庫中可用,賦予用戶所有數據庫的 dbAdmin 權限
root 只在 admin 數據庫中可用。超級賬號,超級權限

查看所有用戶

db.system.users.find()

和用戶管理相關的操作基本都要在 admin 數據庫下運行,要先 use admin; 如果在某個單一的數據庫下,那隻能對當前數據庫的權限進行操作;

1.3、用戶刪除操作

db.system.users.remove({user:"tom"});

1.4 查看當前用戶權限

db.runCommand({usersInfo:"tom",showPrivileges:true})

1.5 修改密碼

use testdb

db.changeUserPassword("tom", "123456")

1.6、啓用用戶

db.auth("tom","123")

1.7、安全檢查 --auth

非testdb 是不能操作數據庫的,啓用自己的用戶才能訪問

非admin 數據庫的用戶不能使用數據庫命令,admin 數據庫中的數據經過認證爲管理員用戶

MongoDB高可用方案

詳解 RouteServer(路由服務器)、ConfigServer(配置服務器)、 Replica Set(副本集)、Shard(切片)、Chunk(分塊)MongDB 啓動與關閉

命令行啓動

$ ./mongod --fork --dbpath=/data/program/mongodb/data

配置文件啓動

$ ./mongod -f mongodb.cfg

mongoDB 基本配置/data/program/mongodb.cfg

dbpath=/data/program/mongodb/data

logpath=/data/program/mongodb/logs/mongodb.log

logappend=true

fork=true

bind_ip=192.168.200.111

port=27017

環境變量配置

export PATH=/data/program/mongodb/bin:$PATH

Mongodb 的三種集羣方式的搭建:Master-Slaver/Replica Set / Sharding。

主從搭建

這個是最簡答的集羣搭建,不過準確說也不能算是集羣,只能說是主備。並且官方已經不推薦這種方式,所以在這裏只是簡單的介紹下吧,搭建方式也相對簡單。

首先準備三臺機器,安裝好mongodb並配置好環境變量:
linux1:192.168.200.111 (mongodb:27017)- master
linux2:192.168.200.112 (mongodb:27017)- slave
linux3:192.168.200.113 (mongodb:27017)- slave

然後創建data與log文件夾,存放啓動日誌

在這裏插入圖片描述
主機配置
新增master配置文件

/data/program/mongodb/master-slave/master/mongodb.cfg

# 數據存儲路徑
dbpath=/data/program/mongodb/master-slave/master/data

# 日誌存儲路徑
logpath=/data/program/mongodb/master-slave/master/logs/mongodb.log

logappend=true

fork=true

bind_ip=192.168.200.111

port=27001

master=true

source=192.168.200.111:27002

從機配置
這裏linux2與linux3的配置相同
同樣地,新增slave配置文件

/data/program/mongodb/master-slave/slave/mongodb.cfg

dbpath=/data/program/mongodb/master-slave/slave/data

logpath=/data/program/mongodb/master-slave/slave/logs/mongodb.log

logappend=true

fork=true

bind_ip=192.168.200.112

port=27002

slave=true

source=192.168.200.112:27001

啓動服務

cd /data/program/mongodb/master-slave/master/

mongod --config mongodb.cfg #主節點 

cd /data/program/mongodb/master-slave/slave/

mongod --config mongodb.cfg #從節點

連接測試

#客戶端連接主節點
mongo	--host 192.168.200.111 --port 27001

#客戶端從節點
mongo	--host 192.168.200.112 --port 27002
mongo	--host 192.168.200.113 --port 27003

基本上只要在主節點和備節點上分別執行這兩條命令,Master-Slaver 就算搭建完成了。我沒有試過主節點掛掉後備節點是否能變成主節點,這裏也不推薦了。

MongoDB高級應用

MongoDB副本集

中文翻譯叫做副本集,不過我並不喜歡把英文翻譯成中文,總是感覺怪怪的。其實簡單來說就是集羣當中包含了多份數據,保證主節點掛掉了,備節點能繼續提供數據服務,提供的前提就是數據需要和主節點一致。如下圖:
在這裏插入圖片描述

Mongodb(M)表示主節點,Mongodb(S)表示備節點,Mongodb(A)表示仲裁節點。主備節點存儲數據,仲裁節點不存儲數據。客戶端同時連接主節點與備節點,不連接仲裁節點。

默認設置下,主節點提供所有增刪查改服務,備節點不提供任何服務。但是可以通過設置使備節點提供查詢服務,這樣就可以減少主節點的壓力,當客戶端進行數據查詢時,請求自動轉到備節點上。這個設置叫做 Read Preference Modes,同時 Java 客戶端提供了簡單的配置方式,可以不必直接對數據庫進行操作。

仲裁節點是一種特殊的節點,它本身並不存儲數據,主要的作用是決定哪一個備節點在主節點掛掉之後提升爲主節點,所以客戶端不需要連接此節點。這裏雖然只有一個備節點,但是仍然需要一個仲裁節點
來提升備節點級別。我開始也不相信必須要有仲裁節點,但是自己也試過沒仲裁節點的話,主節點掛了
備節點還是備節點,所以咱們還是需要它的。

介紹完了集羣方案,那麼現在就開始搭建了。

  1. 建立數據文件夾

一般情況下不會把數據目錄建立在 mongodb 的解壓目錄下,不過這裏方便起見,就建在 mongodb 解壓目錄下吧。

#三個目錄分別對應主,備,仲裁節點

mkdir -p /data/program/mongodb/replset/master

mkdir -p /data/program/mongodb/replset/slaver

mkdir -p /data/program/mongodb/replset/arbiter
  1. 建立配置文件

由於配置比較多,所以我們將配置寫到文件裏。

vi /data/program/mongodb/replset/master/mongodb.cfg

dbpath=/data/program/mongodb/replset/master/data

logpath=/data/program/mongodb/replset/master/logs/mongodb.log

logappend=true

replSet=shard002

bind_ip=192.168.200.111

port=27017

fork=true

vi /data/program/mongodb/replset/slave/mongodb.cfg

dbpath=/data/program/mongodb/replset/slave/data

logpath=/data/program/mongodb/replset/slave/logs/mongodb.log

logappend=true

replSet=shard002

bind_ip=192.168.200.112

port=27017

fork=true

vi /data/program/mongodb/replset/arbiter/mongodb.cfg

dbpath=/data/program/mongodb/replset/arbiter/data

logpath=/data/program/mongodb/replset/arbiter/logs/mongodb.log

logappend=true

replSet=shard002

bind_ip=192.168.209.130

port=27017

fork=true

參數解釋:

dbpath:數據存放目錄

logpath:日誌存放路徑

logappend:以追加的方式記錄日誌

replSet:replica set 的名字

bind_ip:mongodb 所綁定的 ip 地址

port:mongodb 進程所使用的端口號,默認爲 27017

fork:以後臺方式運行進程3、分發到集羣下的其他機器

#將從節點配置發送到 192.168.200.112

scp -r /data/program/mongodb/replset/slave [email protected]:/data/program/mongodb/replset

#將仲裁節點配置發送到 192.168.200.113

scp -r /data/program/mongodb/replset/arbiter [email protected]:/data/program/mongodb/replset
  1. 啓動 mongodb

進入每個 mongodb 節點的 bin 目錄下

#登錄 192.168.200.111 啓動主節點

monood -f /data/program/mongodb/replset/master/mongodb.cfg

#登錄 192.168.200.112 啓動從節點

mongod -f /data/program/mongodb/replset/slave/mongodb.cfg

#登錄 192.168.209.113 啓動仲裁節點

mongod -f /data/program/mongodb/replset/arbiter/mongodb.cfg

注意配置文件的路徑一定要保證正確,可以是相對路徑也可以是絕對路徑。

  1. 配置主,備,仲裁節點

可以通過客戶端連接 mongodb,也可以直接在三個節點中選擇一個連接 mongodb。

#ip 和 port 是某個節點的地址
mongo 192.168.200.111:27017

use admin

cfg={
	_id: "shard002",
	members: [{
		_id: 0,
		host: '192.168.200.111:27017',
		priority: 9
	}, {
		_id: 1,
		host: '192.168.200.112:27017',
		priority: 1
	}, {
		_id: 2,
		host: '192.168.200.113:27017',
		arbiterOnly: true
	}]
};

#使配置生效
rs.initiate(cfg)

注意:cfg 是相當於設置一個變量,可以是任意的名字,當然最好不要是 mongodb 的關鍵字,conf, config 都可以。最外層的_id 表示 replica set 的名字,members 裏包含的是所有節點的地址以及優先級。優先級最高的即成爲主節點,即這裏的 192.168.200.111:27017。特別注意的是,對於仲裁節點,需要有個特別的配置——arbiterOnly:true。這個千萬不能少了,不然主備模式就不能生效。

配置的生效時間根據不同的機器配置會有長有短,配置不錯的話基本上十幾秒內就能生效,有的配置需要一兩分鐘。如果生效了,執行 rs.status()命令會看到如下信息:

{
	"set": "testrs",
	"date": ISODate("2020-05-10T07:46:05Z"),
	"myState": 1,
	"members": [
		{
			"_id": 0,
			"name": "192.168.200.111:27004",
			"health": 1,
			"state": 1,
			"stateStr": "PRIMARY",
			"uptime": 200,
			"optime": Timestamp(1589113177, 1),
			"optimeDate":ISODate("2020-05-10T07:46:05Z"),
			"self": true
		},
		{
			"_id": 1,
			"name": "192.168.200.112:27003",
			"health": 1,
			"state": 2,
			"stateStr": "SECONDARY",
			"uptime": 200,
			"optime": Timestamp(1589113177, 1),
			"optimeDate":ISODate("2020-05-10T07:46:05Z"),
			"lastHeartbeat":ISODate("2020-05-10T07:46:05Z"),
			"pingMs": 0
		},
		{
			"_id": 2,
			"name": "192.168.200.113:27005",
			"health": 1,
			"state": 7,
			"stateStr": "ARBITER",
			"uptime": 200,
			"lastHeartbeat":ISODate("2020-05-10T07:46:05Z"),
			"pingMs": 0
		}
	],
	"ok": 1
}

如果配置正在生效,其中會包含如下信息:

"stateStr" : "STARTUP"

同時可以查看對應節點的日誌,發現正在等待別的節點生效或者正在分配數據文件。

現在基本上已經完成了集羣的所有搭建工作。至於測試工作,可以留給大家自己試試。一個是往主節點插入數據,能從備節點查到之前插入的數據(查詢備節點可能會遇到某個問題,可以自己去網上查查看)。二是停掉主節點,備節點能變成主節點提供服務。三是恢復主節點,備節點也能恢復其備的角色,而不是繼續充當主的角色。二和三都可以通過 rs.status()命令實時查看集羣的變化。

MongoDB數據分片

和Replica Set 類似,都需要一個仲裁節點,但是 Sharding 還需要配置節點和路由節點。就三種集羣搭建方式來說,這種是最複雜的。

  1. 配置數據節點

我這裏以多端口模擬分佈式,畢竟只有三臺機器麼,,

mkdir -p /data/program/mongodb/shard/replset/replica1/data

mkdir -p /data/program/mongodb/shard/replset/replica1/logs

mkdir -p /data/program/mongodb/shard/replset/replica2/data

mkdir -p /data/program/mongodb/shard/replset/replica2/logs

mkdir -p /data/program/mongodb/shard/replset/replica3/data

mkdir -p /data/program/mongodb/shard/replset/replica3/logs

vi /data/program/mongodb/shard/replset/replica1/mongodb.cfg

dbpath=/data/program/mongodb/shard/replset/replica1/data

logpath=/data/program/mongodb/shard/replset/replica1/logs/mongodb.log

logappend=true

fork=true

bind_ip=192.168.200.111

port=27001

replSet=shard001

shardsvr=true

vi /data/program/mongodb/shard/replset/replica2/mongodb.cfg

dbpath=/data/program/mongodb/shard/replset/replica2/data

logpath=/data/program/mongodb/shard/replset/replica2/logs/mongodb.log

logappend=true

fork=true

bind_ip=192.168.200.112

port=27002

replSet=shard001

shardsvr=true

vi /data/program/mongodb/shard/replset/replica3/mongodb.cfg

dbpath=/data/program/mongodb/shard/replset/replica3/data

logpath=/data/program/mongodb/shard/replset/replica3/logs/mongodb.log

logappend=true

fork=true

bind_ip=192.168.200.113

port=27003

replSet=shard001

shardsvr=true
  1. 啓動數據節點
mongod -f /data/program/mongodb/shard/replset/replica1/mongodb.cfg

#192.168.200.111:27001

mongod -f /data/program/mongodb/shard/replset/replica2/mongodb.cfg

#192.168.200.112:27002

mongod -f /data/program/mongodb/shard/replset/replica3/mongodb.cfg
  1. 使數據節點集羣生效

mongo 192.168.200.111:27001 #ip 和 port 是某個節點的地址

cfg={
	_id: "shard001",
	members: [{
		_id: 0,
		host: '192.168.200.111:27001'
	}, {
		_i
		d: 1,
		host: '192.168.200.112:27002'
	}, {
		_id: 2,
		host: '192.168.200.111:27003'

	}]
};

rs.initiate(cfg) #使配置生效

  1. 配置 configsvr
mkdir -p /data/program/mongodb/shard/configsvr/config1/data

mkdir -p /data/program/mongodb/shard/configsvr/config1/logs

mkdir -p /data/program/mongodb/shard/configsvr/config2/data

mkdir -p /data/program/mongodb/shard/configsvr/config2/logs

mkdir -p /data/program/mongodb/shard/configsvr/config3/data

mkdir -p /data/program/mongodb/shard/configsvr/config3/logs

/opt/mongodb/shard/configsvr/config1/mongodb.cfg

dbpath=/data/program/mongodb/shard/configsvr/config1/data

configsvr=true

port=28001

fork=true

logpath=/data/program/mongodb/shard/configsvr/config1/logs/mongodb.log

replSet=configrs

logappend=true

bind_ip=192.168.200.111

/data/program/mongodb/shard/configsvr/config2/mongodb.cfg

dbpath=/data/program/mongodb/shard/configsvr/config2/data

configsvr=true

port=28002

fork=true

logpath=/data/program/mongodb/shard/configsvr/config2/logs/mongodb.log

replSet=configrs

logappend=true

bind_ip=192.168.200.112

/data/program/mongodb/shard/configsvr/config3/mongodb.cfg

dbpath=/data/program/mongodb/shard/configsvr/config3/data

configsvr=true

port=28003

fork=true

logpath=/data/program/mongodb/shard/configsvr/config3/logs/mongodb.log

replSet=configrs

logappend=true

bind_ip=192.168.200.113
  1. 啓動 configsvr 節點
mongod	-f	/data/program/mongodb/shard/configsvr/config1/mongodb.cfg
#192.168.200.111:28001

mongod	-f	/data/program/mongodb/shard/configsvr/config2/mongodb.cfg

#192.168.200.111:28002

mongod	-f	/data/program/mongodb/shard/configsvr/config3/mongodb.cfg

#192.168.200.111:28003

  1. 使 configsvr 節點集羣生效

mongo 192.168.200.111:28001 #ip 和 port 是某個節點的地址
use admin #先切換到 admin

cfg={
	_id: "configrs",
	members: [{
		_id: 0,
		host: '192.168.200.111:28001'
	}, {
		d: 1,
		host: '192.168.200.111:28002'
	}, {
		_id: 2,
		host: '192.168.200.111:28003'
	}]
};

rs.initiate(cfg) #使配置生效

配置路由節點

mkdir -p /data/program/mongodb/shard/routesvr/logs
#注意:路由節點沒有 data 文件夾
vi /data/program/mongodb/shard/routesvr/mongodb.cfg

configdb=configrs/192.168.200.111:28001,192.168.200.111:28002,192.168.200.111:28003

port=30000

fork=true

logpath=/data/program/mongodb/shard/routesvr/logs/mongodb.log

logappend=true

bind_ip=192.168.200.111
  1. 啓動路由節點

./mongos -f /data/program/mongodb/shard/routesvr/mongodb.cfg

這裏我們沒有用配置文件的方式啓動,其中的參數意義大家應該都明白。一般來說一個數據節點對應一個配置節點,仲裁節點則不需要對應的配置節點。注意在啓動路由節點時,要將配置節點地址寫入到啓動命令裏。

  1. 配置 Sharding

mongo 192.168.200.111:30000 #這裏必須連接路由節點

sh.addShard("shard001/192.168.200.111:27001");

sh.addShard("shard002/192.168.200.111:27017");

#shard001、shard002 表示 replica set 的名字 當把主節點添加到 shard 以後,會自動找到 set 裏的主,備,決策節點

use testdb

sh.enableSharding("testdb") #testdb is database name sh.shardCollection("testdb.testcon",{"name":”hashed”}) db.collection.status()

第一個命令很容易理解,第二個命令是對需要進行 Sharding 的數據庫進行配置,第三個命令是對需要進行 Sharding 的 Collection 進行配置,這裏的 testcon 即爲 Collection 的名字。另外還有個 key,這個是比較關鍵的東西,對於查詢效率會有很大的影響。

到這裏 Sharding 也已經搭建完成了,以上只是最簡單的搭建方式,其中某些配置仍然使用的是默認配置。如果設置不當,會導致效率異常低下,所以建議大家多看看官方文檔再進行默認配置的修改。

以上三種集羣搭建方式首選 Replica Set,只有真的是大數據,Sharding 才能顯現威力,畢竟備節點同步數據是需要時間的。Sharding 可以將多片數據集中到路由節點上進行一些對比,然後將數據返回給客戶端,但是效率還是比較低的說。

我自己有測試過,不過具體的機器配置已經不記得了。Replica Set 的 ips 在數據達到 1400W 條時基本能達到 1000 左右,而 Sharding 在 300W 時已經下降到 500 IPS,兩者的單位數據大小大概是 10kb。大家在應用的時候還是多多做下性能測試,畢竟不像 Redis 有 benchmark。

MongoDB索引

索引

  1. 創建索引

db.books.ensureIndex{{number:1}}
創建索引同時指定索引的名字
db.books.ensureIndex({number:1},{name:“book_”})

  1. 索引使用需要注意的地方
  • 創建索引的時候注意 :1 是正序創建索引 ,-1 是倒序創建索引

  • 索引的創建在提高查詢性能的同事會影響插入的性能 對於經常查詢少插入的文檔可以考慮用索引

  • 符合索引要注意索引的先後順序

  • 每個鍵全建立索引不一定就能提高性能呢 索引不是萬能的

  • 在做排序工作的時候如果是超大數據量也可以考慮加上索引 用來提高排序的性能

  1. 唯一索引
    解決文檔 books 不能插入重複的數值
  2. 剔除重複值

#則插入相同的 name 值會報錯
db.books.ensureIndex({name:-1},{unique:true})
如果建議唯一索引之前已經有重複數值如何處理?
#剔除重複數值
db.books.ensureIndex({name:1},{name:“book_”,unique:true,dropDups:true })

  1. 後臺執行創建索引
    爲了解決創建索引鎖表的問題,在不影響查詢功能,可以在後臺運行

db.books.ensureIndex({name:1},{background:true})

  1. 強制查詢已經建立好的索引

#後一個 name 爲索引名,正序倒序依據建立索引的規則,否則會報錯
db.books.find({name:“323book”}).hint({name:1})

  1. 在 shell 查看數據庫已經建立的索引

db.system.indexes.find()
db.system.namespaces.find()

  1. 查詢索引信息和查詢狀態信息

db.books.find({name:“123book”}).explain()

  1. 批量和精確刪除索引

db.runCommand({dropIndexes : “books” , index:“name_-1”})
db.runCommand({dropIndexes : “books” , index:"*"})

二維索引

建立二維索引

#默認會建一個[-108,108]的範圍
db.map.ensureIndex({gis:“2d”},{min:-1,max:201})

MongoDB數據轉存及恢復

  1. 導出數據(中斷其他操作)
    使用 mongoexport 命令行

-d 指明使用的庫
-c 指明要導出的表
-o 指明要導出的文件名
-csv 指定導出的 csv 格式
-q 過濾導出
–type<json|csv|tsv>

把數據好 testdb 中的 persons 導出 , 導出其他主機數據庫的文檔

mongoexport --host 192.168.0.16 --port 37017

  1. 導入數據(中斷其他操作)

mongoimport --db testdb --collections persons --file d:/persons.json

  1. 運行時備份 mongodump.exe

API: http://cn.docs.mongodb.org/manual/reference/mongodump

mongodump --host 127.0.0.1:27017 -d testdb -o d:/testdb

  1. 運行時恢復 mongorestore.exe

API:http://cn.docs.mongodb.org/manual/reference/mongorestore

恢復數據庫

db.dropDatabase()
mongorestore --host 127.0.0.1:27017 -d testdb -directoryperdb

  1. mongoDB 是文件數據庫這其實就可以用拷貝文件的方式進行備份
  2. 上鎖和解鎖

db.runCommand({fsync:1,lock:1}) #上鎖 db.currentOp() #解鎖

  1. 數據修復

當停電等不可逆轉災難來臨的時候,由於 mongodb 的存儲結構導致會產生垃圾數據,在數據恢復以後這垃圾數據依然存在,這是數據庫提供一個自我修復的能力.使用起來很簡單

db.repairDatabase()

後記

更多架構知識,歡迎關注本套Java系列文章,地址導航Java架構師成長之路

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章