研发需要,部署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
完工~