MongoDB 事务配置
1. MongoDB 事务
MongoDB 的事务需要在副本集上完成。MongoDB 的事务操作依赖操作日志 oplog。这个日志包含了下面的信息:
- 原子性的记录:事务中的所有写操作会被打包成一个原子性的条目写入 oplog。这意味着,这些操作要么全部被记录,要么一个也不被记录。这保证了事务的原子性。
- 持久性和恢复的保证:oplog 是一个持久化的、有上限的集合。一旦事务被写入 oplog,就可以认为它已经“安全”了。即使数据库在将数据写入实际的数据文件之前崩溃,只要 oplog 中有记录,MongoDB 在恢复后就可以根据 oplog 来完成或重做这个事务,确保数据不会丢失或损坏。
而一个标准的单体 MongoDB 实例,默认情况下不会创建 oplog,因为 oplog 本身是为数据复制服务的。因此如果我们需要在 MongoDB 中使用事务操作、又不需要分片集群这种复杂架构的话,就需要自己给单体 MongoDB 创建对应的副本集,让 MongoDB 认为自己需要进行数据复制、从而创建 oplog。
2. 副本集创建
下面我们以在 docker-compose.yml 中配置 MongoDB 为例。
key-file 生成
在启用了副本集后,如果在 docker-compose 中配置了 username 和 password,需要提供 key-file 来完成认证。我们用 openssl 在容器内生成一个密钥文件然后将密钥文件交给 MongoDB 用户:
openssl rand -base64 756 > /data/mongodb-keyfile
chmod 400 /data/mongodb-keyfile
chown 999:999 /data/mongodb-keyfile
exec docker-entrypoint.sh mongod --replSet rs0 --bind_ip_all --keyFile /data/mongodb-keyfile
副本集生成
rs.initiate({
_id: 'rs0',
members: [{ _id: 0, host: 'localhost:27017' }]
});
完整的 docker-compose.yml 脚本如下,可以直接拿去用:
services:
mongo:
image: mongo:7
container_name: gdrive-mongo
restart: unless-stopped
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME:-admin}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD:-password123}
command: |
bash -c '
openssl rand -base64 756 > /data/mongodb-keyfile
chmod 400 /data/mongodb-keyfile
chown 999:999 /data/mongodb-keyfile
exec docker-entrypoint.sh mongod --replSet rs0 --bind_ip_all --keyFile /data/mongodb-keyfile
'
volumes:
- mongo-data:/data/db
networks:
- gdrive-network
healthcheck:
test: |
mongosh --quiet -u $${MONGO_INITDB_ROOT_USERNAME:-admin} -p $${MONGO_INITDB_ROOT_PASSWORD:-password123} --authenticationDatabase admin --eval "
try {
rs.status();
} catch (err) {
rs.initiate({
_id: 'rs0',
members: [{ _id: 0, host: 'localhost:27017' }]
});
}
"
interval: 5s
timeout: 5s
retries: 5
start_period: 15s