Redis
redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。它通过提供多种键值数据类型来适应不同场景下的存储求,目前为止redis支持的键值数据类型如下字符串、列表(lists)、集合(sets)、有序集合(sorts sets)、哈希表(hashs)
Redis的应用场景
缓存(数据查询、短连接、新闻内容、商品内容等等)。(最多使用)分布式集群架构中的session分离。聊天室的在线好友列表、任务队列。(秒杀、抢购、12306等等)应用排行榜。网站访问统计。数据过期处理(可以精确到毫秒)
安装
Linux环境下,Redis的安装与部署,Redis的安装与部署,使用redis-3.0以后的稳定版,因为redis从3.0开始增加了集群功能。
cd /usr/local/src
wget http://download.redis.io/releases/redis-4.0.11.tar.gz
tar xf redis-4.0.11.tar.gz
cd /usr/local/src/redis-4.0.11
make PREFIX=/usr/local/redis install #安装
cp /usr/local/src/redis-4.0.11/redis.conf /etc/redis.conf #将源码目录下的配置文件拷贝过来
[root@localhost bin]# ll #
total 21872
-rwxr-xr-x. 1 root root 2451240 Oct 31 22:18 redis-benchmark #性能测试工具
-rwxr-xr-x. 1 root root 5774384 Oct 31 22:18 redis-check-aof #文件修复工具
-rwxr-xr-x. 1 root root 5774384 Oct 31 22:18 redis-check-rdb #文件修复工具
-rwxr-xr-x. 1 root root 2617272 Oct 31 22:18 redis-cli #命令行客户端
lrwxrwxrwx. 1 root root 12 Oct 31 22:18 redis-sentinel -> redis-server #集群管理工具
-rwxr-xr-x. 1 root root 5774384 Oct 31 22:18 redis-server #服务启动工具
将redis命令加入到环境变量中,并加入开机启动
echo 'export PATH=$PATH:/usr/local/redis/bin' >> /etc/profile
source /etc/profile
echo '/usr/local/redis/bin/redis-server /etc/redis.conf' >> /etc/rc.local
启动Redis
Redis默认是以前端模式启动,需要修改redis.conf中的daemonize 为yes才能变成后端模式启动
vim /usr/local/redis/bin/redis.conf
daemonize yes
执行以下命令启动redis
/usr/local/redis/bin/redis-server /etc/redis.conf #将/etc/redis.conf作为配置文件启动
连接redis
/usr/local/redis/bin/redis-cli
关闭Redis
强行终止redis进程可能会导致redis持久化数据丢失。正确停止Redis的方式应该是向Redis发送SHUTDOWN命令,命令为:
./bin/redis-cli shutdown
Redis配置文件参数
配置文件位置:/etc/redis.conf
- daemonize no 是否以守护进程运行
- port:默认监听tcp/6379
- tcp-backlog 511:等待队列
- bind 127.0.0.1 : 监听地址
- unixsocket /tmp/redis.sock
- timeout 0:当客户端连接超时时间0表示不超时
- database 16 :表示可以使用多少个database
- save 900 1:如果900秒内有一次数据修改,就做一次快照,持久化
- save “” : 关闭RDB
- slaveof <masterip> <masterport> : 指明是谁的从服务器
- maxclients : 最大客户端并发数
- maxmemory:指明主机最大允许使用内存量
- dbfilename dump.rdb:持久化文件名
- dir /var/lib/redis:指明持久化文件保存目录
- rdbcompression yes:持久化时是否压缩
- rdbchecksum yes:持久化时是否校验
- stop-write-on-bgsave-error yes :持久化过程中如果出现错误,是否停止持久化
- appendonly on :默认关闭AOF
- appendfilename “appendonly.aof” : AOF文件名
- appendfsync always :每次收到写请求都会追加到文件中(io操作频繁)
- appendfsync everysec:每秒钟往aof文件中写一次(推荐使用)
- appendfsync no:不通知内核,内核决定什么时候持久化写入
- no-appendfsync-on-rewrite no:重写的时候对新的写操作不做写入
- auto-aof-rewrite-percentage 100:表示如果当前的aof文件大小已经是上一次重写时文件大小的2倍时触发一次重写过程
- auto-aof-rewrite-min-size 64mb:重写时的最小大小,避免刚开始的频繁重写
- slave-serve-stale-data yes:当主服务器连接不上时是否仍旧响应数据
- slave-read-only yes:slave只读
- slave-priority 100:slave的优先级,优先同步
redis开启认证方法
- 在 /etc/redis.conf 配置文件中添加:requirepass your_pass
- 登录redis之后使用,auth your_pass即可
清空数据库
- FLUSHDB:清空当前库
- FLUSHALL:清空所有库
Redis连接相关命令
- ping
- echo
- auth:认证
- select:选择数据库
Redis持久化
-
RDB模式:snapshot,二进制格式,默认模式,按照事先定制的策略,周期性的将数据保存至磁盘,数据文件默认为dump.rdb,启动一个新线程来保存数据;
-
客户端也可以显示使用SAVE和BGSAVE命令启动快照保存机制;SAVE:在主线程中保存快照,但是SAVE命令是在主线程中执行保存数据,会阻塞所有客户端请求;BGSAVE:异步,不会阻塞客户端的请求
-
AOF模式:Append Only File,会将收到的每一次写操作记录到文件中类似于,MySQL的binlog,Redis能够合并AOF的文件,当redis重启时,可通过重新执行文件中的命令在内存中重建数据库。
BGREWARITEAOF:不会读取正在使用AOF,而通过将内存中的数据以命令的方式保存到临时文件中,完成之后替换原来的AOF文件。
AOF文件重建过程:redis主进程调用fork生成子进程,子进程根据redis内存中数据现有状态往临时文件中生成重建数据库的命令,父进程将继续接受客户端请求,并且会把这些请求中的写操作继续追加至原来的AOF文件(防止重写失败),额外的,这些新的写请求还会被放置在一个缓冲队列中,子进程重写完成会通知父进程,父进程把缓冲中的命令写到临时文件中,父进程用临时文件替换原来的文件
-
注意:持久化本身不能取代备份,还应该指定备份策略,对redis数据库定期进行备份
-
RDB与AOF同时启用
- BGSAVE和BGREWRITEAOF不会同时执行
- 在Redis服务器启动用于回复数据时,会优先使用AOF
Redis的主从复制
- 特点:一个Master可以有多个Slave,支持链式复制,Master以非阻塞方式同步数据至slave
- 主从复制工作过程:
- 主库基于ping命令检测从服务器是否在线
- 从库发送同步请求到主库请求同步数据,主库启动一个子进程,将内存中的数据保存到文件中发送给从库,从库将数据先保存到本地数据文件中,然后再将文件加载到内存中完成同步
- 主从配置,在从服务器配置文件中配置slaveof <masterip> <masterport>或者直接在命令行接口中redis-cli中配置slaveof <masterip> <masterport>,*注意:配置主从服务器的时候,配置文件如果监听了多个IP,需要将将主从服务器同一网段的IP配置在前面
- 如果master使用requirepass开启了认证功能,从服务器要使用masterauth <password> 来连入主服务器
用sentinel实现redis集群高可用
-
sentinel用于管理多个redis服务器实现高可用
-
可以监控redis Master运行状况,当主服务器发生故障时,实现自动在从服务器中挑选出一个从服务器作为主服务器
-
使用流言协议,投票协议
-
主观下线:一个sentinel实例判断某节点下线
-
客观下线:多个sentinel实例协商后判断出某节点下线
-
每秒通过ping命令探测所有节点是否存活
-
运行sentinel
- redis-sentinel /path/to/file.conf
- redis-server --sentinel /path/to/file.conf
- 服务器自身初始化,运行redis-server中专用于sentinel功能的代码
- 初始化sentinel状态,根据指定的配置文件,初始化监控的Master服务器列表
- 创建连接master的连接
-
专用配置文件:/etc/redis-sentinel.conf
-
主要配置示例:
# sentinel monitor <master-name> <ip> <redis-port> <quorum> 配置监控的master,从节点通过主节点获取,该选项可以设置多次,可以指定多个集群,指定多个集群 的时候需要指定不同的master-name sentinel monitor mymaster 127.0.0.1 6379 2 # sentinel down-after-milliseconds <master-name> <milliseconds> 判断主节点不在线需要的秒数,默认为30秒,可以根据网络状况适当调整 sentinel down-after-milliseconds mymaster 30000 # sentinel parallel-syncs <master-name> <numslaves> 指定主服务器宕机后,新主服务器允许多少个从服务器向新的嘱咐其发起同步请求,默认为1个 sentinel parallel-syncs mymaster 1 # sentinel failover-timeout <master-name> <milliseconds> 故障转移超时时间,当主服务器宕机以后,将从服务器设为主服务器的超时时间,如果设定时间内不能将从 服务器设置为主服务器则失败,默认为3分钟 sentinel failover-timeout mymaster 180000
-
sentinel专用命令:
- sentinel masters:获取所有master节点
- sentinel slaves <master name> 获取指定Master的从服务器节点
- sentinel get-master-addr-by-name <master name>
- sentinel reset:重置所有状态
- sentinel failover <master name>:手动执行故障转移操作
Clustering
- 分布式数据库,通过分片机制进行数据分布,clustering内的每个节点仅有数据库的一部分数据
- 每个节点持有全局元数据,但仅持有一部分数据
Redis安全问题
2015年, 很多redis节点都遭受到了攻击, redis中的数据全部被清除, 只包含一个名为crackit(换一个key就很难被发现了)的key, key的value为类似如下的公钥:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCoqWfDFlTW1aG0aywc/n+f8H0DXcKJ/T5812jzo8jhgthtrOCo/C8x+R8q2KYgihO/anGtHk86Wr8Ng9Kciy495omc18aLHmq5v9TDT24ws//Gj8Rtqn3cEn6LhckDE+nYIrMTaFG164odAYUZJkJyYOxql5xnJzm1Dmlpjft8Se/fOOdtLn4sfyKntDVfVEAT1T5PRu6XS3RSuMUfDxxIhQsidZn5m+V+eHiJESSVhjEIFmbWcITyzwu+xd+/GlvyTtMWNZNB/03zlJY4KCnqMST8sAwQbHZT1JbMa4xL2RZQRONDZp2n7C3jCtNf/J67z4A6olCdaUKrSkh9lvJ5
,对用户的生产环境产生了很大的影响:
将redis作为持久化数据库的产品, 引起数据丢失
将redis最为缓存使用的产品, 因为从redis获取不到数据, 所用请求全部涌入到后端数据库服务器, 造成数据库服务器压力过大, 影响产品性能甚至数据库奔溃 redis服务期被植入了非法公钥, 以至于redis服务器被他人控制
那么攻击是如何发生的呢?简要说来又如下几个步骤:
- 恶意扫描6379端口(redis 默认端口), 确定包含redis服务, 并试图ssh登录, 因为Redis服务器并无攻击者public key, 登录失败
- 使用redis 客户端连接redis服务器, 执行redis命令(del, flushdb, flushall)清除所有redis数据
- 使用“config dir” 命令将 redis 数据备份路径至 /root/.ssh/
- 使用“config filename”指定 RDB(redis定时备份) 备份文件名称为authorized_keys
- 设置crackit key, 将value设置为恶意访问者的公钥
- 执行bgsave, save动作触发RDB数据备份,将攻击者公钥存储在authorized_keys
- 攻击者ssh到redis 服务器成功
redis本省要求redis部署在一个只有可信赖的client才可访问的安全环境,因此包含如下建议:
-
更改默认端口:
更改默认端口可以降低redis服务被发现的可能性, 但并不能完全制止, 攻击可以扫描其他端口并试图判定其为redis服务器
-
增加redis密码验证,增加redis密码验证可有效防止redis服务器的恶意登录, 但redis但密码要足够复杂:
2.1 redis是基于内存的数据库, 访问速度十分快, 如果密码不够复杂, 则很容易被恶意破解
2.2 redis的密码传输是基于明文的, 如果攻击者在客户端和redisf服务器所属的网络之内, 还是可以截取到密码
-
不要绑定所有网络接口
redis提供bind配置选项, 用于配置redis服务绑定都那个所在物理服务器的网络接口, 如果不指定则默认绑定所有网络接口, 如果服务器本身有外网地址, 则外网也可以访问
-
使用非root用户启动redis服务
当redis被贡献后, 如果使用root启动服务器, 可能导致攻击者具有root用户权限, 对服务器危害较大, 因此尽量不要使用root用户
-
更改命令名称防止破坏性命令的执行
redis支持rename操作更改命令名称, 如rename flushall abcdefg, renam后执行flushall命令则会提示命令不存在
rename的缺点是rename后的aof文件向前兼容, 即一个aof文件如果即包含rename前和rename后的command, 在倒入其他redis实例时可能会失败