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开启认证方法

  1. /etc/redis.conf 配置文件中添加:requirepass your_pass
  2. 登录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同时启用

    1. BGSAVE和BGREWRITEAOF不会同时执行
    2. 在Redis服务器启动用于回复数据时,会优先使用AOF

Redis的主从复制

  • 特点:一个Master可以有多个Slave,支持链式复制,Master以非阻塞方式同步数据至slave
  • 主从复制工作过程:
    1. 主库基于ping命令检测从服务器是否在线
    2. 从库发送同步请求到主库请求同步数据,主库启动一个子进程,将内存中的数据保存到文件中发送给从库,从库将数据先保存到本地数据文件中,然后再将文件加载到内存中完成同步
  • 主从配置,在从服务器配置文件中配置slaveof <masterip> <masterport>或者直接在命令行接口中redis-cli中配置slaveof <masterip> <masterport>,*注意:配置主从服务器的时候,配置文件如果监听了多个IP,需要将将主从服务器同一网段的IP配置在前面
  • 如果master使用requirepass开启了认证功能,从服务器要使用masterauth <password> 来连入主服务器

用sentinel实现redis集群高可用

  • sentinel用于管理多个redis服务器实现高可用

  • 可以监控redis Master运行状况,当主服务器发生故障时,实现自动在从服务器中挑选出一个从服务器作为主服务器

  • 使用流言协议,投票协议

  • 主观下线:一个sentinel实例判断某节点下线

  • 客观下线:多个sentinel实例协商后判断出某节点下线

  • 每秒通过ping命令探测所有节点是否存活

  • 运行sentinel

    1. redis-sentinel /path/to/file.conf
    2. redis-server --sentinel /path/to/file.conf
    3. 服务器自身初始化,运行redis-server中专用于sentinel功能的代码
    4. 初始化sentinel状态,根据指定的配置文件,初始化监控的Master服务器列表
    5. 创建连接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专用命令:

    1. sentinel masters:获取所有master节点
    2. sentinel slaves <master name> 获取指定Master的从服务器节点
    3. sentinel get-master-addr-by-name <master name>
    4. sentinel reset:重置所有状态
    5. 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服务器被他人控制

那么攻击是如何发生的呢?简要说来又如下几个步骤:

  1. 恶意扫描6379端口(redis 默认端口), 确定包含redis服务, 并试图ssh登录, 因为Redis服务器并无攻击者public key, 登录失败
  2. 使用redis 客户端连接redis服务器, 执行redis命令(del, flushdb, flushall)清除所有redis数据
  3. 使用“config dir” 命令将 redis 数据备份路径至 /root/.ssh/
  4. 使用“config filename”指定 RDB(redis定时备份) 备份文件名称为authorized_keys
  5. 设置crackit key, 将value设置为恶意访问者的公钥
  6. 执行bgsave, save动作触发RDB数据备份,将攻击者公钥存储在authorized_keys
  7. 攻击者ssh到redis 服务器成功

redis本省要求redis部署在一个只有可信赖的client才可访问的安全环境,因此包含如下建议:

  1. 更改默认端口:

    更改默认端口可以降低redis服务被发现的可能性, 但并不能完全制止, 攻击可以扫描其他端口并试图判定其为redis服务器

  2. 增加redis密码验证,增加redis密码验证可有效防止redis服务器的恶意登录, 但redis但密码要足够复杂:

    2.1 redis是基于内存的数据库, 访问速度十分快, 如果密码不够复杂, 则很容易被恶意破解

    2.2 redis的密码传输是基于明文的, 如果攻击者在客户端和redisf服务器所属的网络之内, 还是可以截取到密码

  3. 不要绑定所有网络接口

    redis提供bind配置选项, 用于配置redis服务绑定都那个所在物理服务器的网络接口, 如果不指定则默认绑定所有网络接口, 如果服务器本身有外网地址, 则外网也可以访问

  4. 使用非root用户启动redis服务

    当redis被贡献后, 如果使用root启动服务器, 可能导致攻击者具有root用户权限, 对服务器危害较大, 因此尽量不要使用root用户

  5. 更改命令名称防止破坏性命令的执行

    redis支持rename操作更改命令名称, 如rename flushall abcdefg, renam后执行flushall命令则会提示命令不存在

    rename的缺点是rename后的aof文件向前兼容, 即一个aof文件如果即包含rename前和rename后的command, 在倒入其他redis实例时可能会失败

posted @ 2018-10-11 17:10  谭普利特  阅读(246)  评论(0编辑  收藏  举报