redis
一、Redis与Mencached对比
Redis是一个开源的、使用C语言编写的、支持网络交互的、可基于内存(基于内存的这个特点,说明Reids的速度是极快的)也可持久化的Key-Value数据库。
官方的一个简单测试。测试完成了50个并发执行100000个请求。
设置和获取的值是一个256字节字符串。
结果:读的速度是110000次/s,写的速度是81000次/s
Redis与Memcached对比
| Memcached | Reids | |
| 类型 | Key-Value数据库 | Key-Value数据库 |
| 过期策略 | 支持 | 支持 |
| 数据类型 | 单一数据类型 | 五种数据类型 |
| 持久化 | 不支持 | 支持 |
| 主从复制 | 不支持 | 支持 |
| 虚拟内存 | 不支持 | 支持 |
二、Redis的安装
redis在linux中玩最佳,在linux中下载(如果在windows下玩Linux,那简直就是对redis的侮辱)
wget http://download.redis.io/releases/redis-4.0.8.tar.gz
cp redis-4.0.8.tar.gz /opt/
cd /opt/
tar xzf redis-4.0.8.tar.gz
cd redis-4.0.8
make install(因为是c语言开发的,所以需要操作系统的支持,需要编译)
这样将会在/usr/local/bin/目录下生成有启动的redis-server 和 redis-cli等
redis的配置文件在/opt/redis-4.0.8/目录下
我们可以cp一份redis.conf配置文件至另一处,然后可以修改配置文件中的参数
启动redis-server /myredis/redis.conf 注意想要后台启动server 修改配置文件的daemonize yes(以后台进程启动)
连接redis-cli -p 6379
关闭redis-cli -p 6379 shutdown
如果觉得这样的启动方式需要切换到/usr/local/bin/目录下麻烦,我们可以使用ln -s 源文件 目标文件的连接方式链接到/usr/bin目录下,这样可以直接启动命令脚本,而不用切换到指定目录下
ln -s /usr/local/bin/redis-server /usr/bin/redis-server
ln -s /usr/local/bin/redis-cli /usr/bin/redis-cli
三、Redis的基础
1.配置文件
daemonize yes 后台启动(这个我们都以后台进程的方式启动)
logfile '' 默认是没有的(我们应该在此处配置一个路径)
databases 16 默认是16个数据库的
dir ./ 持久化文件存放的路径
2.基本命令
set key value
get key
exists key
del key
keys */a*
type key
info 当前数据库的所有状态信息
select num切换数据库
incr key 如果key不存在,默认为我们创建一个key,其默认value=0
incrby key num
3.五大数据类型
可以使用help + tab键查看帮助
- String
- set key value
- get key
- del key
- append key value
- strlen key
- incr/decr key(如果value不为integer类型的话,会报错)
- incrby/decrby key num
hash(底层使用hash结构,说明其在查找的时候是相对来说比较快的)
- hset key field value
- hget key field
- hdel key field
- hgeall key
- lpush key value1 value2 value3
- rpush key value1 value2 value3
- lpop key
- rpop key
- llen key
- lindex key num
- lrange key start end /0 -1就是遍历
- ltrim key start end 截取 start end之间 比如写日志的时候,只保存一部分的日志信息
- sadd key value1 value2 value3
- srem key value 判断某个value是否存在
- smembers key
- sismenber key value 判断某个value是否在某个集合里
- sdiff key1 key2
- sinter key1 key2
- sunion key1 key2
- zset 有序集合
zadd key member
zrem key member
smembers key
sismenber key member
sdiff key1 key2
sinter key1 key2
sunion key1 key2
四、Redis的持久化
1、rdb(快照)(默认)
在配置文件中的配置信息
save 900 1
save 300 10
save 60 10000
fork一个子进程,然后写入一个临时文件中,写完了之后,临时文件再与rdb文件替换。主进程不会进行任何IO操作,保证了redis的高性能。因此rdb文件确保一定是可用的。
如果禁用此种方式的话,将上面的三个save注释掉即可。
1.rbd文件是经过压缩的二进制文件,所以我们是看不了的。
2.如果禁用的话。直接把save 给注释掉
3.对于异常退出的话,会丢失快照以后的数据,但是如果正常关闭的话,redis会自动自动添加至快照中。
优点:
持久化成一个二进制文件,特别好备份
缺点:
rdb是间隔一段时间持久化的,如果在两次持久化间隔时间内,redis发送故障宕机的话,那么这个间隔时间段的数据会丢失。
所以这种方式更适合存放一些对数据要求不是那么严谨的时候。
2、aof(append-only file)
也是fork一个子进程,主进程仍向外提供服务,子进程负责执行AOF持久化,与rdb不同的是,后台子进程持久化过程中,主进程会记录该期间所有的数据变更,并存储在server.aof_rewrite_buf_blocks中。后台子进程结束后,redis会更新缓存并追加到
aof文件中。
aof文件中存放的是一些数据变更的指令,如set xxx vvv。对于一些查询的操作记录aof文件中并不会记录。
配置参数
appendfsync everysec
appendfsync no
appendfsync always
这三个参数的作用?
大多数unix系统为了减少磁盘IO,都采用了“延迟写”技术,也就是说当我们执行完write调用后,数据并不一定立马被写入磁盘(可能还是保留在系统的buffer cache或者page cache中),这样当主机突然断电,这些我们本以为已经写入到磁盘文件的数据
可能就会丢失;所以当我们需要确保数据被完整正确的写入磁盘(譬如数据库的持久化),则需要调用同步函数fsync,它会一直阻塞直到数据全部被写入到硬盘。
上面三个参数就是用来指定flush策略
no:完全依赖于操作系统自动sync,因此不能保证数据的完整性
always:每次写入文件都会调用fsync,这种虽然保证了数据的完整性,但是性能太差(因为fysnc是个同步调用,会阻塞主进程对客户端请求的处理)
everysec:定期(至少1s)去调用fsync,并且该操作是放到一个异步队列中(线程)去执行,因此不会阻塞主进程
AOF文件越来越大?怎么优化?
AOF协议本身是文本协议,所以相对rdb的二进制文件来说是比较占空间的。
redis需要记录从开始一直到现在的所有更新命令
优化策略:AOF_REWRITE.(原理就是对于aof中的更新命令进行优化,比如说set key value,后面又对该Key进行了很多的操作,但是我们只需要记住value的最后一个值即可,中间的那些更新指令我们更本不用记。这样会大大减小磁盘空间的使用)
在配置文件中
auto-aof-rewrite-min-size 64mb,
auto-aof-rewrite-percentage 100,
当达到这两个阙值就会AOF_REWRITE来优化AOF文件(这是被动触发,还有一种主动触发,就是调用BAREWRITEAOF命令)
AOF_REWRI触发条件
1.被动:当AOF文件尺寸超过REDIS_AOF_REWRITE_MIN_SIZE & 达到一定增长比; 也就是上面配置的两个
注意:此时主进程是不能向外提供服务的
2.主动:调用BAREWRITEAOF命令
注意:此时主进程并没有停止对外提供服务
AOF_REWRITE过程
最重要的一个函数:rewriteAppendOnlyFile,它主要做了下面的事情:
创建一个临时文件temp-rewriteaof-pid.aof;
循环所有数据库,把每一个数据库中的键值对,按照aof协议写入临时文件;
重命名临时文件
当AOF_REWRITE过程执行完毕,Redis会用新生成的文件取替换原来的AOF文件,支持AOF_REWRITE过程完毕。
对于主动调用AOF_REWRITE存在的问题:
如果我们通过主动方式去执行AOF_REWRITE,那么在保存AOF问价期间,"键空间"是可能发送变化的(因为主进程并没有被阻塞,他是通过子进程完成的,主进程还可以提供服务),若直接使用新的生成文件取替换原来的AOF文件,就会造
成数据的不一致性(丢失在AOF_REWRITE过程中更新的数据)
redis如何解决这个问题的呢?
如果redis检测到有一个子进程正在进行AOF_REWRITE的话,那么它会把这期间所有的变更命令写到AOF重写缓存(aof_rewrite_buf_blocks),然后当子进程完成AOF_REWRITE后,它会再把AOF重写缓存中的内容追加到新生成的文件,
这样我们就可以保证数据的一致性,避免这个问题。
3、总结
可以通过配置文件来指定他们中的一种,或者同时使用他们(不建议同时使用),或者全部禁用,在架构良好的环境中,master通常使用
AOF,slace使用snapshot,主要原因是master需要确保数据完整性,它作为数据备份的第一选择;slave提供只读服务(目前slave只提供
读取服务),它的主要目的就是快速响应客户端read请求;但是如果你的redis运行在网络稳定性差/物理环境糟糕情况下,建议你master
和slave均采取AOF,这个在master和slave角色切换时,可以减少“人工数据备份”/“人工引导数据恢复”的时间成本;如果你的环境一切
非常良好,且服务需要接收密集性的write操作,那么建议master采取snapshot,而slave采用AOF。
五、Redis的主从复制
Redis虽然读取写入的速度都特别快,但是也产生读压力特别大的情况。为了分担读压力,Redis支持主从复制,Redis的主从结构可以采用一主多从或者级联结构。在slave客户端 SLAVEOF 127.0.0.1 6380或者在配置文件中配置。通过info可以查看信息.
1、全量哦同步和增量同步
全量同步:
Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的目前拥有的数据复制一份。具体步骤如下
1)从服务器连接到主服务器,发送SYNC命令
2)主服务器接收到SYNC命令后,开始执行BGSAVE命令生成RDB文件,并使用缓冲去记录此后执行的所有更新命令
3)主服务BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续执行记录被执行的写命令
4)从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
5)主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
Redis的增量同步
增量复制是指Slave初始化执行后开始正常工作是主服务器发送的写操作同步到从服务器的过程。增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。
2、哨兵模式
2.6版本引入了哨兵模式,但是不稳定,2.8版本之后哨兵模式才稳定起来
Redis的哨兵模式就是对redis系统进行实时的监控,其主要功能有下面两点
1.检测主数据库和从数据库是否正常运行
2.当我们的主数据库出现故障的时候,可以自动将从数据库转换为主数据库,实现自动的切换。
配置一个sentinel.conf。
sentinel monitor master 127.0.0.1 6380 1
还可以配置其他的一些参数,具体百度
启动监控
redis-server sentinel.conf --sentinel
就会自动监控,类似于mongodb中的裁判节点。
六、Redis的集群(3.0之后才支持的)
Redis Cluster分区实现原理
槽(slot)概念
Redis cluster中有一个16384长度的槽的概念,他们的编号为0、1、2、3……16382、16383。这个槽是一个虚拟的槽,并不是真正存在的。正常工作的时候,Redis Cluster中的每个Master节点都会负责一部分的槽,当有某个key被映
射到某个Master负责的槽,那么这个Master负责为这个key提供服务,至于哪个Master节点负责哪个槽,这是可以由用户指定的,也可以在初始化的时候自动生成(redis-trib.rb脚本)。这里值得一提的是,在Redis Cluster中,只有Master
才拥有槽的所有权,如果是某个Master的slave,这个slave只负责槽的使用,但是没有所有权。Redis Cluster怎么知道哪些槽是由哪些节点负责的呢?某个Master又怎么知道某个槽自己是不是拥有呢?
在redis-cluster集群中,他们的任何两个节点之间都是相互连通的。客户端可以与任何一个节点相连接,然后就可以访问集群中的任何一个节点。对其进行存取和其他操作。
那么Redis是怎么做到的呢?
首先,在redis的每一个节点上,都有这么两个东西,一个是插槽(slot)可以理解为是一个可以存储两个数值的一个变量这个变量的取值范围是:0-16383。还有一个就是cluster我个人把这个cluster理解为是
一个集群管理的插件。当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,
去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
还有就是因为如果集群的话,是有好多个redis一起工作的,那么,就需要这个集群不是那么容易挂掉,所以呢,理论上就应该给集群中的每个节点至少一个备用的redis服务。这个备用的redis称为从节点(slave)。那么这个集群是如何判断是否有某个 节点挂掉了呢?
首先要说的是,每一个节点都存有这个集群所有主节点以及从节点的信息。
它们之间通过互相的ping-pong判断是否节点可以连接上。如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了,然后去连接它的备用节点。如果某个节点和所有从节点全部挂掉,我们集群就进入faill状态。还有就是 如果有一半以上的主节点宕机,那么我们集群同样进入发力了状态。这就是我们的redis的投票机制,
(1)投票过程是集群中所有master参与,如果半数以上master节点与master节点通信超时(cluster-node-timeout),认为当前master节点挂掉.
(2):什么时候整个集群不可用(cluster_state:fail)?
a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完整时进入fail状态. ps : redis-3.0.0.rc1加入cluster-require-full-coverage参数,默认关闭,打开集群兼容部分失败.
b:如果集群超过半数以上master挂掉,无论是否有slave,集群进入fail状态.
集群配置
绑定地址:bind 192.168.XXX.XXX。不能绑定到127.0.0.1或localhost,否则指导客户端重定向时会报”Connection refused”的错误。
开启Cluster:cluster-enabled yes
集群配置文件:cluster-config-file nodes-7000.conf。这个配置文件不是要我们去配的,而是Redis运行时保存配置的文件,所以我们也不可以修改这个文件。
集群超时时间:cluster-node-timeout 15000。结点超时多久则认为它宕机了。
槽是否全覆盖:cluster-require-full-coverage no。默认是yes,只要有结点宕机导致16384个槽没全被覆盖,整个集群就全部停止服务,所以一定要改为no
后台运行:daemonize yes
输出日志:logfile "./redis.log"
监听端口:port 7000
redis-trib管理器
redis-trib依赖Ruby和RubyGems,以及redis扩展。
最简便的方法就是用apt或yum包管理器安装RubyGems后执行gem install redis。
启动6个实例redis服务 redis-server 启动
6个实例还没有形成集群,现在使用redis-trb.rb管理脚本建立起集群。redis-trib默认用前3个实例作为Master,后3个作为Slave。因为Redis基于Master-Slave做数据备份,而非像Cassandra或Hazelcast一样不区分结点角色,
自动复制并分配Slot的位置到各个结点。
edis-trib.rb create --replicas 1 192.168.1.100:7000 192.168.1.100:7001 192.168.1.100:7002 192.168.1.100:7003 192.168.1.100:7004 192.168.1.100:7005
简单测试
启动redis-cli时要加-c选项,存取两个Key-Value感受一下Redis久违的集群功能。
redis-cli -c -h 192.168.1.100 -p 7000

浙公网安备 33010602011771号