postgresql、redis
一. postgresql架构与原理。
1.1体系架构概览
PostgreSQL和MySQL相似,也采用典型的C/S模型。
PostgreSQL体系结构分两部分
- 实例 instance(内存)
- 磁盘存储
实例 instance 包括
- 进程(客户端的响应进程,服务端的处理进程)
- 内存存储结构
PostgreSQL是进程架构模型,MySQL是线程架构模型
1.2 进程
- Postmaster 主进程
- 它是整个数据库实例的主控制进程,负责启动和关闭该数据库实例。
- 实际上,使用pg ctl来启动数据库时,pg_ctl也是通过运行postgres来启动数据库的,只是它做了一些包装,更容易启动数据库。
- 它是第一个PostgreSQL进程,此主进程还会fork出其他子进程,并管理它们。
- 当用户和PostgreSQL建立连接时,首先是和Postmaster进程建立连接。首先,客户端会发出身份验证的信息给Postmaster进程,Postmaster进程根据消息中的信息进行身份验证判断,
如果验证通过,它会fork出一个会话子进程为这个连接服务。 - 当某个服务进程出现错误的时候,Postmaster主进程会自动完成系统的恢复。恢复过程中会停掉所有的服务进程,然后进行数据库数据的一致性恢复,等恢复完成后,数据库又可以接受新的连接。
- 验证功能是通过配置文件pg_hba.conf和用户验证模块来提供。
- postmaster 程序是指向postgres的软链接
[root@ubuntu2004 ~]#ll /apps/pgsql/bin/postmaster
lrwxrwxrwx 1 root root 8 Dec 28 01:19 /apps/pgsql/bin/postmaster ->
postgres*
- BgWriter 后台写进程
- 为了提高插入、删除和更新数据的性能,当往数据库中插入或者更新数据时,并不会马上把数据持久化到数据文件中,而是先写入Buffer中
- 该辅助进程可以周期性的把内存中的脏数据刷新到磁盘中
- WalWriter 预写式日志进程(类似于mysql的事务日志)有了日志优点安全、速度快,缺点磁盘空间大、IO多一次—日志追加写入比直接随机写入数据库快
- WAL是write ahead log的缩写,WAL log旧版中称为xlog,相当于MySQL中Redo log
- 预写式日志是在修改数据之前,必须把这些修改操作记录到磁盘中,这样后面更新实际数据时,就不需要实时的把数据持久化到文件中了。即使机器突然宕机或者数据库异常退出,
导致一部分内存中的脏数据没有及时的刷新到文件中,在数据库重启后,通过读取WAL日志,并把最后一部分WAL日志重新执行一遍,就能恢复到宕机时的状态了 - WAL日志保存在pg_wal目录(早期版本为pg_xlog) 下。每个xlog文件默认是16MB,为了满足恢复要求,在pg_wal目录下会产生多个WAL日志,这样就可保证在宕机后,未持久化的数据都可以通过WAL日志来恢复,那些不需要的WAL日志将会被自动覆盖
- Checkpointer 检查点进程(数据写入到磁盘)
- 检查点(Checkpoints)是事务序列中的点,保证在该点之前的所有日志信息都更新到数据文件中。
- 在检查点时,所有脏数据页都冲刷到磁盘并且向日志文件中写入一条特殊的检查点记录。在发生崩溃的时候,恢复器就知道应该从日志中的哪个点(称做
redo 记录)开始做 REDO
操作,因为在该记录前的对数据文件的任何修改都已经在磁盘上了。在完成检查点处理之后,任何在redo记录之前写的日志段都不再需要,因此可以循环使用或者删除。在进行
WAL 归档的时候,这些日志在循环利用或者删除之前应该必须先归档保存检查点(CKPT)
在特定时间自动执行一个检查点,通过向数据库写入进(BgWriter) 传递消息来启动检查点请求
- AutoVacuum 自动清理进程
- 执行delete操作时,旧的数据并不会立即被删除,在更新数据时,也不会在旧的数据上做更新,而是新生成一行数据。旧的数据只是被标识为删除状态,在没有并发的其他事务读到这些
旧数据时,它们才会被清除掉autovacuum lanucher
负责回收垃圾数据的master进程,如果开启了autovacuum的话,那postmaster会fork这个进程 - autovacuum worker 负责回收垃圾数据的worker进程,是lanucher进程fork出来的
- 执行delete操作时,旧的数据并不会立即被删除,在更新数据时,也不会在旧的数据上做更新,而是新生成一行数据。旧的数据只是被标识为删除状态,在没有并发的其他事务读到这些
- PgStat 统计数据收集进程
- 此进程主要做数据的统计收集工作
- 收集的信息主要用于查询优化时的代价估算。统计的数据包括对一个表或索引进行的插入、删除、更新操作,磁盘块读写的次数以及行的读次数等。
- 系统表pg_statistic中存储了PgStat收集的各类统计信息
- PgArch 归档进程
- 默认没有此进程,开启归档功能后才会启动archiver进程
- WAL日志文件会被循环使用,也就是说WAL日志会被覆盖,利用PgArch进程会在覆盖前把WAL日志备份出来,类似于binlog,可用于备份功能
- PostgreSQL 从8.X版本开始提供了PITR ( Point-In-Time-Recovery)技术,即就是在对数据厍进行过一次全量备份后,该技术将备份时间点后面的WAL日志通过归档进行备份,将来可以 使用数据库的全量备份再加上后面产生的WAL 日志,即可把数据库向前恢复到全量备份后的任意一个时间点的状态
- SysLogger 系统日志进程
- 默认没有此进程,配置文件 postgresql.conf
设置参数logging_collect设置为“on”时,主进程才会启动SysLogger辅助进程- 它从Postmaster主进程、所有的服务进程以及其他辅助进程收集所有的stderr输出,并将这些输出写入到日志文件中
- startup 启动进程
- 用于数据库恢复的进程
- Session 会话进程
- 每一个用户发起连接后,一旦验证成功,postmaster进程就会fork—个新的子进程负责连接此用户。
- 通常表现为进程形式: postgres postgres [local] idle
案例: 查看进程
1.2 内存结构
PostgreSQL的内存空间包括共享内存和本地内存两部分
- 共享内存
- PostgreSQL启动后,会生成一块共享内存,共享内存主要用做数据块的缓冲区,以便提高读写性能。WAL日志缓冲区和CLOG(Commit log)缓冲区也存在于共享内存中。除此以外,一些全局信息也保存在共享内存中,如进程信息、锁的信息、全局统计信息等。
- PostgreSQL 9.3之前的版本与Oracle数据库一样,都是使用“SystemV”类型的共享内存,但到PostgreSQL9.3之后,PostgreSQL使用mmap()方式共享内存,好处能使用较大的共享内 存。
- 可以通过配置postgresql.conf文件中shared_buffers 指定,默认128M,建议是内存的50%
本地内存
后台服务进程除访问共享内存外,还会申请分配一些本地内存,以便暂存一些不需要全局存储的数
据。
都可以通过在配置postgresql.conf文件中指定
这些内存缓冲区主要有以下几类: - temp_buffers :用于访问临时表的本地缓冲区,默认为8M
- work_mem:内部排序操作和Hash表在使用临时磁盘文件之前使用的内存缓冲区,默认为4M
- maintenance_work_mem:在维护性操作(比如 VACUUM、CREATE INDEX和ALTERTABLE
- ADDFOREIGN KEY 等)中使用的内存缓冲区,默认为64M
范例:查看内存空间
postgres=# show shared_buffers;
shared_buffers
----------------
128MB
(1 row)
postgres=# show maintenance_work_mem;
maintenance_work_mem
----------------------
64MB
(1 row)
postgres=# show work_mem;
work_mem
----------
4MB
(1 row)
1.3 数据更新过程
-
先将数据库文件中的更改的数据加载至内存
-
在内存更新数据
-
将日志写入内存WAL的缓存区
-
将日志提交,将日志写入操作系统 cache
-
同步日志到磁盘
-
后台写数据库的更新后的数据到操作系统 cache
-
写完数据后,更新检查点checkpoint
-
同步数据到磁盘
二. 基于流复制完成postgresql的高可用。
2.1 基础环境准备
两个主机节点
10.0.0.101 Master
10.0.0.102 Standby
2.2 Master 节点配置
#创建复制的用户并授权
[postgres@master ~]$ psql
postgres=#create role repluser with replication login password '123456';
#修改pg_hba.conf进行授权
[postgres@master ~]$vi /pgsql/data/pg_hba.conf
host replication repluser 0.0.0.0/0 md5
#修改配置(可选):
[postgres@master ~]$vi /pgsql/data/postgresql.conf
synchronous_standby_names = '*' #开启此项,表示同步方式,需要同时打开synchronous_commit
= on,此为默认值,默认是异步方式
synchronous_commit = on #开启同步模式
archive_mode = on #建议打开归档模式,防止长时间无法同步,WAL被覆盖造成数据丢失
archive_command = '[ ! -f /archive/%f ] && cp %p /archive/%f'
wa1_level = replica #设置wal的级别
max_wal_senders = 5 #这个设置可以最多有几个流复制连接,一般有几个从节点就设置几个
wal_keep_segments = 128 #设置流复制保留的最多的WAL文件数目
wal_sender_timeout = 60s #设置流复制主机发送数据的超时时间
max_connections = 200 # 一般查多于写的应用从库的最大连接数要比较大
hot_standby = on #对主库无影响,用于将来可能会成为从库,这台机器不仅仅是用于数据归档,也用于数
据查询,在从库上配置此项后为只读
max_standby_streaming_delay = 30s #数据流备份的最大延迟时间
wal_receiver_status_interval = 10s #多久向主报告一次从的状态,当然从每次数据复制都会向主报
告状态,只是设置最长的间隔时间
hot_standby_feedback = on #如果有错误的数据复制,是否向主进行反馈
wal_log_hints = on #对非关键更新进行整页写入
[postgres@master ~]$pg_ctl restart -D /pgsql/data
2.3 Standby 节点配置
#清空数据和归档
[postgres@standby ~]$ pg_ctl stop -D $PGDATA
[postgres@standby ~]$ rm -rf /pgsql/data/*
[postgres@standby ~]$ rm -rf /archive/*
[postgres@standby ~]$ rm -rf /pgsql/backup/*
#备份主库数据到备库
[postgres@standby ~]$ pg_basebackup -D /pgsql/backup/ -Ft -Pv -Urepluser -h
10.0.0.101 -p 5432 -R
#还原备份的数据,实现初始的主从数据同步
[postgres@standby ~]$ tar xf /pgsql/backup/base.tar -C /pgsql/data
[postgres@standby ~]$ tar xf /pgsql/backup/pg_wal.tar -C /archive/
#方法1
#修改postgresql.conf文件
[postgres@standby ~]$ vi /pgsql/data/postgresql.conf
#添加下面两行
primary_conninfo = 'host=10.0.0.101 port=5432 user=repluser password=123456'
restore_command = 'cp /archive/%f %p' #此项可不配置
#修改配置(可选):
hot_standby = on #开启此项,此是默认项
recovery_target_timeline = latest # 默认
max_connections = 120 # 大于等于主节点,正式环境应当重新考虑此值的大小
max_standby_streaming_delay = 30s
wal_receiver_status_interval = 10
shot_standby_feedback = on
max_wal_senders = 15
1ogging_co1lector = on
1og_directory = 'pg_log'
1og_filename = 'postgresql-%Y-%m-%d_%H%M%S.1og'
#方法2
#修改postgresql.auto.conf
[postgres@standby ~]$ vi /pgsql/data/postgresql.auto.conf
primary_conninfo = 'host=10.0.0.101 port=54321 user=repluser password=123456
sslmode=disable sslcompression=0 gssencmode=disable
krbsrvname=post_session_attrs=any' #此行自动生成,只修改用户名即可
restore_command = 'cp /archive/%f %p'
[postgres@standby ~]$ pg_ctl -D /pgsql/data start
2.4 监控同步状态
2.4.1 在主库查看状态
[root@master ~]#pg_controldata
pg_control version number: 1201
Catalog version number: 201909212
Database system identifier: 7051752604814091288
Database cluster state: in production #主库状态
......
postgres=#select pid,state,client_addr,sync_priority,sync_state from
pg_stat_replication;
pid | state | client_addr | sync_priority | sync_state
-------+-----------+-------------+---------------+------------
21373 | streaming | 10.0.0.102 | 0 | async
(1 row)
#下面只在主节点查看同步模式,注意:如果无从节点连接,将无任何显示信息
postgres=# SELECT pg_current_wal_insert_lsn(),* from pg_stat_replication;
-[ RECORD 1 ]-------------+------------------------------
pg_current_wal_insert_lsn | 0/5B002988 #当前lsn号
pid | 33479
usesysid | 16452
usename | repluser
application_name | walreceiver
client_addr | 10.0.0.8
client_hostname |
client_port | 56742
backend_start | 2020-05-18 11:50:21.970079+00
backend_xmin |
state | streaming
sent_lsn | 0/5B002988
write_lsn | 0/5B002988 #同步的lsn号,和上面一致,说明同步,有差表示有同步
延迟
flush_lsn | 0/5B002988
replay_lsn | 0/5B002988
write_lag |
flush_lag |
replay_lag |
sync_priority | 1
sync_state | async #当前是异步,同步显示为sync
reply_time | 2020-05-18 12:00:20.851292+00
#服务器查看数据库是否为备库,f表主库 t表示为备库
postgres=# select * from pg_is_in_recovery();
-[ RECORD 1 ]-----+--
pg_is_in_recovery | f
postgres=# select application_name,client_addr,sync_state from
pg_stat_replication;
application_name | client_addr | sync_state
------------------+-------------+------------
walreceiver | 10.0.0.200 | async
(1 row)
[root@master ~]#ps aux |grep walsender
postgres 1263 0.0 0.8 159672 17656 ? Ss 08:46 0:00
/apps/pgsql/bin/postgres -D /pgsql/data
postgres 1267 0.0 2.8 159804 56752 ? Ss 08:46 0:00 postgres:
checkpointer
postgres 1268 0.0 0.1 159672 2472 ? Ss 08:46 0:00 postgres:
background writer
postgres 1269 0.0 0.3 159672 7144 ? Ss 08:46 0:00 postgres:
walwriter
postgres 1270 0.0 0.2 160340 5124 ? Ss 08:46 0:00 postgres:
autovacuum launcher
postgres 1271 0.0 0.1 14084 3108 ? Ss 08:46 0:00 postgres:
archiver last was 00000001000000000000004E
postgres 1272 0.0 0.0 14224 1852 ? Ss 08:46 0:00 postgres:
stats collector
postgres 1273 0.0 0.1 160100 3204 ? Ss 08:46 0:00 postgres:
logical replication launcher
postgres 1295 0.0 0.3 160748 6448 ? Ss 08:47 0:00 postgres:
walsender repluser 10.0.0.8(39850) streaming 0/4F912580 #发送WAL日志进程
2.4.2 在从库查看状态
#从节点可以读
hellodb=# select * from teachers;
tid | name | age | gender
-----+---------------+-----+--------
1 | Song Jiang | 45 | M
2 | Zhang Sanfeng | 94 | M
3 | Miejue Shitai | 77 | F
4 | Lin Chaoying | 93 | F
(4 rows)
#从节点不支持写
hellodb=# delete from teachers where tid=4;
ERROR: cannot execute DELETE in a read-only transaction
[postgres@slave ~]$pg_controldata
pg_control version number: 1201
Catalog version number: 201909212
Database system identifier: 7051752604814091288
Database cluster state: in archive recovery #备库状态
.....
postgres=# select * from pg_is_in_recovery();
-[ RECORD 1 ]-----+--
pg_is_in_recovery | t
postgres=# \x
Expanded display is on.
postgres=# SELECT * FROM pg_stat_wal_receiver;
-[ RECORD 1 ]---------+---------------------------------------------------------
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
-----------------------------------------------------------
pid | 6341
status | streaming
receive_start_lsn | 0/75000000
receive_start_tli | 1
written_lsn | 0/7E9DA9E8
flushed_lsn | 0/7E9DA9E8
received_tli | 1
last_msg_send_time | 2022-02-16 18:06:01.970639+08
last_msg_receipt_time | 2022-02-16 18:06:01.958855+08
latest_end_lsn | 0/7E9DA9E8
latest_end_time | 2022-02-16 18:02:01.693206+08
slot_name |
sender_host | 10.0.0.101
sender_port | 5432
conninfo | user=repluser password=******** channel_binding=disable
dbname=replication host=10.0.0.200 port=5432
fallback_application_name=walreceiver sslmode=disable sslcompression=0 sslsni=1
ssl_min_protocol_version=TLSv1.2 gssencmode=disable krbsrvname=postgres
target_session_attrs=any
#查看进程
[root@standby ~]#ps aux|grep postgres
postgres 1222 0.0 0.8 172536 17252 ? Ss 08:47 0:00
/apps/pgsql/bin/postgres -D /pgsql/data
postgres 1223 0.0 2.8 172668 57916 ? Ss 08:47 0:01 postgres:
startup recovering 00000001000000000000004F #恢复进程
postgres 1224 0.0 2.8 172676 56844 ? Ss 08:47 0:00 postgres:
checkpointer
postgres 1225 0.0 0.1 172536 2768 ? Ss 08:47 0:00 postgres:
background writer
postgres 1226 0.0 0.1 27080 2320 ? Ss 08:47 0:00 postgres:
stats collector
postgres 1227 0.0 0.2 177376 5652 ? Ss 08:47 0:06 postgres:
walreceiver streaming 0/4F912580 #接收WAL日志进程
2.4 切换主从
2.4.1 将从库切换为主库
[postgres@slave ~]$pg_ctl promote
waiting for server to promote.... done
server promoted
[postgres@slave ~]$pg_controldata
pg_control version number: 1201
Catalog version number: 201909212
Database system identifier: 7051752604814091288
Database cluster state: in production
[postgres@rocky8 ~]$pg_ctl restart
#恢复正常模式()
postgres=# select pg_wal_replay_resume();
2.4.2 原主库切换为从库
#在原主库修复故障后,在主库服务器重复上面Standby节点的6.2.3的步骤
#在原主库服务器创建standby.signal文件
[postgres@master ~]$touch $PGDATA/standby.signal
#在原主库服务器启动服务
[postgres@master ~]$pg_ctl -D /pgsql/data restart
#在原主库服务器查看状态
[postgres@master ~]$/pgsql/data$ pg_controldata
pg_control version number: 1201
Catalog version number: 201909212
Database system identifier: 7051752604814091288
Database cluster state: in archive recovery
pg_control last modified: Thu Jan 20 10:23:03 2022
Latest checkpoint location: 0/5E000060
hellodb=# select * from pg_is_in_recovery();
pg_is_in_recovery
-------------------
t
(1 row)
三. 实现postgresql的时间点还原。
3.1 利用PITR实现误删除的实战案例
场景说明
每天2:00备份,第二天10:00误删除数据库,如何恢复?
故障恢复过程
备份数据和归档
还原流程
- 还原完全备份
- 归档日志恢复:
- 备份中的归档
- 恢复2:00到10:00之间的归档
- 恢复在线redo
3.1.1 备份(备份时停止业务,不能错上加错)
#在PG服务器开启归档
[postgres@pgserver ~]$ vim /pgsql/data/postgresql.conf
archive_mode = on
archive_command = 'test ! -f /archive/%f &&cp %p /archive/%f'
[postgres@gpserver ~]$pg_ctl restart -D $PGDATA
#在PG服务器上创建测试数据
postgres=#create database testdb;
postgres=#\c testdb
testdb=# create table t1(id int);
testdb=# insert into t1 values(1);
#在备份服务器对PG数据库进行远程完全备份
[postgres@backup ~]$pg_basebackup -D /pgsql/backup/ -Ft -Pv -Upostgres -h
10.0.0.200 -p 5432 -R
#在PG服务器上继续生成测试数据
testdb=# insert into t1 values(2);
#模拟数据库删除
postgres=# drop database testdb;
#发现故障,停止用户访问
#查看当前日志文件
postgres=# select pg_walfile_name(pg_current_wal_lsn());
-[ RECORD 1 ]---+-------------------------
pg_walfile_name | 000000020000000000000020
#查看当前事务ID
postgres=# select txid_current();
txid_current
--------------
521
(1 row)
3.1.2 故障还原
#在PG服务器上切换归档日志(好处是以后这个文件不再使用)
postgres=#select pg_switch_wal();
#在要还原的服务器停止服务,准备还原
[postgres@pgserver ~]$pg_ctl stop -D $PGDATA
[postgres@pgserver ~]$rm -rf /pgsql/data/*
#在测试的还原服务器进行还原
[postgres@backup ~]$tar xf /pgsql/backup/base.tar -C /pgsql/data/
#此步可以不执行
[postgres@backup ~]$tar xf /pgsql/backup/pg_wal.tar -C /archive/
#复制PG服务器的归档日志到还原的测试服务器
[postgres@pgserver ~]$rsync -a 10.0.0.200:/archive/ /archive/
#查看故障点事务ID
[postgres@backup ~]$pg_waldump /archive/000000020000000000000020 |grep -B 10
"DROP dir"
rmgr: Database len (rec/tot): 34/ 34, tx: 521, lsn: 0/3D000828,
prev 0/3D0007B0, desc: DROP dir 1663/16445
#查看此指令的事务ID为521,前一个事务为520
#修改配置文件postgresql.conf,或者postgresql.auto.conf文件也可以
[postgres@backup ~]$vi /pgsql/data/postgresql.conf
#加下面两行
restore_command = 'cp /archive/%f %p'
#指定还原至上面查到的事务ID
recovery_target_xid = '520'
#也可以通过下面方式指定还原至的位置
recovery_target_name = 'restore_point' #指定还原点名称
recovery_target_time = '2021-01-17 16:26:12' #指定还原至时间点
recovery_target_lsn = '0/3E000148' #指定还原到LSN号的位置
#启动服务
[postgres@backup ~]$pg_ctl start -D $PGDATA
#验证数据
[postgres@backup ~]$psql
psql (12.9)
Type "help" for help.
postgres=# \c testdb
You are now connected to database "testdb" as user "postgres".
testdb=# select * from t1;
id
----
1
2
(2 rows)
#验证数据是否还原,恢复后读取正常
testdb=# select * from t1;
id
----
1
2
3
(3 rows)
#当前无法写入
testdb=# insert into t1 values(4);
ERROR: cannot execute INSERT in a read-only transaction
[postgres@pgserver ~]$pg_controldata
pg_control version number: 1300
Catalog version number: 202107181
Database system identifier: 7064396403376562327
Database cluster state: in archive recovery
#恢复正常模式
postgres=# select pg_wal_replay_resume();
[postgres@pgserver ~]$pg_controldata
pg_control version number: 1300
Catalog version number: 202107181
Database system identifier: 7064396403376562327
Database cluster state: in production
#恢复正常写入
testdb=# insert into t1 values(4);
四. 规划高可用的LAMP,要求wordpress网站放在NFS共享存储上,并且用户可以正常发布博客,上传图片。尝试更新wordpress版本,测试网站仍可用。
4.1实战案例
4.1.1 环境准备
共四台主机
一台主机 nfs server
IP:10.0.0.8
一台主机备份 nfs server
IP:10.0.0.9
另两台当 nfs client
IP:10.0.0.7
IP:10.0.0.6
4.1.2 步骤
#NFS服务器创建用户和相应的家目录,将用户wang的家目录共享
[root@centos8 ~]#yum -y install nfs-utils
[root@centos8 ~]#systemctl enable --now nfs-server
[root@centos8 ~]#mkdir -pv /data/home
[root@centos8 ~]#useradd -d /data/home/wang -u 2000 wang
[root@centos8 ~]#Vim /etc/exports.d/test.exports
/data/home *(rw)
[root@centos8 ~]#exportfs -r
#在第一台NFS客户端主机10.0.0.7上实现
[root@centos7 ~]#yum -y install nfs-utils
[root@centos7 ~]#useradd -u 2000 wang
[root@centos7 ~]#vim /etc/fstab
10.0.0.8:/data/home/wang /home/wang nfs _netdev 0 0
[root@centos7 ~]#mount -a
[root@centos7 ~]#su - wang
Last login: Fri Jul 3 16:33:34 CST 2020 on pts/0
[wang@centos7 ~]$pwd
/home/wang
[wang@centos7 ~]$df /home/wang -T
Filesystem Type 1K-blocks Used Available Use% Mounted on
10.0.0.8:/data/home/wang nfs4 52403200 398464 52004736 1% /home/wang
#在第二台NFS客户端主机10.0.0.6上实现
[root@centos6 ~]#yum -y install nfs-utils
[root@centos6 ~]#useradd -u 2000 wang
[root@centos6 ~]#vim /etc/fstab
10.0.0.8:/data/home/wang /home/wang nfs _netdev 0 0
[root@centos6 ~]#su - wang
[wang@centos6 ~]$pwd
/home/wang
[wang@centos6 ~]$df -T /home/wang
Filesystem Type 1K-blocks Used Available Use% Mounted on
10.0.0.8:/data/home/wang nfs 52403200 398464 52004736 1% /home/wang
基于rsync daemon 实现 sersync
#在数据服务器上下载sersync,并拷贝至相应的目录,设置PATH变量
[root@data-centos8 ~]#wget https://storage.googleapis.com/google-code-archive-
downloads/v2/code.google.com/sersync/sersync2.5.4_64bit_binary_stable_final.tar.
gz
[root@data-centos8 ~]#tar xf sersync2.5.4_64bit_binary_stable_final.tar.gz
[root@data-centos8 ~]#cp -a GNU-Linux-x86 /usr/local/sersync
[root@data-centos8 ~]#echo 'PATH=/usr/local/sersync:$PATH' >
/etc/profile.d/sersync.sh
[root@data-centos8 ~]#source /etc/profile.d/sersync.sh
#sersync目录只有两个文件:一个是二进制程序文件,一个是xml格式的配置文件
[root@data-centos8 ~]#ls /usr/local/sersync/
confxml.xml sersync2
#确认安装rsync客户端工具
[root@data-centos8 ~]#rpm -q rsync &> /dev/null || dnf -y install rsync
#备份sersync配置文件
[root@data-centos8 ~]#cp /usr/local/sersync/confxml.xml{,.bak}
#修改sersync配置文件
[root@data-centos8 ~]#vim /usr/local/sersync/confxml.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<head version="2.5">
<host hostip="localhost" port="8008"></host>
<debug start="false"/> # 是否开启调试模式
<fileSystem xfs="false"/>
<filter start="false"> #不开启文件过滤功能,当为true时,以下类型的文件将不同
步
<exclude expression="(.*)\.svn"></exclude>
<exclude expression="(.*)\.gz"></exclude>
<exclude expression="^info/*"></exclude>
<exclude expression="^static/*"></exclude>
</filter>
<inotify> # 监控事件,默认监控
delete/close_write/moved_from/moved_to/create folder
<delete start="true"/>
<createFolder start="true"/>
<createFile start="false"/>
<closeWrite start="true"/>
<moveFrom start="true"/>
<moveTo start="true"/>
<attrib start="true"/> #修改此行为true,文件属性变化后也会同步
<modify start="false"/>
</inotify>
<sersync> # rsync命令的配置段
<localpath watch="/data/www"> #修改此行,需要同步的源目录或文件,建议同步目
录
<remote ip="备份服务器IP" name="backup"/> #修改此行,指定备份服务器地址和rsync
daemon的模块名,如果下面开启了ssh start,此时name为远程shell方式运行时的目标目录
<!--<remote ip="192.168.8.39" name="tongbu"/>-->
<!--<remote ip="192.168.8.40" name="tongbu"/>-->
</localpath>
<rsync>
<commonParams params="-artuz"/> # 指定rsync选项
<auth start="true" users="rsyncuser" passwordfile="/etc/rsync.pas"/> #修
改此行为true,指定备份服务器的rsync配置的用户和密码文件
<userDefinedPort start="false" port="874"/><!-- port=874 -->#指定rsync的非
标准端口号
<timeout start="false" time="100"/><!-- timeout=100 -->
<ssh start="false"/> #默认使用rsync daemon运行rsync命令,true为使用远程shell模
式
</rsync>
<failLog path="/tmp/rsync_fail_log.sh" timeToExecute="60"/><!--default every
60mins execute once--> #错误重传及日志文件路径
<crontab start="false" schedule="600"><!--600mins--> #不开启crontab功能
<crontabfilter start="false"> #不开启crontab定时传输的筛选功能
<exclude expression="*.php"></exclude>
<exclude expression="info/*"></exclude>
</crontabfilter>
</crontab>
<plugin start="false" name="command"/>
</sersync>
#####################################以下行不需要修改
####################################
<plugin name="command">
<param prefix="/bin/sh" suffix="" ignoreError="true"/> <!--prefix
/opt/tongbu/mmm.sh suffix-->
<filter start="false">
<include expression="(.*)\.php"/>
<include expression="(.*)\.sh"/>
</filter>
</plugin>
<plugin name="socket">
<localpath watch="/opt/tongbu">
<deshost ip="192.168.138.20" port="8009"/>
</localpath>
</plugin>
<plugin name="refreshCDN">
<localpath watch="/data0/htdocs/cms.xoyo.com/site/">
<cdninfo domainname="ccms.chinacache.com" port="80" username="xxxx"
passwd="xxxx"/>
<sendurl base="http://pic.xoyo.com/cms"/>
<regexurl regex="false" match="cms.xoyo.com/site([/a-zA-Z0-
9]*).xoyo.com/images"/>
</localpath>
</plugin>
</head>
#创建连接rsynd服务器的用户密码文件,并必须修改权限
[root@data-centos8 ~]#echo magedu > /etc/rsync.pas
[root@data-centos8 ~]#chmod 600 /etc/rsync.pas
#查看帮助
[root@data-centos8 ~]#sersync2 -h
set the system param
execute:echo 50000000 > /proc/sys/fs/inotify/max_user_watches
execute:echo 327679 > /proc/sys/fs/inotify/max_queued_events
parse the command param
_______________________________________________________
参数-d:启用守护进程模式
参数-r:在监控前,将监控目录与远程主机用rsync命令推送一遍
c参数-n: 指定开启守护线程的数量,默认为10个
参数-o:指定配置文件,默认使用当前工作目录下的confxml.xml文件
参数-m:单独启用其他模块,使用 -m refreshCDN 开启刷新CDN模块
参数-m:单独启用其他模块,使用 -m socket 开启socket模块
参数-m:单独启用其他模块,使用 -m http 开启http模块
不加-m参数,则默认执行同步程序
#以后台方式执行同步
[root@data-centos8 ~]#sersync2 -dro /usr/local/sersync/confxml.xml
set the system param
execute:echo 50000000 > /proc/sys/fs/inotify/max_user_watches
execute:echo 327679 > /proc/sys/fs/inotify/max_queued_events
parse the command param
option: -d run as a daemon
option: -r rsync all the local files to the remote servers before the sersync
work
option: -o config xml name: /usr/local/sersync/confxml.xml
daemon thread num: 10
parse xml config file
host ip : localhost host port: 8008
daemon start,sersync run behind the console
use rsync password-file :
user is rsyncuser
passwordfile is /etc/rsync.pas
config xml parse success
please set /etc/rsyncd.conf max connections=0 Manually
sersync working thread 12 = 1(primary thread) + 1(fail retry thread) +
10(daemon sub threads)
Max threads numbers is: 22 = 12(Thread pool nums) + 10(Sub threads)
please according your cpu ,use -n param to adjust the cpu rate
------------------------------------------
rsync the directory recursivly to the remote servers once
working please wait...
#如果同步失败,可以手动执行下面命令,观察过程
[root@data-centos8 ~]# cd /data/www && rsync -artuz -R --delete ./
rsyncuser@backup-server::backup --password-file=/etc/rsync.pas >/dev/null 2>&1
run the sersync:
watch path is: /data/www
#sersync支持多实例,也即监控多个目录时,只需分别配置不同配置文件,然后使用sersync2指定对应配置
文件运行
[root@data-centos8 ~]#sersync2 -rd -o /etc/sersync.d/nginx.xml
五. redis数据类型有哪些?
参考资料:http://www.redis.cn/topics/data-types.html
相关命令参考: http://redisdoc.com/
5.1 字符串 string
字符串是一种最基本的Redis值类型。Redis字符串是二进制安全的,这意味着一个Redis字符串能包含任意类型的数据,例如: 一张JPEG格式的图片或者一个序列化的Ruby对象。一个字符串类型的值最多能存储512M字节的内容。Redis 中所有 key 都是字符串类型的。此数据类型最为常用
数字递增
利用INCR命令簇(INCR, DECR, INCRBY,DECRBY)来把字符串当作原子计数器使用。
博客点赞、评论用此方法比较简便,像mysql需要update
5.2 列表 list
5.3 集合 set**
集合特点
- 无序
- 无重复
- 集合间操作
交集
- 可以实现共同的朋友
差集 - 可以实现我的朋友的朋友
并集
5.4 有序集合 sorted set
Redis有序集合和Redis集合类似,是不包含相同字符串的合集。它们的差别是,每个有序集合的成员都关联着一个双精度浮点型的评分,这个评分用于把有序集合中的成员按最低分到最高分排序。有序集合的成员不能重复,但评分可以重复,一个有序集合中最多的成员数为 2^32 - 1=4294967295个,经常用于排行榜的场景
- 有序集合特点
- 有序
- 无重复元素
- 每个元素是由score和value组成
- score 可以重复
- value 不可以重复
5.5 哈希 hash
hash 即字典, 用于保存字符串字段field和字符串值value之间的映射,即key/value做为数据部分,hash特别适合用于存储对象场景.
一个hash最多可以包含2^32-1 个key/value键值对
哈希特点
- 无序
- k/v 对
- 适用于存放相关的数据
5.6 消息队列
消息队列: 把要传输的数据放在队列中,从而实现应用之间的数据交换
常用功能: 可以实现多个应用系统之间的解耦,异步,削峰/限流等
常用的消息队列应用: Kafka,RabbitMQ,Redis
消息队列分为两种
- 生产者/消费者模式: Producer/Consumer
[root@redis ~]# redis-cli
127.0.0.1:6379> AUTH 123456
OK
127.0.0.1:6379> LPUSH channel1 message1 #从管道的左侧写入
(integer) 1
127.0.0.1:6379> LPUSH channel1 message2
(integer) 2
127.0.0.1:6379> LPUSH channel1 message3
(integer) 3
127.0.0.1:6379> LPUSH channel1 message4
(integer) 4
127.0.0.1:6379> LPUSH channel1 message5
(integer) 5
#获取所有消息
127.0.0.1:6379> LRANGE channel1 0 -1
1) "message5"
2) "message4"
3) "message3"
4) "message2"
5) "message1"
#消费者消费消息
127.0.0.1:6379> RPOP channel1 #基于实现消息队列的先进先出原则,从管道的右侧消费
"message1"
127.0.0.1:6379> RPOP channel1
"message2"
127.0.0.1:6379> RPOP channel1
"message3"
127.0.0.1:6379> RPOP channel1
"message4"
127.0.0.1:6379> RPOP channel1
"message5"
127.0.0.1:6379> RPOP channel1
(nil)
- 发布者/订阅者模式: Publisher/Subscriber
#订阅者订阅频道
[root@redis ~]# redis-cli
127.0.0.1:6379> AUTH 123456
OK
127.0.0.1:6379> SUBSCRIBE channel01 #订阅者事先订阅指定的频道,之后发布的消
息才能收到
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel01"
3) (integer) 1
#发布者发布消息
127.0.0.1:6379> PUBLISH channel01 message1 #发布者发布信息到指定频道
(integer) 2 #订阅者个数
127.0.0.1:6379> PUBLISH channel01 message2
(integer) 2
#各个订阅者都能收到消息
[root@redis ~]#redis-cli
127.0.0.1:6379> AUTH 123456
OK
127.0.0.1:6379> SUBSCRIBE channel01
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel01"
3) (integer) 1
1) "message"
2) "channel01"
3) "message1"
1) "message"
2) "channel01"
3) "message2"
#订阅多个频道
127.0.0.1:6379> SUBSCRIBE channel01 channel02
#订阅所有频道
127.0.0.1:6379> PSUBSCRIBE * #支持通配符*
#订阅匹配的频道
127.0.0.1:6379> PSUBSCRIBE chann* #匹配订阅多个频道
#取消订阅频道
127.0.0.1:6379> unsubscribe channel01
1) "unsubscribe"
2) "channel01"
3) (integer) 0
六. redis RDB和AOF比较?
如果主要充当缓存功能,或者可以承受较长时间,比如数分钟数据的丢失, 通常生产环境一般只需启用RDB即可,此也是默认值
如果一点数据都不能丢失,可以选择同时开启RDB和AOF一般不建议只开启AOF
七. redis配置文件详解。
- Units
- Network 网络相关
- GENERAL 通用配置
- SNAPSHOTTING 快照相关
- SECURITY 安全相关
- CLIENTS 客户端配置
- MEMORY MANAGEMENT 内存管理
- LAZY FREEING 懒惰删除
- THREADED I/O
- KERNEL OOM CONTROL 设置OOM时终止哪些进程
- APPEND ONLY MODE AOF持久化配置
- LUA SCRIPTING-LUA脚本相关
- REDIS CLUSTER 集群配置
- CLUSTER DOCKER/NAT support
- SLOW LOG 慢日志
- LATENCY MONITOR 延迟监控
- EVENT NOTIFICATION 事件通知
- GOPHER SERVER Gopher协议
- ADVANCED CONFIG 高级设置
- ACTIVE DEFRAGMENTATION 碎片整理
Units
- 配置数据单位换算关系
################## 该部分用于指定存储单位的大小换算关系,不区分大小写,只支持bytes,不支持bits
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.
- 包含其它配置文件的信息 include path
对于公共部分配置,可以按以下方式配置引入
# include /path/to/local.conf
# include /path/to/other.conf
Network 网络相关
- bind IP1 [IP2 …]
这项配置绑定的IP并不是远程访问的客户端的IP地址,而是本机的IP地址。
(主要bind只能有一行配置,如果有多个网卡要监听,就配置多个ip,用空格隔开,否者只有配置的最后一个bind生效)
# bind 192.168.1.100 10.0.0.1
# bind 127.0.0.1 ::1
bind 127.0.0.1
- 保护模式 protected-mode
从注释信息就可以看到,如果protected-mode是yes的话,如果没有指定bind或者没有指定密码,那么只能本地访问。
protected-mode yes
- 端口号 port
配置Redis监听的端口号,默认6379。
# Accept connections on the specified port, default is 6379 (IANA #815344).
# If port 0 is specified Redis will not listen on a TCP socket.
port 6379
- TCP半连接队列长度配置 tcp-backlog
在进行TCP/IP连接时,内核会维护两个队列
- syns queue用于保存已收到sync但没有接收到ack的TCP半连接请求。由/proc/sys/net/ipv4/tcp_max_syn_backlog指定,我的系统(Ubuntu20.04)上是1024。
- accept queue,用于保存已经建立的连接,也就是全连接由/proc/sys/net/core/somaxconn指定。根据配置里的注释,需要同时提高somaxconn和tcp_max_syn_backlog的值来确保生效。
tcp-backlog 511
是否超时无操作关闭连接 timeout
客户端经过多少时间(单位秒)没有操作就关闭连接,0代表永不关闭。
timeout 0
- TCP连接保活策略 tcp-keepalive
TCP连接保活策略,可以通过tcp-keepalive配置项来进行设置,单位为秒,假如设置为60秒,则server端会每60秒向连接空闲的客户端发起一次ACK请求,以检查客户端是否已经挂掉,对于无响应的客户端则会关闭其连接。如果设置为0,则不会进行保活检测。
tcp-keepalive 300
GENERAL 通用配置
- 启动方式 daemonize
是否以守护(后台)进程的方式启动,默认no。
daemonize yes
- 进程pid文件 pidfile
redis启动后会把pid写入到pidfile指定的文件中。
pidfile /var/run/redis_6379.pid
- 日志相关 loglevel logfile
loglevel用于配置日志打印机别,默认notice:- debug:能设置的最高的日志级别,打印所有信息,包括debug信息。
- verbose:打印除了debug日志之外的所有日志。
- notice:打印除了debug和verbose级别的所有日志。
- warning:仅打印非常重要的信息。
loglevel notice
logfile ""
-
指定数据库的数量 databse
-
redis默认有16个数据库,编号从0开始。
databases 16
- 启动是否显示logo
always-show-logo yes
SNAPSHOTTING 快照相关
SECURITY 安全相关
################################## SECURITY ###################################
# Warning: since Redis is pretty fast, an outside user can try up to
# 1 million passwords per second against a modern box. This means that you
# should use very strong passwords, otherwise they will be very easy to break.
# Note that because the password is really a shared secret between the client
# and the server, and should not be memorized by any human, the password
# can be easily a long string from /dev/urandom or whatever, so by using a
# long and unguessable password no brute force attack will be possible.
大致意思就是redis很快,所以被破解密码时,性能也很好,如果你的密码太渣渣了,那么可能很快就被破解了,因此尽量使用长且不容易被猜到的密码作为redis的访问密码。
- 配置ACL
ACL:访问控制列表。
有两种方法配置ACL:- 在命令行通过ACL命令进行配置
在Redis配置文件中开始,可以直接在redis.conf中配置,也可以通过外部aclfile配置。aclfile path。 - 配置语法:user … acl rules …,例如 user worker +@list +@connection ~jobs:* on >ffa9203c493aa99
- 在命令行通过ACL命令进行配置
redis默认有一个default用户。如果default具有nopass规则(就是说没有配置密码),那么新连接将立即作为default用户登录,无需通过AUTH命令提供任何密码。否则,连接会在未验证状态下启动,并需要AUTH验证才能开始工作。
- ACL日志配置
设置ACL日志最大长度,默认128个记录。这个日志是存在内存里的。
acllog-max-len 128
- 外部ACL文件配置
默认位置etc/redis/users.acl,我们可以在这个文件中定义所有用户的ACL控制信息。
aclfile /etc/redis/users.acl
- 配置默认用户default的密码
该配置只对默认用户default生效。
requirepass yourpass
CLIENTS 客户端配置
- 设置最大同时客户端连接数
设置可以同时连接客户端的最大数量。默认该项设置为 10000 个客户端。达到限制值后的连接会被拒绝并会返回错误信息。
maxclients 10000
MEMORY MANAGEMENT 内存管理
- 最大内存限制
指定Redis最大内存限制。达到内存限制时,Redis将尝试删除已到期或即将到期的Key。
maxmemory
1
- 达到最大内存限制时的策略
配置达到最大内存限制后,Redis进行何种操作。默认noeviction
maxmemory-policy noeviction
总共有8种策略可供选择。
- volatile-lru 只对设置了过期时间的Key进行淘汰,淘汰算法近似的LRU。
- allkeys-lru 对所有Key进行淘汰,LRU。
- volatile-lfu 只对设置了过期时间的Key进行淘汰,淘汰算法近似的LFU。
- allkeys-lfu 对所有Key进行淘汰,LFU。
- volatile-random 只对设置了过期时间的Key进行淘汰,淘汰算法为随机淘汰。
- allkeys-random 对所有Key进行淘汰,随机淘汰。
- volatile-ttl 只对设置了过期时间的Key进行淘汰,删除即将过期的即ttl最小的。
- noeviction 永不删除key,达到最大内存再进行数据装入时会返回错误。
对于可以通过删除key来释放内存的策略,如果没有key可以删除了,那么也会报错。
使用LRU/LFU/TTL算法时采样率
Redis使用的是近似的LRU/LFU/minimal TTL算法。主要是为了节约内存以及提升性能。Redis配置文件有maxmemory-samples选项,可以配置每次取样的数量。Redis每次会选择配置数量的key,然后根据算法从中淘汰最差的key。
maxmemory-samples 5
- 使用LRU/LFU/TTL算法时采样率
Redis使用的是近似的LRU/LFU/minimal TTL算法。主要是为了节约内存以及提升性能。Redis配置文件有maxmemory-samples选项,可以配置每次取样的数量。Redis每次会选择配置数量的key,然后根据算法从中淘汰最差的key。
maxmemory-samples 5
可以通过修改这个配置来获取更高的淘汰精度或者更好的性能。默认值5就可以获得很好的结果。选择10可以非常接近真是的LRU算法,但是会耗费更多的CPU资源。3的话更快但是淘汰结果不是特别准确。
- 从库不淘汰数据
配置Redis主从复制时,从库超过maxmemory也不淘汰数据。这个配置主要是为了保证主从库的一致性,因为Redis的淘汰策略是随机的,如果允许从库自己淘汰key,那么会导致主从不一致的现象出现(master节点删除key的命令会同步给slave节点)。
replica-ignore-maxmemory yes
- 过期keys驻留在内存中的比例
设置过期keys仍然驻留在内存中的比重,默认是为1,表示最多只能有10%的过期key驻留在内存中,该值设置的越小,那么在一个淘汰周期内,消耗的CPU资源也更多,因为需要实时删除更多的过期key。
active-expire-effort 1
LAZY FREEING 懒惰删除
# Redis has two primitives to delete keys. One is called DEL and is a blocking
# deletion of the object. It means that the server stops processing new commands
# in order to reclaim all the memory associated with an object in a synchronous
# way. If the key deleted is associated with a small object, the time needed
# in order to execute the DEL command is very small and comparable to most other
# O(1) or O(log_N) commands in Redis. However if the key is associated with an
# aggregated value containing millions of elements, the server can block for
# a long time (even seconds) in order to complete the operation.
#
# For the above reasons Redis also offers non blocking deletion primitives
# such as UNLINK (non blocking DEL) and the ASYNC option of FLUSHALL and
# FLUSHDB commands, in order to reclaim memory in background. Those commands
# are executed in constant time. Another thread will incrementally free the
# object in the background as fast as possible.
# DEL, UNLINK and ASYNC option of FLUSHALL and FLUSHDB are user-controlled.
# It's up to the design of the application to understand when it is a good
# idea to use one or the other. However the Redis server sometimes has to
# delete keys or flush the whole database as a side effect of other operations.
# Specifically Redis deletes objects independently of a user call in the
# following scenarios:
#
# 1) On eviction, because of the maxmemory and maxmemory policy configurations,
# in order to make room for new data, without going over the specified
# memory limit.
# 2) Because of expire: when a key with an associated time to live (see the
# EXPIRE command) must be deleted from memory.
# 3) Because of a side effect of a command that stores data on a key that may
# already exist. For example the RENAME command may delete the old key
# content when it is replaced with another one. Similarly SUNIONSTORE
# or SORT with STORE option may delete existing keys. The SET command
# itself removes any old content of the specified key in order to replace
# it with the specified string.
# 4) During replication, when a replica performs a full resynchronization with
# its master, the content of the whole database is removed in order to
# load the RDB file just transferred.
#
# In all the above cases the default is to delete objects in a blocking way,
# like if DEL was called. However you can configure each case specifically
# in order to instead release memory in a non-blocking way like if UNLINK
# was called, using the following configuration directives.
翻译上面的话就是:
Redis有两个删除keys的原语。一个是DEL并且它是一个阻塞的删除对象的操作。意味着server会停止处理新的command以便以同步的方式回收与对象关联的所有内存。如果被删除的key关联的是一个小对象,那么执行DEL命令所需要的时间非常短,与Redis中其它O(1)或O(log_N)的命令时间开销几乎一样。然鹅,如果key与包含了数百万个元素的大对象相关联,那么服务器为了完成删除命令会阻塞很长时间(甚至几秒钟)。
出于以上原因,Redis提供了非阻塞的删除原语,例如UNLINK(非阻塞式的DEL)和FLUSHALL、FLUSHDB命令的ASYNC选项,以便在后台回收内存。这些命令会在常量(固定的)时间内执行。另外一个线程会在后台尽可能快的以渐进式的方式释放对象。
使用DEL,UNLINK以及FLUSHALL和FLUSHDB的ASYNC选项是由用户来控制的。这应该由应用程序的设计来决定使用其中的哪一个。 然鹅,作为其它操作的副作用,Redis server有时不得不去删除keys或者刷新整个数据库。具体来说,Redis在以下情况下会独立于用户调用而删除对象:
1) 由于maxmemory 和maxmemory policy的设置,为了在不超出指定的内存限制而为新对象腾出空间而逐出旧对象;
2) 因为过期:当一个key设置了过期时间且必须从内存中删除时;
3) 由于在已经存在的key上存储对象的命令的副作用。例如,RENAME命令可能会删除旧的key的内容,当该key的内容被其它内容代替时。类似的,SUNIONSTORE或者带STORE选项的SORT命令可能会删除已经存在的keys。SET命令会删除指定键的任何旧内容,以便使用指定字符串替换。
4)在复制过程中,当副库与主库执行完全重新同步时,整个数据库的内容将被删除,以便加载刚刚传输的RDB文件。
在上述所有情况下,默认情况是以阻塞方式删除对象,就像调用DEL一样。但是,你可以使用以下配置指令专门配置每种情况,以非阻塞的方式释放内存,就像调用UNLINK一样。
相关的配置:
# 内存达到设置的maxmemory时,是否使用惰性删除,对应上面 1)
lazyfree-lazy-eviction no
# 过期keys是否惰性删除,对应上面 2)
lazyfree-lazy-expire no
# 内部删除选项,对应上面选项 3)的情况是否惰性删除
lazyfree-lazy-server-del no
# slave接收完RDB文件后清空数据是否是惰性的,对应上面情况 4)
replica-lazy-flush no
# It is also possible, for the case when to replace the user code DEL calls
# with UNLINK calls is not easy, to modify the default behavior of the DEL
# command to act exactly like UNLINK, using the following configuration
# directive:
# 是否将DEL调用替换为UNLINK,注释里写的从user code里替换DEL调用为UNLINK调用可能并不是一件
# 容易的事,因此可以使用以下选项,将DEL的行为替换为UNLINK
lazyfree-lazy-user-del no
THREADED I/O
Redis大体上是单线程的,但是也有一些场景使用额外的线程去做的,比如UNLINK、slow I/O accesses。
现在还可以在不同的I/O线程中处理Redis客户端socket读写。(只是网络IO这块儿成了多线程,执行命令的那个家伙,还是单线程!)特别是因为写操作很慢,通常Redis的用户使用pipeline来提升每个核心下的Redis性能,并且运行多个Redis实例来实现扩展。使用多线程I/O,不需要使用pipeline和实例切分,就可以轻松的提升两倍的性能。
默认情况下,多线程是禁用的,我们建议只在至少有4个或更多内核的机器中启用多线程,至少保留一个备用内核。使用超过8个线程不太可能有多大帮助。我们还建议仅当您确实存在性能问题时才使用线程化I/O,因为除非Redis实例能够占用相当大的CPU时间,否则使用此功能没有意义。
- 配置IO线程数
如果你的机器是4核的,可以配置2个或者3个线程。如果你有8核,可以配置6个线程。通过下面这个参数来配置线程数:
io-threads 4
将io-threads设置为1将只使用主线程。当启用I/O线程时,我们只使用多线程进行写操作,也就是说,执行write(2)系统调用并将Client缓冲区传输到套接字。但是,也可以通过将以下配置指令设置为yes来启用读取线程和协议解析:
io-threads-do-reads no
通常情况下多线程的read并没有什么卵用。
需要注意的两点是:
- 这两个配置不能运行时通过CONFIG SET来改变,而且开启SSL功能时,多线程I/O同样不会生效。
- 如果你想用benchmark脚本测试多线程下的性能提升,确保benchmark也是多线程模式,在后面加上–threads参数,来匹配Redis的线程数。不然看不到什么性能提升。
KERNEL OOM CONTROL 设置OOM时终止哪些进程
在Linux上,可以提示内核OOM killer在OOM发生时应该首先终止哪些进程。
启用此功能可使Redis根据其角色主动控制其所有进程的oom_score_adj值。默认分数将尝试在所有其他进程之前杀死背景子进程,并在主进程之前杀死从节点进程。
Redis支持三个选项:
- no:对oom-score-adj不做任何修改(默认值)
- yes:relative的别名
- absolute:oom-score-adj-values配置的值将写入内核
- relative:当服务器启动时,使用相对于oom_score_adj初始值的值,然后将其限制在-1000到1000的范围内。因为初始值通常为0,所以它们通常与绝对值匹配。
oom-score-adj no
当使用oom-score-adj选项(不为no)时,该指令控制用于主、从和后台子进程的特定值。数值范围为-2000到2000(越高意味着死亡的可能性越大)。
非特权进程(不是根进程,也没有CAP_SYS_RESOURCE功能)可以自由地增加它们的价值,但不能将其降低到初始设置以下。这意味着将oom score adj设置为“相对”,并将oom score adj值设置为正值将始终成功
# 分别控制主进程、从进程和后台子进程的值
oom-score-adj-values 0 200 800
APPEND ONLY MODE AOF持久化配置
- 开始/关闭aof
appendonly no
- aof文件名称
appendfilename "appendonly.aof"
执行fsync()系统调用刷盘的频率
appendfsync everysec
- everysec:每秒执行,可能会丢失最后一秒的数据。
- always:每次写操作执行,数据最安全,但是对性能有影响。
- no:不强制刷盘,由内核决定什么时候刷盘,数据最不安全,性能最好。
- 当有后台保存任务时,关闭appendfsync
当后台在执行save任务或者aof文件的rewrite时,会对磁盘造成大量I/O操作,在某些Linux配置中,Redis可能会在fsync()系统调用上阻塞很长时间。需要注意的是,目前还没有很好的解决方法,因为即使是在不同的线程中执行fsync()调用也会阻塞write(2)调用。
为了缓解上述问题,可以使用以下选项,防止在进行BGSAVE或者BGREWRITEAOF时在主进程中调用fsync()。
这意味这如果有其它子进程在执行saving任务时,Redis的行为相当于配置了appendfsync none。实际上,这意味着在最坏的情况下(使用Linux默认设置),可能丢失最多30s的日志。
如果您有延迟的问题(性能问题),将此设置为“yes”,否则,设置为“no”。从持久化的角度看,这是最安全的选择。
no-appendfsync-on-rewrite no
- 自动重写aof文件
在AOF文件大小增长到了指定的百分比(相对于上次AOF文件大小的增长量)或者最小体积时,自动调用BGREWRITEAOF命令重写AOF文件。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
- AOF文件末尾被截断
在Redis启动过程的最后,当AOF数据加载回内存时,可能会发现AOF文件被截断。当运行Redis的系统崩溃时,可能会发生这种情况,尤其是在安装ext4文件系统时,没有data=ordered选项(然而,当Redis本身崩溃或中止,但操作系统仍然正常工作时,这种情况不会发生)。
Redis可以在出现这种情况时带着错误退出,也可以加载尽可能多的数据(现在是默认值),并在发现AOF文件在最后被截断时启动。以下选项控制此行为。
如果aof load truncated设置为yes,则会加载一个被截断的aof文件,Redis服务器开始发送日志,通知用户该事件。否则,如果该选项设置为“no”,服务器将因错误而中止并拒绝启动。当选项设置为“no”时,用户需要使用“redis-check-aof”实用程序修复AOF文件,然后才能重新启动服务器。
请注意,如果在中间发现AOF文件已损坏,服务器仍将退出并出现错误。此选项仅适用于Redis尝试从AOF文件读取更多数据,但找不到足够字节的情况。
aof-load-truncated yes
- 开启混合持久化
当重写AOF文件时,Redis能够在AOF文件中使用RDB前导,以更快地重写和恢复。启用此选项后,重写的AOF文件由两个不同的节组成:
[RDB file][AOF tail]
加载时,Redis识别出AOF文件以“Redis”字符串开头,并加载带前缀的RDB文件,然后继续加载AOF尾部。
aof-use-rdb-preamble yes
LUA SCRIPTING-LUA脚本相关
- 配置LUA脚本最大执行时长
单位毫秒,默认5s。当脚本运行时间超过限制后,Redis将开始接受其他命令当不会执行,而是会返回BUSY错误。
lua-time-limit 5000
REDIS CLUSTER 集群配置
- 允许集群模式
只有以集群模式启动的Redis实例才能作为集群的节点
cluster-enabled yes
- 集群配置文件
由Redis创建维护,不需要我们关心内容,只需要配好位置即可
cluster-config-file nodes-6379.conf
- 节点超时时间
集群模式下,master节点之间会互相发送PING心跳来检测集群master节点的存活状态,超过配置的时间没有得到响应,则认为该master节点主观宕机。
cluster-node-timeout 15000
- 设置副本有效因子
副本数据太老旧就不会被选为故障转移的启动者。
副本没有简单的方法可以准确测量其“数据年龄”,因此需要执行以下两项检查:
- 如果有多个复制副本能够进行故障切换,则它们会交换消息,以便尝试为具有最佳复制偏移量的副本提供优势(已经从master接收了尽可能多的数据的节点更可能成为新master)。复制副本将尝试按偏移量获取其排名,并在故障切换开始时应用与其排名成比例的延迟(排名越靠前的越早开始故障迁移)。
- 每个副本都会计算最后一次与其主副本交互的时间。这可以是最后一次收到的PING或命令(如果主机仍处于“已连接”状态),也可以是与主机断开连接后经过的时间(如果复制链路当前已关闭)。如果最后一次交互太旧,复制副本根本不会尝试故障切换。
第二点的值可以由用户调整。特别的,如果自上次与master交互以来,经过的时间大于(node-timeout * cluster-replica-validity-factor) + repl-ping-replica-period,则不会成为新的master。
较大的cluster-replica-validity-factor可能允许数据太旧的副本故障切换到主副本,而太小的值可能会阻止群集选择副本。
为了获得最大可用性,可以将cluster-replica-validity-factor设置为0,这意味着,无论副本上次与主机交互的时间是什么,副本都将始终尝试故障切换主机。(不过,他们总是会尝试应用与其偏移等级成比例的延迟)。
0是唯一能够保证当所有分区恢复时,集群始终能够继续的值(保证集群的可用性)。
cluster-replica-validity-factor 10
- 设置master故障转移时保留的最少副本数
群集某个master的slave可以迁移到孤立的master,即没有工作slave的master。这提高了集群抵御故障的能力,因为如果孤立master没有工作slave,则在发生故障时无法对其进行故障转移。
只有在slave的旧master的其他工作slave的数量至少为给定数量时,slave才会迁移到孤立的master。这个数字就是cluster-migration-barrier。值为1意味着slave只有在其master至少有一个其他工作的slave时才会迁移,以此类推。它通常反映集群中每个主机所需的副本数量。
默认值为1(仅当副本的主副本至少保留一个副本时,副本才会迁移)。要禁用迁移,只需将其设置为非常大的值。可以设置值0,但仅对调试有用,并且在生产中很危险。
cluster-migration-barrier 1
- 哈希槽全覆盖检查
默认情况下,如果Redis群集节点检测到至少有一个未覆盖的哈希槽(没有可用的节点为其提供服务),它们将停止接受查询。这样,如果集群部分关闭(例如,一系列哈希槽不再被覆盖),那么所有集群最终都将不可用。一旦所有插槽再次被覆盖,它就会自动返回可用状态。
然而,有时您希望正在工作的集群的子集继续接受对仍然覆盖的密钥空间部分的查询。为此,只需将cluster-require-full-coverage选项设置为no。
cluster-require-full-coverage yes
- 是否自动故障转移
当设置为“yes”时,此选项可防止副本在主机故障期间尝试故障切换master。但是,如果被迫这样做,主机仍然可以执行手动故障切换。
这在不同的场景中很有用,尤其是在多个数据中心运营的情况下,如果不在DC(DataCenter?)完全故障的情况下,我们希望其中一方永远不会升级为master。
cluster-replica-no-failover no
- 集群失败时允许节点处理读请求
此选项设置为“yes”时,允许节点在集群处于关闭状态时提供读取流量,只要它认为自己拥有这些插槽。
这对两种情况很有用。第一种情况适用于在节点故障或网络分区期间应用程序不需要数据一致性的情况。其中一个例子是缓存,只要节点拥有它应该能够为其提供服务的数据。
第二个用例适用于不满足三个分片集群,但又希望启用群集模式并在以后扩展的配置。不设置该选项而使用1或2分片配置中的master中断服务会导致整个集群的读/写服务中断。如果设置此选项,则只会发生写中断。如果达不到master的quorum(客观宕机)数值,插槽所有权将不会自动更改。
cluster-allow-reads-when-down no
CLUSTER DOCKER/NAT support
声明访问IP、port
以下三项设置对NAT网络或者Docker的支持。
因为NAT端口映射的IP地址在局域网之外是没办法访问到的,因此在这种情况下,要声明集群的公网网关(NAT映射)/宿主机的IP地址,以便局域网之外也可以访问到NAT映射后的/Docker容器内的Redis集群中的每个实例。
cluster-announce-bus-port集群节点之间进行数据交换的额外端口。
cluster-announce-ip
cluster-announce-port
cluster-announce-bus-port
SLOW LOG 慢日志
Redis的慢查询日志功能用于记录执行时间超过给定时长的命令请求,用户可以通过这个功能产生的日志来监视和优化查询速度
- 设置慢日志记录阈值
超过这个值的命令会被记录到慢日志中,默认10000微秒。
slowlog-log-slower-than <microseconds>
慢日志文件大小
可以通过这个配置改变慢日志文件的最大长度,超过这个长度后最旧的记录会被删除。默认128。
slowlog-max-len 128
LATENCY MONITOR 延迟监控
Redis延迟监控子系统在运行时对不同的操作进行采样,以收集与Redis实例可能的延迟源相关的数据。
通过延迟命令,用户可以打印图表和获取报告。
系统仅记录在等于或大于通过延迟监视器阈值配置指令指定的毫秒数的时间内执行的操作。当其值设置为零时,延迟监视器将关闭。
默认情况下,延迟监控是禁用的,因为如果没有延迟问题,通常不需要延迟监控,而且收集数据会对性能产生影响,虽然影响很小,但可以在大负载下进行测量。如果需要,可以在运行时使用命令CONFIG SET latency-monitor-threshold 轻松启用延迟监控。
设置延迟阈值
latency-monitor-threshold 0
EVENT NOTIFICATION 事件通知
Redis keyspace notifications
实时的监控keys和values的更改。
Redis可以将key space中发生的事件通过发布/订阅通知客户端。
例如,如果notify-keyspace-events已经启用,并且客户端对数据库0中存储的键foo执行DEL操作,则将通过Pub/Sub发布两条消息:
-
PUBLISH keyspace@0:foo del
-
PUBLISH keyevent@0:del foo
可以在一组类中选择Redis将通知的事件。每个类由一个字符标识: -
K Keyspace事件,通过__keyspace@__前缀发布。
-
E Keyevent事件,通过__keyevent@__ 前缀发布。
-
g 通用命令(非特定类型),例如DEL,EXPIRE,RENAME…
-
$ String相关命令
-
l List相关命令
-
s Set相关命令
-
h Hash相关命令
-
z Sorted Set(ZSet)相关命令
-
x 过期事件(每次key过期时生成的事件)
-
e 回收事件(达到maxmemory时回收key的事件)
t- Stream相关命令 -
m Key-miss events,访问的key不存在时触发
-
A g$lshzxet的别名,因此AKE代表了除了m之外的所有事件。
默认情况下所有事件通知都是关闭的,因为大多数用户不需要这些特性。且需要至少有K或者E时事件通知才会生效。
notify-keyspace-events ""
ADVANCED CONFIG 高级设置
- 设置Hash底层数据结构由ziplist转为hashtable的阈值
当Hash类型的keys只包含了少量的实体并且实体的大小没有超过给定的阈值时,Hash底层会使用ziplist来存储数据而不是使用hashtable以节省空间。
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
当一个Hash类型的key包含的实体数量超过了hash-max-ziplist-entries的值或者某个实体的大小超过了hash-max-ziplist-value的值(单位字节),那么底层编码就会升级成hashtable。
- 设置List底层数据结构quicklist中单个ziplist的大小
Redis中List数据结构的底层使用的是quicklist的数据结构,本质上是ziplist作为节点串起来的linkedlist。可以通过该项设置来改变每个ziplist的最大大小(ziplist中的fill属性,超过这个值就会开启一个新的ziplist)。总共提供了-5到-1五个选项:
--5:最大大小为64Kb,不推荐作为正常情况下的负载
-4:最大大小为32Kb,不推荐
-3:最大大小为16Kb,大概可能估计好像不是很推荐(原话:probably not recommended)
-2:最大大小为8Kb,good(原话)
-1:最大大小为4Kb,good(原话)
默认值是-2
list-max-ziplist-size -2
- 设置压缩List中ziplist为quicklistLZF结构
大神们觉着ziplist不够zip啊,所以再压缩一下吧。实际上是考虑了这样的场景,即List数据结构两端访问频率比较高,但是中间部分访问频率不是很高的情况,那么使用ziplist存放这部分结构就有点浪费,是不是可以把这部分结构进行压缩(LZF算法压缩)呢?这个选项就是进行这个操作的。有下面几个值:
- 0:代表不压缩,默认值
- 1:两端各一个节点不压缩
- 2:两端各两个节点不压缩
…:依次类推。。。
list-compress-depth 0
- 设置Set底层intset最大entities个数/intset升级为hashtable的阈值
Set数据结构只有在一种情况下会使用intset来存储:set由能转成10进制且数值在64bit有符号整形数值组成时。下面的配置设置了intset能存储的最大entities数量,超过这个数量会转成hashtable存储。默认512个。
set-max-intset-entries 512
- 设置ZSet底层数据结构由ziplist转为skiplist的阈值
当超过下面设置的阈值时,ZSet底层存储结构会由ziplist转为skiplist。
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
设置HyperLogLog底层稀疏矩阵转为稠密矩阵的阈值
HyperLogLog当在计数比较小时会使用稀疏矩阵来存储,只有当计数达到阈值时,才会转为稠密矩阵。
超过16000的值是完全无用的,因为这种情况下使用稠密矩阵更加节省内存。
建议的值是3000左右,以便在不降低太多PFADD速度的情况下获取空间有效编码的好处,稀疏编码的PFADD的时间复杂度为O(N)。当不考虑CPU占用时而考虑内存占用时,这个值可以升到10000左右。
hll-sparse-max-bytes 3000
- 自定义Stream宏节点大小
可以通过stream-node-max-bytes选项修改Stream中每个宏节点能够占用的最大内存,或者通过stream-node-max-entries参数指定每个宏节点中可存储条目的最大数量。
stream-node-max-bytes 4096
stream-node-max-entries 100
- 开启Rehash
Redis将在每100毫秒时使用1毫秒的CPU时间来对redis的hash表进行重新hash,可以降低内存的使用。当你的使用场景中,有非常严格的实时性需要,不能够接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置为no。如果没有这么严格的实时性要求,可以设置为yes,以便能够尽可能快的释放内存。
activerehashing yes
客户端输出缓存控制
客户端输出缓冲区限制可用于强制断开由于某种原因从服务器读取数据速度不够快的客户端(一个常见原因是发布/订阅客户端不能像发布服务器生成消息那样快地使用消息)。
对于三种不同类型的客户端,克制设置不同的限制:
normal:一般客户端包含监控客户端
replica:副本客户端(slave)
pubsub:客户端至少订阅了一个pubsub通道或模式。
每个客户端输出缓冲区限制指令语法:
client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>
一旦达到限制或者达到之后又过了秒,那么客户端会立即被断开连接。
例如,如果为32兆字节,和分别为16兆字节,10秒,则如果输出缓冲区的大小达到32兆字节,客户端将立即断开连接,但如果客户端达到16兆字节并连续超过限制10秒,客户端也将断开连接。
默认情况下,普通客户端不受限制,因为它们不会在没有请求(以推送方式)的情况下接收数据,而是在请求之后接收数据,因此只有异步客户端可能会创建一个场景,其中请求数据的速度比读取数据的速度快。
相反,pubsub和副本客户端有一个默认限制,因为订阅者和副本以推送方式接收数据。
硬限制或软限制都可以通过将其设置为零来禁用。
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
- 配置客户端query buffer大小
客户端query buffer大小不能超过该项配置的值。
每个Client都有一个query buffer(查询缓存区或输入缓存区), 它用于保存客户端的发送命令,redis
server从query buffer获取命令并执行。如果程序的Key设计不合理,客户端使用大量的query
buffer,这会导致redis server比较危险,很容易达到maxmeory限制,导致缓存数据被清空、数据无法写入和oom.https://blog.csdn.net/u012271526/article/details/107208295
client-query-buffer-limit 1gb
Redis协议批量请求单个字符串限制
默认512mb,可以通过下面选项修改
proto-max-bulk-len 512mb
- Redis执行任务频率
Redis调用一个内部函数来执行许多后台任务,比如在超时时关闭客户端连接,清楚从未被请求过的过期key…
并非所有任务都已相同的频率执行,但Redis根据指定的hz值检查要执行的任务。
默认情况下,hz的值为10.提高这个值会让Redis在空闲的时候占用更多的CPU,但同时也会让Redis在有很多keys同时过期时响应更快并且可以更精确的处理超时。
范围在1到500之间,但是超过100通常不是一个好主意。大多数用户应该使用缺省值10,只有在需要非常低延迟的环境中才应该将值提高到100。
hz 10
- 动态hz配置
根据客户端连接的数量动态的调整hz的值,当有更多的客户端连接时,会临时以hz设置基准提高该hz的值。默认开启。
dynamic-hz yes
- AOF重写时执行fsync刷盘策略
当一个子系统重写AOF文件时,如果启用了以下选项,则该文件将每生成32MB的数据进行fsync同步。这对于以更增量的方式将文件提交到磁盘并避免较大的延迟峰值非常有用。
aof-rewrite-incremental-fsync yes
- 保存RDB文件时执行fsync刷盘策略
当redis保存RDB文件时,如果启用以下选项,则每生成32 MB的数据,文件就会同步一次。这对于以更增量的方式将文件提交到磁盘并避免较大的延迟峰值非常有用。
rdb-save-incremental-fsync yes
- LFU设置
设置Redis LFU相关。Redis LFU淘汰策略实现有两个可调整参数:lfu-log-factor和lfu-decay-time。
lfu-log-factor 10
lfu-decay-time 1
ACTIVE DEFRAGMENTATION 碎片整理
主动(在线)碎片整理允许Redis服务器压缩内存中数据的少量分配和释放之间的空间(内存碎片),从而回收内存。
碎片化是每个分配器(幸运的是,Jemalloc比较少发生这种情况)和某些工作负载都会发生的自然过程。通常需要重启服务器以降低碎片,或者至少清除所有数据并重新创建。然而,多亏了Oran Agra为Redis 4.0实现的这一功能,这个过程可以在服务器运行时以“hot”的方式在运行时发生(类似热部署的意思,不需要停止服务)。
基本上,当碎片超过某个级别(参见下面的配置选项)时,Redis将通过利用特定的Jemalloc功能(以了解分配是否导致碎片并将其分配到更好的位置)开始在连续内存区域中创建值的新副本,同时释放数据的旧副本。对所有键递增地重复该过程将导致碎片降至正常值。
需要了解的重要事项:
1.默认情况下,此功能被禁用,并且仅当您编译Redis以使用我们随Redis源代码提供的Jemalloc副本时,此功能才有效。这是Linux版本的默认设置。
2.如果没有碎片问题,则无需启用此功能。
3.一旦遇到内存碎片,可以在需要时使用命令CONFIG SET activedefrag yes启用此功能。
配置参数能够微调碎片整理过程的行为。如果你不确定它们是什么意思,最好不要改变默认值。
- 开启活动碎片整理
activedefrag no
- 启动活动碎片整理的最小内存碎片阈值
active-defrag-ignore-bytes 100mb
- 启动活动碎片整理的最小内存碎片百分比
active-defrag-threshold-lower 10
- 尝试释放的最大百分比
active-defrag-threshold-upper 100
- 最少CPU使用率
active-defrag-cycle-min 1
- 最大CPU使用率
active-defrag-cycle-max 25
- 最大扫描量
# Maximum number of set/hash/zset/list fields that will be processed from
# the main dictionary scan
active-defrag-max-scan-fields 1000
使用后台线程
jemalloc-bg-thread yes