原文地址:https://www.douyacun.com/article/b1833461eadfd05dbb32cfbe6f33e0ce
save
rdb出发记录条件
save 900 1
# 服务器在900秒内,修改了1次save 300 10
# 服务器在300秒内,修改了10次save 60 10000
# 服务器在60秒内,修改了10000次save ""
关闭rdb持久化rdbchecksum yes
压缩rdb文件
rdbcompression yes
压缩rdb文件
dbfilename dump.rdb
rdb文件
appendonly yes
启用aof增量持久化
appendfilename "appendonly.aof"
aof文件
appendfsync
fsync
脏页同步策略
always
每次修改everysec
每秒记录一次no
取决于系统no-appendfsync-on-rewrite yes
# 如果是开启状态的,并且有bgsave或bgrewriteaof正在进行的话不调用系统函数fsync()
(同步脏页到磁盘中)
/* Don't fsync if no-appendfsync-on-rewrite is set to yes and there are
* children doing I/O in the background.
*
* 如果 no-appendfsync-on-rewrite 选项为开启状态,
* 并且有 BGSAVE 或者 BGREWRITEAOF 正在进行的话,
* 那么不执行 fsync
*/
if (server.aof_no_fsync_on_rewrite &&
(server.aof_child_pid != -1 || server.rdb_child_pid != -1))
return;
aof重写并不读取分析现有aof文件,是通过读取当前数据库状态来实现,然后用一条命令代替之前记录这个键值对的多条命令,aof重写函数,因为这个函数会进行大量的写入操作,这个线程会被长时间阻塞,no-appendfsync-on-rewrite 是为了避免在此期间与aof重写进程占用文件描述符
aof.c/rewriteAppendOnlyFileBackground
/* This is how rewriting of the append only file in background works:
* 1) The user calls BGREWRITEAOF
* 2) Redis calls this function, that forks():
* 2a) the child rewrite the append only file in a temp file.
* 2b) the parent accumulates differences in server.aof_rewrite_buf.
* 3) When the child finished '2a' exists.
* 4) The parent will trap the exit code, if it's OK, will append the
* data accumulated into server.aof_rewrite_buf into the temp file, and
* finally will rename(2) the temp file in the actual file name.
* The the new file is reopened as the new append only file. Profit!
*/
int rewriteAppendOnlyFileBackground(void) {
pid_t childpid;
long long start;
// 已经有进程在进行 AOF 重写了
if (server.aof_child_pid != -1) return REDIS_ERR;
// 记录 fork 开始前的时间,计算 fork 耗时用
start = ustime();
if ((childpid = fork()) == 0) {
char tmpfile[256];
/* Child */
// 关闭网络连接 fd
closeListeningSockets(0);
// 为进程设置名字,方便记认
redisSetProcTitle("redis-aof-rewrite");
// 创建临时文件,并进行 AOF 重写
snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {
size_t private_dirty = zmalloc_get_private_dirty();
if (private_dirty) {
redisLog(REDIS_NOTICE,
"AOF rewrite: %zu MB of memory used by copy-on-write",
private_dirty/(1024*1024));
}
// 发送重写成功信号
exitFromChild(0);
} else {
// 发送重写失败信号
exitFromChild(1);
}
} else {
/* Parent */
// 记录执行 fork 所消耗的时间
server.stat_fork_time = ustime()-start;
if (childpid == -1) {
redisLog(REDIS_WARNING,
"Can't rewrite append only file in background: fork: %s",
strerror(errno));
return REDIS_ERR;
}
redisLog(REDIS_NOTICE,
"Background append only file rewriting started by pid %d",childpid);
// 记录 AOF 重写的信息
server.aof_rewrite_scheduled = 0;
server.aof_rewrite_time_start = time(NULL);
server.aof_child_pid = childpid;
// 关闭字典自动 rehash
updateDictResizePolicy();
/* We set appendseldb to -1 in order to force the next call to the
* feedAppendOnlyFile() to issue a SELECT command, so the differences
* accumulated by the parent into server.aof_rewrite_buf will start
* with a SELECT statement and it will be safe to merge.
*
* 将 aof_selected_db 设为 -1 ,
* 强制让 feedAppendOnlyFile() 下次执行时引发一个 SELECT 命令,
* 从而确保之后新添加的命令会设置到正确的数据库中
*/
server.aof_selected_db = -1;
replicationScriptCacheFlush();
return REDIS_OK;
}
return REDIS_OK; /* unreached */
}
新功能上线又有点不放心,于是做了个开关放在 Redis,所有应用可以很方便的共享。通过读取 Redis 中的开关 key 来判断是否启用某个功能,对每个请求做判断。这里的问题是什么?
这个key只能放在一个实例上,而所有的流量都要去这个实例去get,导致该分片实例亚历山大,他的极限在我们的实例上不过4w QPS