研发需要,部署MongoDB的一主一副一仲裁集群,用于解锁对事务的支持,顺带提供高可用。同时,还会一同部署一备份节点和一内存缓存节点,备份节点为数据提供冷备,使用LUN快照,保障数据异常时还有机会进行回滚;内存节点用于加速查询速度。
环境
CentOS 8 x86_64
前置工作
准备目录
mkdir /data/etc -p
mkdir /data/db -p
mkdir /data/log -p
如上,分别新建了几个目录,其中:
- etc目录用于存放配置文件
- db用于存放数据库文件
- log用于存放所有的日志(不含数据库的操作日志)
优化
THP优化
按照官方的说法,Linux Kernel默认开启了内存透明大页(THP)支持。透明大页面是一种Linux内存管理系统,通过使用更大的内存页面,可以减少具有大量内存的计算机上的Translation Lookaside Buffer(TLB)查找的开销。但是由于数据库对内存的访问模式往往是稀疏而不是连续的,因此透明大页一定程度上会影响数据库的性能,所以要关掉。
命令直接贴出来了
mkdir /etc/tuned/virtual-guest-no-thp
cat > /etc/tuned/virtual-guest-no-thp/tuned.conf << EOF
[main]
include=virtual-guest
[vm]
transparent_hugepages=never
EOF
tuned-adm profile virtual-guest-no-thp
文件系统优化
Linux默认方式下会对文件访问的时间进行记录,这些操作是没有必要的,因此可以关掉
直接改/etc/fstab即可,使得挂载记录为如下配置:
UUID=ecdbaaaa-1113-222b-3336-444fa1112227 /data xfs defaults,noatime 0 0
重启后即可看到生效了:/dev/sdb1 on /data type xfs (rw,noatime,attr2,inode64,noquota)
关闭磁盘预读
这个应该归属到阵列卡设置里,将阵列卡的读写策略进行调整即可。
放开资源限制
ulimit,该优化已直接写进systemd的service文件中
禁用NUMA
由于我用的不是宿主机,因此无法直接管理NUMA调度域
按照一些文献和资料的说法,假设一台服务器有两个CPU,即他会存在两个NUMA调度域,由于内存和CPU是直连的,因此不跨调度域执行的情况下响应速度会比跨调度域执行快,同时如果两个调度域内内存命中情况不一样的话(A节点剩余0.1G内存可用,B节点剩余32G内存可用)并且某个CPU节点的内存不足时,会导致swap交换发生,而不是从远程节点分配内存。即swap insanity
新建用户
groupadd mongod
useradd -s /sbin/nologin -M -g mongod mongod
检查目录结构
正确的目录结构应该如下(.为/data):
.
├── db
│ ├── admin
│ │ ├── collection
│ │ │ ├── 17--7409093569969147507.wt
│ │ │ ├── 19--7409093569969147507.wt
│ │ │ └── 31--7409093569969147507.wt
│ │ └── index
│ │ ├── 18--7409093569969147507.wt
│ │ ├── 20--7409093569969147507.wt
│ │ ├── 32--7409093569969147507.wt
│ │ └── 33--7409093569969147507.wt
│ ├── config
│ │ ├── collection
│ │ │ ├── 21--7409093569969147507.wt
│ │ │ └── 27--7409093569969147507.wt
│ │ └── index
│ │ ├── 22--7409093569969147507.wt
│ │ ├── 24--7409093569969147507.wt
│ │ └── 28--7409093569969147507.wt
│ ├── diagnostic.data
│ │ ├── metrics.2019-12-07T15-08-54Z-00000
│ │ ├── metrics.2019-12-07T15-16-56Z-00000
│ │ ├── metrics.2019-12-07T15-24-55Z-00000
│ │ └── metrics.interim
│ ├── journal
│ │ ├── WiredTigerLog.0000000003
│ │ ├── WiredTigerPreplog.0000000001
│ │ └── WiredTigerPreplog.0000000002
│ ├── local
│ │ ├── collection
│ │ │ ├── 0--7409093569969147507.wt
│ │ │ ├── 10--7409093569969147507.wt
│ │ │ ├── 16--7409093569969147507.wt
│ │ │ ├── 2--7409093569969147507.wt
│ │ │ ├── 4--7409093569969147507.wt
│ │ │ ├── 6--7409093569969147507.wt
│ │ │ └── 8--7409093569969147507.wt
│ │ └── index
│ │ ├── 11--7409093569969147507.wt
│ │ ├── 1--7409093569969147507.wt
│ │ ├── 3--7409093569969147507.wt
│ │ ├── 5--7409093569969147507.wt
│ │ ├── 7--7409093569969147507.wt
│ │ └── 9--7409093569969147507.wt
│ ├── _mdb_catalog.wt
│ ├── mongod.lock
│ ├── sizeStorer.wt
│ ├── storage.bson
│ ├── WiredTiger
│ ├── WiredTigerLAS.wt
│ ├── WiredTiger.lock
│ ├── WiredTiger.turtle
│ └── WiredTiger.wt
├── etc
│ ├── mongod.key
│ └── mongod.yml
├── log
│ ├── mongod.log
│ ├── mongod.log.2019-12-06T08-16-12
│ ├── mongod.log.2019-12-07T08-48-16
│ ├── mongod.log.2019-12-07T14-13-29
│ ├── mongod.log.2019-12-07T14-13-49
│ ├── mongod.log.2019-12-07T14-14-09
│ ├── mongod.log.2019-12-07T14-14-30
│ ├── mongod.log.2019-12-07T14-14-50
│ ├── mongod.log.2019-12-07T14-15-10
│ ├── mongod.log.2019-12-07T14-15-22
│ ├── mongod.log.2019-12-07T14-15-42
│ ├── mongod.log.2019-12-07T14-16-03
│ ├── mongod.log.2019-12-07T14-16-23
│ ├── mongod.log.2019-12-07T14-23-03
│ ├── mongod.log.2019-12-07T14-56-40
│ ├── mongod.log.2019-12-07T15-07-18
│ ├── mongod.log.2019-12-07T15-08-53
│ ├── mongod.log.2019-12-07T15-16-55
│ └── mongod.log.2019-12-07T15-24-53
├── mongodb-linux-x86_64-rhel80-4.2.1
│ ├── bin
│ │ ├── bsondump
│ │ ├── install_compass
│ │ ├── mongo
│ │ ├── mongod
│ │ ├── mongodump
│ │ ├── mongoexport
│ │ ├── mongofiles
│ │ ├── mongoimport
│ │ ├── mongoreplay
│ │ ├── mongorestore
│ │ ├── mongos
│ │ ├── mongostat
│ │ └── mongotop
│ ├── LICENSE-Community.txt
│ ├── MPL-2
│ ├── README
│ ├── THIRD-PARTY-NOTICES
│ └── THIRD-PARTY-NOTICES.gotools
└── mongodb-linux-x86_64-rhel80-4.2.1.tgz
16 directories, 81 files
配置文件
该配置文件参考官方文档,对应mongodb的4.2版本,其他版本慎用。配置文件为yaml语法
systemLog:
# 日志等级,0为Info等级
verbosity: 0
# 静默启动,交由systemd管理所以不用
quiet: false
# 追踪所有的异常,将会输出所有的日志
traceAllExceptions: true
# 日志facility
syslogFacility: "daemon"
# 日志位置
path: "/data/log/mongod.log"
# 每次启动后使用新的日志文件
logAppend: false
# 使用新日志文件,重命名旧日志
logRotate: "rename"
# 日志独立,不给syslog接管
destination: "file"
# 日志输出时间格式,日志时间为本地时区
timeStampFormat: "iso8601-local"
# 全局日志等级
# component:
processManagement:
# 不使用fork
fork: false
# PID文件路径
pidFilePath: "/tmp/mongod.pid"
# 云监控
# cloud:
# monitoring:
# free:
# state: <string>
# tags: <string>
net:
port: 27017
bindIp: "0.0.0.0"
# bindIpAll: true
# 最大连接
maxIncomingConnections: 65536
# 启用写入对象检查
wireObjectCheck: true
# 启用IPv6
ipv6: false
# 域描述符
unixDomainSocket:
enabled: false
# pathPrefix: <string>
# filePermissions: <int>
tls:
# 关闭TLS
mode: "disabled"
# certificateSelector: <string>
# clusterCertificateSelector: <string>
# certificateKeyFile: <string>
# certificateKeyFilePassword: <string>
# clusterFile: <string>
# clusterPassword: <string>
# CAFile: <string>
# clusterCAFile: <string>
# CRLFile: <string>
# allowConnectionsWithoutCertificates: <boolean>
# allowInvalidCertificates: <boolean>
# allowInvalidHostnames: <boolean>
# disabledProtocols: <string>
# FIPSMode: <boolean>
compression:
# 压缩模式
# 默认配置:snappy,zstd,zlib,不需要压缩因此关闭
compressors: "disabled"
# 同步执行
serviceExecutor: "synchronous"
security:
# key文件,用于副本集间认证
keyFile: "/data/etc/mongod.key"
# 集群认证模式
clusterAuthMode: "keyFile"
# 安全认证
# 禁用的话数据库将会没有权限控制,初次配置完后记得改回去
# 要改为"enabled"
authorization: "disabled"
# 滚动认证,没看懂文档啥意思,默认关了吧
transitionToAuth: false
# 允许执行JS脚本
javascriptEnabled: true
# 企业版才有
# redactClientLogData: <boolean>
# 集群IP白名单
# clusterIpSourceWhitelist:
# - 192.168.0.0/16
# - 192.167.0.0/16
# Kerberos认证
# sasl:
# hostName: <string>
# serviceName: <string>
# saslauthdSocketPath: <string>
# 数据库加密,关闭,报错,注释掉
# enableEncryption: false
# encryptionCipherMode: <string>
# encryptionKeyFile: <string>
# kmip:
# keyIdentifier: <string>
# rotateMasterKey: <boolean>
# serverName: <string>
# port: <string>
# clientCertificateFile: <string>
# clientCertificatePassword: <string>
# clientCertificateSelector: <string>
# serverCAFile: <string>
# LDAP关闭,企业版才有
# ldap:
# servers: <string>
# bind:
# method: <string>
# saslMechanisms: <string>
# queryUser: <string>
# queryPassword: <string>
# useOSDefaults: <boolean>
# transportSecurity: <string>
# timeoutMS: <int>
# userToDNMapping: <string>
# authz:
# queryTemplate: <string>
storage:
# 指定数据库存储的目录
dbPath: "/data/db"
# 启动后继续重建不完整的索引,副本集模式下不允许修改
# indexBuildRetry: true
#
journal:
# 启用文件系统日志,副本集成员无法指定
enabled: true
# 日志提交周期,默认100,单位为毫秒,取值范围1-500
commitIntervalMs: 500
# 使用独立的目录存储每个数据库
directoryPerDB: true
# fsync刷新操作到磁盘的周期,默认为60
syncPeriodSecs: 60
# 存储引擎,wiredTiger/inMemory
engine: "wiredTiger"
wiredTiger:
engineConfig:
# 缓存大小,小数
cacheSizeGB: 1.0
# 日志压缩方法,默认snappy
journalCompressor: "none"
# 分离存储索引
directoryForIndexes: true
# 最大缓存文件大小,超出会直接导致程序退出。0为无限制大小
maxCacheOverflowFileSizeGB: 0
collectionConfig:
# 块压缩方法
blockCompressor: "none"
indexConfig:
# 前缀压缩
prefixCompression: false
# inMemory:
# engineConfig:
# # 浮点数,Default: 50% of physical RAM less 1 GB
# inMemorySizeGB: <number>
operationProfiling:
# 操作分析模式,打开会影响性能
mode: "off"
# slowOpThresholdMs: <int>
# slowOpSampleRate: <double>
replication:
# 副本同步日志的最大大小,MB
# 建议为磁盘大小的5%
oplogSizeMB: 10240
# 副本集名称,一个集群名称要相同
replSetName: "BSDB"
# 官方文档没说,注释掉
# secondaryIndexPrefetch: <string>
# 启动读取事件关注,事务使用,关掉会影响事务
enableMajorityReadConcern: true
# 分片集
# sharding:
# clusterRole: <string>
# archiveMovedChunks: <boolean>
# 审计日志,开了影响性能
# auditLog:
# # 目标,该选项一旦设置将会启用日志审计
# destination: "file"
# format: <string>
# path: <string>
# filter: <string>
KeyFile配置
博主我在KeyFile上栽了将近一天时间。这个KeyFile在被mongod加载时会检查权限是否过大,如果过大daemon会直接退出,然而日志里却只有一个INFO等级的日志,trace并没有任何直接相关的内容输出。所以在保存完配置文件后,接着开始生成key,严格按照下面的步骤进行
openssl rand -base64 741 > /data/etc/mongod.key
# 0600的权限一定要给,否则就是无法启动
chmod 0600 /data/etc/mongod.key
service配置
mongodb交由systemd管理,对应的service文件如下
[Unit]
Description=MongoDB Database Server
Documentation=https://docs.mongodb.org/manual
After=network.target
[Service]
User=mongod
Group=mongod
Environment="OPTIONS=-f /data/etc/mongod.yml"
ExecStart=/data/mongodb-linux-x86_64-rhel80-4.2.1/bin/mongod $OPTIONS
ExecStartPre=/usr/bin/chown mongod:mongod /data -R
PermissionsStartOnly=true
PIDFile=/tmp/mongod.pid
Type=simple
Restart=on-failure
RestartSec=20
# file size
LimitFSIZE=infinity
# cpu time
LimitCPU=infinity
# virtual memory size
LimitAS=infinity
# open files
LimitNOFILE=64000
# processes/threads
LimitNPROC=64000
# locked memory
LimitMEMLOCK=infinity
# total threads (user+kernel)
TasksMax=infinity
TasksAccounting=false
# Recommended limits for mongod as specified in
# https://docs.mongodb.com/manual/reference/ulimit/#recommended-ulimit-settings
[Install]
WantedBy=multi-user.target
启动
systemctl start mongod.service
systemctl enable mongod.service
systemctl status mongod.service
● mongod.service - MongoDB Database Server
Loaded: loaded (/etc/systemd/system/mongod.service; enabled; vendor preset: disabled)
Active: active (running) since Fri 2019-12-06 16:00:48 CST; 4s ago
Docs: https://docs.mongodb.org/manual
Process: 3917 ExecStartPre=/usr/bin/chown mongod:mongod /data -R (code=exited, status=0/SUCCESS)
Main PID: 3919 (mongod)
Memory: 64.1M
CGroup: /system.slice/mongod.service
└─3919 /data/mongodb-linux-x86_64-rhel80-4.2.1/bin/mongod -f /data/etc/mongod.yml
Dec 06 16:00:48 BS-DB-M systemd[1]: Starting MongoDB Database Server...
Dec 06 16:00:48 BS-DB-M systemd[1]: Started MongoDB Database Server.
后置操作
关firewalld开iptables
systemctl disable firewalld.service
dnf install iptables-services
cat > /etc/sysconfig/iptables << EOF
# sample configuration for iptables service
# you can edit this manually or use system-config-firewall
# please do not ask us to add additional ports/services to this default configuration
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 27017 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
EOF
systemctl restart iptables.service
systemctl enable iptables.service
增加根用户
增加根用户前一定要先初始化副本集,否则无法写入
rs.initiate()
use admin
db.createUser(
{
user: "User",
pwd: "Password",
roles: ['root']
})
进而修改配置文件重启到带角色认证的模式(security.authorization改成enabled)
到此处,主节点就成功部署完成了,紧接着是从节点和仲裁节点
副节点(S1)
副节点只需要把配置文件中的身份认证打开即可,其他的复制粘贴即可。但是需要注意的是,同一集群的KeyFile应当相同,因此这个KeyFile要手工同步到各个节点去
待到服务运行后,在主节点里按照如下步骤添加副节点,需要特别注意的是,只有主节点才能添加从(副)节点和仲裁节点。同时,所有节点间必须要使用主机名域名通讯,否则可能会出现无法同步的问题,可以使用类似于如下的脚本给每个节点加上hosts记录就行,需要使用域名直接连接,后续客户端驱动也可以直接使用,如果使用主机名可能会导致客户端驱动连接异常。
紧接着再在主节点添加副节点和仲裁即可
# shell命令
/data/mongodb-linux-x86_64-rhel80-4.2.1/bin/mongo --port 27017 -u <username> -p
# 数据库CLI中执行的命令
rs.status();
rs.add("域名:27017");
rs.addArb("域名:27017");
添加完成后,使用rs.status()即可看到节点的投票情况和当前等级。使用如下命令执行同步即可(主节点执行)
rs.slaveOk()
到这一步,就意味着配置已经完成了,如果没有问题,就可以将日志等级调低了。输出完整的跟踪日志就可以关闭了,在systemLog.traceAllExceptions即可置为false
完工~