Redis学习笔记

373 阅读13分钟

1.基础

1.安装

wget http://download.redis.io/releases/redis-4.0.8.tar.gz
tar xzf redis-4.0.8.tar.gz
mv redis-4.0.8 /home/user/app
cd /home/user/app/redis-4.0.8
make
ln -s /home/user/app/redis-4.0.8 /usr/local/redis
chown -R user:user /user/local/redis

如果make失败,可能是没有安装gcc

yum install gcc
yum install gcc-c++

如果报

zmalloc.h:50:31: error: jemalloc/jemalloc.h: No such file or directory
zmalloc.h:55:2: error: #error "Newer version of jemalloc required"
make[1]: *** [adlist.o] Error 1
make[1]: Leaving directory `/data0/src/redis-2.6.2/src'
make: *** [all] Error 2

在README中有一段话

Allocator  
---------  
 
Selecting a non-default memory allocator when building Redis is done by setting  
the `MALLOC` environment variable. Redis is compiled and linked against libc  
malloc by default, with the exception of jemalloc being the default on Linux  
systems. This default was picked because jemalloc has proven to have fewer  
fragmentation problems than libc malloc.  
 
To force compiling against libc malloc, use:  
 
    % make MALLOC=libc  
 
To compile against jemalloc on Mac OS X systems, use:  
 
    % make MALLOC=jemalloc

说关于分配器allocator, 如果有MALLOC  这个 环境变量, 会有用这个环境变量的 去建立Redis。
而且libc 并不是默认的 分配器, 默认的是 jemalloc, 因为 jemalloc 被证明 有更少的 fragmentation problems 比libc。
但是如果你又没有jemalloc 而只有 libc 当然 make 出错。 所以加这么一个参数。

即执行 make MALLOC=libc

注:chown 需要用root权限

1.1 使用yum安装

#设置Redis的仓库地址
yum install epel-release
yum install redis
#启动 redis,到此完成
service redis start

#开机自启
chkconfig redis on
1.2 设置密码

redis.conf 关键字 requirepass foobared

2.启动

服务端

cd /usr/local/redis/src
./redis-server

客户端

cd /usr/local/redis/src
./redis-cli

如果需要远程访问 需要修改redis.conf 注释掉ping 127.0.0.1

./src/redis-server redis.conf 

2.1 开机自启

www.cnblogs.com/zuidongfeng…

3.快速开始

redis有五种对象:字符串、列表、集合、散列、有序集合

1.字符串

GET 获取存储给定键
SET 存储给定键的值
DEL 获取存储给定键
INCR 将键存储的值加一
DECR 将键存储的值减一
INCRBY 将键存储的值加上整数amount
DECRBY 将键存储的值减上整数amount
INCRBYFLOAT 将键存储的值加上浮点数amount

2.散列

存储多个键值对之间的映射

HGET 获取散列键的值
HSET 在散列里面关联器给定的键值对
HDEL 如果给定键存在于散列里面,那么移除这个键
HEXISTS 检查给定键是否存在于散列中
HKEYS 获取散列包含的所有键
HVALS 获取散列包含的所有值
HGETALL 获取散列
HVALS 获取散列包含的所有值
hset hash-key(键名) sub-key1(键) value1(与键关联的值)

sub-key1 是无序排列的

3.列表

一个列表结构可以有序地存储多个字符串

RPUSH(LPUSH) 将给定值推入列表的右(左)端
LRANGE 获取列表在给定范围上的所有值
LINDEX 获取列表在给定位置上的单个元素
LPOP(RPOP) 从列表的左(右)端弹出一个值,并返回被弹出的值
LTRIM 从列表的左(右)端弹出一个值,并返回被弹出的值

4.集合

集合和列都可以存储多个字符串,不同在于:列表可以存储多个相同的字符串,而集合则通过使用散列表来保证自己存储的每个字符串各不相同

SADD 将给定元素添加到集合
SMEMBERS 返回集合包含的所有元素
SISMEMBER 检查给定元素释放存在于集合中
SREM 如果给定的元素存在于集合中,那么移除这个元素

5.有序集合

有序集合和散列一样,都用于存储键值对:有序集合的键被称为成员(member),每个成员不同;有序集合的值则被称为分值(score),分值必须是浮点数

ZADD 将一个带有给定分值的成员添加到有序集合里面
ZRANGE 根据元素在有序排列中所处的位置,从有序集合里面获取多个元素
ZRANGEBYSCORE 获取有序集合在给定分值范围内的所有元素
SREM 如果给定的元素存在于集合中,那么移除这个元素

3. 持久化

redis提供两种持久化方案 AOF(增量) 和 快照RDB(全量)

####3.1 AOF

appendonly no #开启aof特性,这个控制是否启用aof
appendfsync everysec  #每次有数据修改发生时都会写入AOF文件
#其余两种方式 everysec可以替换为 always 和 no
# 每次有数据修改发生时都会写入AOF文件 以及 由操作系统来决定应该合适进行同步

no-appendfsync-on-rewrite no 
#执行bgrewriteaof操作和主进程写aof文件的操作,两者都会操作磁盘,而bgrewriteaof
#往往会涉及大量磁盘操作,这样就会造成主进程在写aof文件的时候出现阻塞的情形,现
#在no-appendfsync-on-rewrite参数出场了。如果该参数设置为no,是最安全的方式,不
#会丢失数据,但是要忍受阻塞的问题。如果设置为yes呢?这就相当于将appendfsync设置#为no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为#没有竞争磁盘),但是如果这个时候redis挂掉,就会丢失数据。丢失多少数据呢?在linux
#的操作系统的默认设置下,最多会丢失30s的数据

auto-aof-rewrite-percentage 100
#aof文件增长比例,指当前aof文件比上次重写的增长比例大小。aof重写即在aof文件在
#一定大小之后,重新将整个内存写到aof文件当中,以反映最新的状态(相当于bgsave)。
#这样就避免了,aof文件过大而实际内存数据小的问题(频繁修改数据问题)
auto-aof-rewrite-min-size 64mb
dir ./

随着Redis 不断的运行,AOF文件的体积也会不断的增长,可以通过向Reids 发送BGREWRITEAOF命令,这个命令会通过移除AOF文件中的冗余命令来重写(rewrite)AOF文件,使用AOF文件的体积变得尽可能地小; BGREWRITEAOF 的工作原理和BGSAVE 创建快照相似:Reids 会创建一个子进程,然后由子进程重写AOF文件 注:如果不加以控制,AOF文件的体积可能会比快照文件的体积大好几倍,在进行AOF重写并删除旧AOF文件的时候,删除一个体积达到数十GB大的旧AOF文件会导致操作系统挂起(hang)数秒

3.2 RDB

save 60 1000  #表示在60秒(1分钟)之后如果至少有10000个key发生变化则dump内存快照
stop-writes-on-bgsave-error no #在创建快照失败后是否仍然继续执行命令
rdbcompression yes #是否对快照进行压缩
dbfilename dump.rdb
dir ./
3.2.1 创建快照的三种方式
  1. 客户端可以通过向Redis发送BGSAVE 命令来创建一个快照.对于支持BGSAVE命令的平台(即除Windows外),Reids 会调用fork来创建一个子进程,然后子进程负责将快照写入硬盘,而父进程继续处理命令请求

  2. 客户端还可以通过向Redis 发送SAVE 命令来创建一个快照,接到SAVE命令的Redis服务器在快照创建完毕之前将不再响应任何其他命令,SAVE 一般只有在内存不足去执行BGSAVE的情况下使用

  3. save 配置选项比如 save 60 10000,表示 60秒内有10000次写入,Redis 会自动触发BGSAVE 命令。如果用户配置多个save配置,则当任意一个save 配置选项所设置的条件被满足时,Redis就会触发一次BGSAVE 命令

  4. 当Redis 通过SHUTDOWN命令接收到关闭服务器 的请求时,或者接收到标准TERM信号时,会执行一个SAVE命令,阻塞所有客户端,不再执行客户端发送的命令,并在SAVE 命令执行完毕后关闭服务器

  5. 当Redis服务连接另一个Redis服务器,并向对方发送SYNC 命令来开始一次复制操作的时候,如果主服务器目前没有执行BGSAVE 操作,或者主服务器并非刚刚执行完BGSAVE,主服务器就会执行BGSAVE命令

4. 复制

#redis.conf 开启 从服务器 ,更加IP地址和端口连接主服务器
slaveof host port

也可以发送命令

SLAVEOF no one #让服务终止复制操作
SLAVEOF host port # 让服务开始复制一个新的主服务器

4.2 复制的操作原理

主服务器操作

  • 1.等待命令进入
  • 2.开始执行BGSAVE,并使用缓冲区记录BGSAVE 之后执行的所有命令
  • 3.BGSAVE 执行完毕,向从服务器发送快照文件,并在发送期间继续使用缓冲区记录被执行的写命令
  • 4.快照文件发送完毕,开始向服务器发送存储在缓冲区记录被执行的写命令
  • 5.缓冲区存储的写命令发送完毕;从现在开始每执行一个写命令,就向从服务器发送相同的写命令

从服务器操作

  • 1.连接(或者重连)主服务器,发送SYNC 命令
  • 2.根据配置选项来决定是继续使用现有的数据(如果有的话)来处理客户端的命令请求,还是发送请求的客户端返回错误
  • 3.丢弃所有旧数据(如果有的话) ,开始载入主服务器发来的快照文件
  • 4.完成对快照文件的解释操作,像往常一样开始接受命令请求
  • 5.执行主服务器发来的所有存储在缓冲去里面的写命令;并从现在开始,接收并执行主服务器传来的的每个写命令

注:让主服务器只使用50%~65%的内存,留下30%~45%的内存用于执行BGSAVE命令和创建记录写命令的缓冲区

4.2.1 验证快照文件和AOF文件
#检查 AOF文件和快照文件的状态
redis-check-aof [--fix]
redis-check-dump

5 内存回收

5.1 Maxmemory 配置命令

通过设置Maxmemory限制内存大小 通过redis.conf 或者 CONFIG SET 进行配置

5.2 回收策略

内存超过Maxmemory限制时Redis会根据 maxmemory-policy配置指令来进行配置

  • 1.noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
  • 2.allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
  • 3.volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
  • 4.allkeys-random: 回收随机的键使得新添加的数据有空间存放。
  • 5.volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。 volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

2.集群

1.replication 主从架构

2.哨兵(Sentinel)

哨兵的主要功能

    1. 集群监控,负责redis master和slave进程是否正常工作
    2. 消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
    3. 故障转移,master node挂掉了,会自动转移到slave node
    4. 配置中心,如果故障转移发送,通知client客户端新的master地址
  1. 哨兵至少需要3个实例,来保证自己的健壮性
  2. 哨兵 + redis主从的部署架构,不保证数据零丢失,智能保证redis集群的高可用性
  3. 至少需要部署三个节点(类似zk)
1. 脑裂导致数据丢失

哨兵,salve无法与master进行通信,但client还在给master写数据 ;

2.异步复制数据丢失

主从切换的时候,master节点可能会有数据没能及时同步到slave

(对 client 做降级,在自己内存中做缓存(第三方,如kafka),等待master恢复)

以下两个参数减少异步复制和脑裂的数据丢失

#要求至少一个slave,数据复制和同步延迟不能超过10秒
#如果所有的的slave的数据复制和同步的延迟都超过了10秒钟,master就不会再接收任何请求
min-slaves-to-write 1
min-slaves-max-lag 10
3.sdown和odown转换机制

两种失败状态

sdown是主观状态,如果一个哨兵自己觉得master宕机了,那么就是主观宕机

sdown达成条件,当一个哨兵ping一个master,超过了is-master-down-after-milliseconds指定的毫秒数,就认为是master宕机

odown是客观状态,如果quorum数量的哨兵觉得一个master宕机了,那么就是客观宕机

当一个哨兵收到了quorum指定数量的哨兵都认为master是sdown,则认为master是odown

4.哨兵和slave集群的自动发现机制

哨兵之间的通信是通过redis的pub/sub系统实现的,每个哨兵都会在

_sentinel_:hello

Channel 里发送一个消息,内容包括

  • host
  • ip
  • runid
  • master的监控配置

每个哨兵还会跟其他哨兵交换对master的监控配置,互相进行监控配置的同步

5.slave配置的纠错
6.slave->master选举算法
  • 跟 master 断开连接的时间
  • slave 优先级
  • 复制offset
  • run id

如果slave跟master断开连接已经超过了 down-after-milliseconds的10 倍+master宕机 的时长,则这个slave就不会被选举为master

接下来按照以下规则排序

  • 按照slave的优先级(slave-priority越低,优先级就越高)
  • 如果slave-priority相同,那么看replica offset,offset越靠后,优先级就越高
  • 如果slave-priority相同,则run id 小的那个slave
7.quorum和majority

每次一个哨兵要做主备切换,首先需要quorum数量的哨兵认为odown,然后选举出一个哨兵来做切换,这个哨兵还得得到majority哨兵的授权,才能正式执行切换

如果quorum < majority,比如5个哨兵,majority就是3,quorum设置为2,那么就3个哨兵授权就可以执行切换

但是如果quorum >= majority,那么必须quorum数量的哨兵都授权,比如5个哨兵,quorum是5,那么必须5个哨兵都同意授权,才能执行切换

8.configuration epoch

哨兵会对一套redis master+slave进行监控,有相应的监控的配置

执行切换的那个哨兵,会从要切换到的新master(salve->master)那里得到一个configuration epoch,这就是一个version号,每次切换的version号都必须是唯一的

如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待failover-timeout时间,然后接替继续执行切换,此时会重新获取一个新的configuration epoch,作为新的version号

9.configuraiton传播

哨兵完成切换之后,会在自己本地更新生成最新的master配置,然后同步给其他的哨兵,就是通过之前说的pub/sub消息机制

这里之前的version号就很重要了,因为各种消息都是通过一个channel去发布和监听的,所以一个哨兵完成一次新的切换之后,新的master配置是跟着新的version号的

其他的哨兵都是根据版本号的大小来更新自己的master配置的

3.cluster

3.应用