概述
redis是一个开源的、使用C语言编写的、支持网络交互的、可基于内存也可持久化的Key-Value的nosql数据库 特点
Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用 Redis不仅仅支持简单的key-value类型的数据,同时还提供String,list,set,zset,hash等数据结构的存储 Redis支持数据的备份,即master-slave模式的数据备份 优点
redis是单线程的,速度快,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) 支持丰富数据类型,支持string,list,set,sorted set,hash 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除 重要的可执行文件
redis-server:Redis服务器程序 redis-cli:Redis客户端程序,它是一个命令行操作工具。也可以使用telnet根据其纯文本协议操作 redis-benchmark:Redis性能测试工具,测试Redis在你的系统及配置下的读写性能 redis加锁
第一种锁命令INCR
key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作进行加一。 然后其它用户在执行 INCR 操作进行加一时,如果返回的数大于 1 ,说明这个锁正在被使用当中。 incr($key) 第二种锁SETNX
如果 key 不存在,将 key 设置为 value 如果 key 已存在,则 SETNX 不做任何动作 setNX($key, $value) 第三种锁SET
上面两种方法都需要设置 key 过期 set($key, $value, array(‘nx’, ‘ex’ => $ttl)); //ex表示秒
基本命令
启动redis服务:redis-server 配置文件地址 进入数据库:redis-cli -h host -p port -a password 退出服务:shutdown 退出数据库:exit 测试数据库:ping(回复pong) 切换数据库:select 数据库角标(默认为0-15) 帮助命令:help @generic 删除数据库:flushdb 删除全部数据库库:flushAll 清屏(cmd窗口):clear 查看当前数据库的key数量:Dbsize
key键命令
查看指定 key 的值:get key 查看所有key:keys * 查看key类型:type key 查看所有符合给定模式(pattern)的key:keys pattern 查看key剩余生存时间,-1表示永不过期,-2表示已过期,以秒为单位:ttl key 查看key剩余生存时间,以毫秒为单位返:pttl key 设置过期时间,以秒计:expire key seconds 删除指定 key-value 键值对:del key 移除当前库:move key db 判断 key 是否存在: exists key1 key2 …
String类型命令
帮助命令:help @string 设置指定 key 的value值:set key value(key值存在则替换) 设置指定 key 的存活时间:set key value ex 秒(px是毫秒) 获取指定 key 的value值:get key 获取指定 key 的value长度:strlen key 若 key 不存在时设置 key 的value值:setnx key value 截取字符串:getrange key start end 追加字符串:append key value 设置指定 key 的value值,返回原来的值(无则返回nil):getset key value 同时设置一个或多个 key-value 对:mset key value [key value …] 获取所有(一个或多个)给定 key 的值:mget key1 [key2…] 将 key 中储存的数字值增一:incr key 将 key 所储存的值加上给定的增量值(increment):incrby key increment 将 key 中储存的数字值减一:decr key 将 key 所储存的值减去给定的减量值(decrement):decrby key
List类型命令:列表
获取列表长度:llen key 获取列表指定范围内的元素:lrange key start stop 通过索引获取列表中的元素:lindex key index 通过索引设置列表元素的值:lset key index value 将一个值插入到已存在的列表头部:lpushx key value 将一个值插入到已存在的列表尾部:rpushx key value 将一个或多个值插入到列表头部:lpush key value1 [value2] 将一个或多个值插入到列表尾部:rpush key value1 [value2] 在列表的元素前或者后插入元素:linsert key before|after pivot value 移出并获取列表的第一个元素:lpop key 移出并获取列表的最后一个元素:rpop key 移除列表元素:lrem key count value(count>0从表头移除count个value,count>0从表尾移除count个value,count=0则移除所有value) 截取列表:ltrim key start end(负数则反向计数截取) 总结:
set类型命令:集合
获取集合的成员数:scard key 获取给定所有集合的交集:sinter key1 [key2] 获取给定所有集合的并集:sunion key1 [key2] 获取第一个集合与其他集合之间的差集:sdiff key1 [key2] 获取集合中的所有成员:smembers key 判断 member 元素是否是集合 key 的成员:sismember key member 获取集合中一个或多个随机数:srandmember key [count] //count为负则取出数可为重复值 向集合添加一个或多个成员:sadd key member1 [member2] 移除集合中一个或多个成员:srem key member1 [member2] 移除并返回集合中的一个随机元素:spop key 将key1里的某个值赋给key2:smove key1 key2
zset类型命令:在set基础上,加一个score值(set是k1 v1 v2,zset是k1 score1 v1 score2 v2)
通过索引区间获取有序集合指定区间内的成员:zrange key start stop [withscores] 通过分数获取有序集合指定区间内的成员:zrangebyscore key min max [withscores] [limit] 获取有序集合的成员数:zcard key 获取有序集合中指定成员的索引:zrank key member 获取在有序集合中指定区间分数的成员数:zcount key min max 向有序集合添加一个或多个成员,或者更新已存在成员的分数:zadd key score1 member1 [score2 member2] 移除有序集合中的一个或多个成员:zrem key member [member …] 添加一个或多个成员,或者更新已存在成员的分数:zadd key score1 member1 [score2 member2] 逆序获取有序集合中指定成员的排名:zrevrank key values 获取有序集中指定区间内的成员,通过索引,分数从高到低:zrevrange key start stop [withscores] 获取有序集中指定分数区间内的成员,分数从高到低排序:zrevrangebyscore key max min [withscores]
Hash类型命令:KV模式不变,但V是一个键值对
删除一个或多个哈希表字段:hdel key field1 [field2] 判断哈希表 key 中,指定的字段是否存在:hexists key field 获取存储在哈希表中指定字段的值:hget key field 获取所有给定字段的值:hmget key field1 [field2] 同时将多个 field-value (域-值)对设置到哈希表 key 中:hmset key field1 value1 [field2 value2 ] 获取在哈希表中指定 key 的所有字段和值:hgetall key 获取所有哈希表中的字段:hkeys key 获取哈希表中字段的数量:hlen key 获取哈希表中所有值:hvals key 设置哈希表 key 中的字段 field 的值为 value:hset key field value 为哈希表 key 中的指定字段的整数值加上增量 increment:hincrby key field increment 为哈希表 key 中的指定字段的浮点数值加上增量 increment:hincrbyfloat key field increment 若字段 field 不存在时,设置哈希表字段的值:hsetnx key field value
配置文件
修改前请先备份 开头部分:定义基本的度量单位,只支持bytes,不支持bit,对大小写不敏感 include包含部分:导入其他文件 general通用部分
daemonize:用来指定redis是否要用守护线程的方式启动,设置成yes时,代表开启守护进程模式。在该模式下,redis会在后台运行,并将进程pid号写入至redis.conf选项pidfile设置的文件中,此时redis将一直运行,除非手动kill该进程 pidfile:当Redis 在后台运行的时候,Redis 默认会把pid 文件放在/var/run/redis.pid,你可以配置到其他地址。当运行多个redis 服务时,需要指定不同的pid 文件和端口 port:监听端口,默认为6379 tcp-backlog:连接队列,backlog队列总和=未完成三次握手队列 + 已经完成三次握手队列,在高并发环境下你需要一个高backlog值来避免慢客户端连接问题,Linux内核会将这个值减小到/proc/sys/net/core/somaxconn的值,所以需要确认增大somaxconn和tcp_max_syn_backlog两个值来达到想要的效果 bind:指定Redis 只接收来自于该IP 地址的请求,如果不进行设置,那么将处理所有请求,在生产环境中为了安全最好设置该项。默认注释掉,不开启 timeout:设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接 tcp-keepalive: 指定TCP连接是否为长连接,"侦探"信号有server端维护。默认为0.表示禁用 loglevel:log 等级分为4 级,debug,verbose, notice, 和warning。生产环境下一般开启notice logfile:配置log 文件地址,默认使用标准输出,即打印在命令行终端的窗口上,修改为日志文件目录 syslog-enabled:是否把日志输出到syslog中 syslog-ident:指定syslog里的日志标志 syslog-facility:指定syslog设备,值可以是USER或LOCAL0-LOCAL7 databases:设置数据库的个数,可以使用SELECT 命令来切换数据库。默认使用的数据库是0号库。默认16个库 SNAPSHOTTING快照部分
save:保存数据快照的频率,即将数据持久化到dump.rdb文件中的频度。用来描述"在多少秒期间至少多少个变更操作"触发snapshot数据保存动作,RDB是整个内存的压缩过的Snapshot,RDB的数据结构,可以配置复合的快照触发条件,默认是1分钟内改了1万次,或5分钟内改了10次,或15分钟内改了1次
如果想禁用RDB持久化的策略,只要不设置任何save指令,或者给save传入一个空字符串参数也可以 stop-writes-on-bgsave-error:如果配置成no,表示你不在乎数据不一致或者有其他的手段发现和控制 rdbcompression:rdbcompression:对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能 rdbchecksum: 是否校验rdb文件。在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能 dbfilename:指定本地数据库文件名,一般采用默认的 dump.rdb dir /usr/local/redis/var:数据目录,数据库的写入会在这个目录。rdb、aof文件也会写在这个目录 REPLICATION复制部分
slaveof < masterip> < masterport>:设置该数据库为其他数据库的从数据库,并为其指定master信息 masterauth:当主数据库连接需要密码验证时,在这里指定 slave-serve-stale-data yes:当主master服务器挂机或主从复制在进行时,是否依然可以允许客户访问可能过期的数据。在"yes"情况下,slave继续向客户端提供只读服务,有可能此时的数据已经过期;在"no"情况下,任何向此server发送的数据请求服务(包括客户端和此server的slave)都将被告知"error" slave-read-only yes:slave是否为"只读",强烈建议为"yes" repl-ping-slave-period 10:slave向指定的master发送ping消息的时间间隔(秒),默认为10 repl-timeout 60:slave与master通讯中,最大空闲时间,默认60秒.超时将导致连接关闭 repl-disable-tcp-nodelay no:是否禁止复制tcp链接的tcp nodelay参数,可传递yes或者no。默认是no,即使用tcp nodelay。如果master设置了yes来禁止tcp nodelay设置,在把数据复制给slave的时候,会减少包的数量和更小的网络带宽。但是这也可能带来数据的延迟。默认我们推荐更小的延迟,但是在数据量传输很大的场景下,建议选择yes SECURITY安全部分
requirepass foobared:requirepass配置可以让用户使用AUTH命令来认证密码,才能使用其他命令。这让redis可以使用在不受信任的网络中。为了保持向后的兼容性,可以注释该命令,因为大部分用户也不需要认证。使用requirepass的时候需要注意,因为redis太快了,每秒可以认证15w次密码,简单的密码很容易被攻破,所以最好使用一个更复杂的密码 rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52:把危险的命令给修改成其他名称。比如CONFIG命令可以重命名为一个很难被猜到的命令,这样用户不能使用,而内部工具还能接着使用 rename-command CONFIG “”:设置成一个空的值,可以禁止一个命令 LIMITS限制部分
maxclients:设置redis同时可以与多少个客户端进行连接。默认情况下为10000个客户端。当你无法设置进程文件句柄限制时,redis会设置为当前的文件句柄限制值减去32,因为redis会为自身内部处理逻辑留一些句柄出来。如果达到了此限制,redis则会拒绝新的连接请求,并且向这些连接请求方发出“max number of clients reached”以作回应 maxmemory:设置redis可以使用的内存量。一旦到达内存使用上限,redis将会试图移除内部数据,移除规则可以通过maxmemory-policy来指定。如果redis无法根据移除规则来移除内存中的数据,或者设置了“不允许移除”,那么redis则会针对那些需要申请内存的指令返回错误信息,比如SET、LPUSH等,但是对于无内存申请的指令,仍然会正常响应,比如GET等。如果你的redis是主redis(说明你的redis有从redis),那么在设置内存使用上限时,需要在系统中留出一些内存空间给同步队列缓存,只有在你设置的是“不移除”的情况下,才不用考虑这个因素 maxmemory-policy
volatile-lru:使用LRU算法移除key,只对设置了过期时间的键 allkeys-lru:使用LRU算法移除key volatile-random:在过期集合中移除随机的key,只对设置了过期时间的键 allkeys-random:移除随机的key volatile-ttl:移除那些TTL值最小的key,即那些最近要过期的key noeviction:不进行移除。针对写操作,只是返回错误信息 maxmemory-samples:设置样本数量,LRU算法和最小TTL算法都并非是精确的算法,而是估算值,所以你可以设置样本的大小,redis默认会检查这么多个key并选择其中LRU的那个 APPEND ONLY MODE追加部分
appendonly no:默认情况下,redis 会在后台异步的把数据库镜像备份到磁盘,但是该备份是非常耗时的,而且备份也不能很频繁。所以redis 提供了另外一种更加高效的数据库备份及灾难恢复方式。开启append only 模式之后,redis 会把所接收到的每一次写操作请求都追加到appendonly.aof 文件中,当redis 重新启动时,会从该文件恢复出之前的状态。但是这样会造成appendonly.aof 文件过大,所以redis 还支持了BGREWRITEAOF 指令,对appendonly.aof 进行重新整理。如果不经常进行数据迁移操作,推荐生产环境下的做法为关闭镜像,开启appendonly.aof,同时可以选择在访问较少的时间每天对appendonly.aof进行重写一次。另外,对master机器,主要负责写,建议使用AOF,对于slave,主要负责读,挑选出1-2台开启AOF,其余的建议关闭 appendfilename appendonly.aof:aof文件名字,默认为appendonly.aof appendfsync
always:同步持久化 每次发生数据变更会被立即记录到磁盘 性能较差但数据完整性比较好 everysec:出厂默认推荐,异步操作,每秒记录 如果一秒内宕机,有数据丢失 no:不主动fsync,由OS自己来完成 no-appendfsync-on-rewrite:重写时是否可以运用Appendfsync,用默认no即可,保证数据安全性。 auto-aof-rewrite-min-size:设置重写的基准值 auto-aof-rewrite-percentage:设置重写的基准值
持久化
RDB(Redis DataBase)
简介
RDB方式是通过快照完成的,当符合一定条件时Redis会自动将内存中的所有数据进行快照,并且存储到硬盘上。就像拍照一样,将这一瞬间的所有东西都保存下来。进行快照的条件在配置文件中指定。主要有两个参数构成:时间和改动的键值的个数,即当在指定时间内被更改的键的个数大于执行数值时,就会进行快照。RDB是Redis的默认持久化方式 在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里 Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。 Fork
fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程 使用fork来复制一份当前进程,那么子进程就会占有和主进程一样的内存资源,比如说主进程8G内存,那么在备份的时候必须保证有16G内存,要不然会启用虚拟内存,性能非常差。 RDB方式配置
设置触发条件:Redis的配置文件:redis.conf中设置save 设置rdb文件路径:默认rdb文件存放路径是当前目录,文件名是:dump.rdb。可以在配置文件中修改路径和文件名,分别是dir和dbfilename Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存,一般情况下1GB的快照文件载入到内存的时间大约20-30分钟
// /etc/redis/redis.conf 文件中
save 900 1 # 时间策略,服务器在900秒之内,对数据库进行了至少1次修改。
save 300 10 # 时间策略,服务器在300秒之内,对数据库进行了至少10次修改。
save 60 10000 # 时间策略,服务器在60秒之内,对数据库进行了至少1000次修改。
dbfilename dump.rdb #文件名称
dir /var/lib/redis #文件保存路径
stop-writes-on-bgsave-error yes # 如果持久化出错,主进程是否停止写入
rdbcompression yes # 是否压缩
rdbchecksum yes # 导入时是否检查
# 通过save 300 10次略,我们可以在5分钟内插入10个数据,到了五分钟发现的确生成了新的dump.rdb文件,说明配置生效
RDB的快照过程
Redis使用fork函数复制一份当前进程(父进程)的副本 父进程继续接受并处理客户端发来的命令,而子进程开始将内存中的数据写入到硬盘中的临时文件 当子进程写入完成所有数据后会用该临时文件替换旧的RDB文件 手动快照
如果没有触发自动快照,可以对redis进行手动快照操作,SAVE和BGSAVE都可以执行手动快照,两个命令的区别是前者是由主进程进行快照操作,会阻塞其他请求;而后者是通过fork子进程进行快照操作 bgsave:bgsave命令会派生出一个子进程,由子进程负责创建rdb文件,父进程继续处理redis命令 Save:save命令会阻塞redis服务器进程,直到rdb文件创建完成为止,在服务器进程阻塞期间不能处理任何命令请求 RDB文件的压缩:Redis默认开启压缩,可以通过配置rdbcompression参数来禁用压缩 优点
适合大规模的数据恢复,如果业务对数据完整性和一致性要求不高,RDB是很好的选择 缺点
数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了 备份时占用内存,因为Redis 在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时总占用内存是原来的两倍),最后再将临时文件替换之前的备份文件。所以Redis 的持久化和数据的恢复要选择在夜深人静的时候执行是比较合理的
AOF(Append Only File)
简介
Redis 默认不开启。它的出现是为了弥补RDB的不足(数据的不一致性),所以它采用以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作 AOF持久化步骤
命令追加:在AOF模式打开的情况下,服务器每执行一次写命令就会以协议格式将执行的写命令追加到aof_buf缓冲区的末尾 AOF文件的写入和同步:Redis每执行完一次事件循环,就要考虑要不要将缓冲区的数据写入AOF文件,写入同步策略有配置文件的appendfsync决定:appendfsync的值有三个
always:将缓冲区所有内容写入并同步AOF文件 everysec(默认):将缓冲区内容写入AOF文件,如果上次同步AOF文件的时间与现在间隔超过1秒钟,那么在此对AOF文件进行同步,并且这个同步操作是由一个线程专门执行的 no:将缓冲区内容写入文件,不对AOF进行同步,何时同步由操作系统来决定 AOF重写机制
因为AOF备份的策略是保存所有的写命令,当写命令不断增加时,AOF文件会越来越大,可能会影响系统性能和恢复数据的性能。为了解决这个问题,Redis提供了AOF文件重写(rewrite)功能。通过该功能,Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新旧两个AOF文件所保存的数据库状态相同,但新AOF文件不会包含任何浪费空间的冗余命令,所以新AOF文件的体积通常会比旧AOF文件的体积要小得多,虽然名字叫做AOF重写,但是新文件并不会读取并分析旧的AOF文件,而是通过读取当前数据库的状态来实现的。过程就是首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令,这就是AOF重写功能的实现原理 数据不一致的处理
Redis使用一个子进程来处理AOF的重写,这样会导致数据不一致的问题,比如当开始重写的时候数据库只有key1,在重写过程中有增加了key2,那么重写完后AOF中只有key1,就导致了数据的不一致。为了解决这种数据不一致问题,Redis服务器设置了一个AOF重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用,当Redis服务器执行完一个写命令之后,它会同时将这个写命令发送给AOF缓冲区和AOF重写缓冲区 当子进程完成AOF重写工作之后,它会向父进程发送一个信号,父进程在接到该信号之后,会调用一个信号处理函数,并执行以下工作
将AOF重写缓冲区中的所有内容写入到新AOF文件中,这时新AOF文件所保存的数据库状态将和服务器当前的数据库状态一致 对新的AOF文件进行改名,原子地(atomic)覆盖现有的AOF文件,完成新旧两个AOF文件的替换。这个信号处理函数执行完毕之后,父进程就可以继续像往常一样接受命令请求了 在整个AOF后台重写过程中,只有信号处理函数执行时会对服务器进程(父进程)造成阻塞,在其他时候,AOF后台重写都不会阻塞父进程,这将AOF重写对服务器性能造成的影响降到了最低 AOF配置和恢复
// etc/redis/redis.conf 文件中
appendonly yes # yes表示开启AOF持久化
appendfilename "appendonly.aof"
appendfsync everysec # 数据写入同步的策略(everysec、always、no)
#设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no
no-appendfsync-on-rewrite no
#当前AOF文件大小是上次日志重写得到AOF文件大小的二倍时,自动启动新的日志重写过程。
auto-aof-rewrite-percentage 100
#当前AOF文件启动新的日志重写过程的最小值,避免刚刚启动Reids时由于文件尺寸较小导致频繁的重写。
auto-aof-rewrite-min-size 64mb
// 恢复数据
# 配置完后重启redis,写入几条数据,发现生成了aof文件
# 先将aof文件移动到其他目录,然后清空所有数据,再移动回来,重启redis后发现数据恢复了。
优点:数据的完整性和一致性更高 缺点:因为AOF记录的内容多,文件会越来越大,数据恢复也会越来越慢
事务
简介
本质是一组命令的集合,可以一次执行多个命令,所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许插队。将一组需要一起执行的命令放到multi和exec两个命令之间。multi命令代表事务开始,exec命令代表事务结束,它们之间的命令是原子顺序执行的
常见命令
discard:取消事务,放弃执行事务快块内的所有命令 exec:执行所有事务块内的命令 multi:标记一个事务块的开始 watch key[key1 key2…]:监视指定的key,如果在事务执行之前这个(或这些)key被其他命令所改动,事务将会被打断–在开启事务前启动 unwatch:取消watch命令对所有key的监视
Redis并发控制
redis本身是没有锁的概念的, 但由于redis是单进程单线程的, 所以redis内部也不会出现并发冲突. 虽然redis内部不会出现并发冲突, 但这并不代表在业务场景下使用redis, 也不会出现并发冲突, 比如以下业务场景
多个客户端并发地写同一个key, 且写命令的执行顺序对结果会有影响 多个客户端并发地读同一个key, 如果满足条件就修改值后写回去
事务情况
Case1:正常执行 Case2:放弃事务 Case3:全体连坐 Case4:冤头债主 Case5:watch监控
悲观锁:悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,乐观锁策略:提交版本必须大于记录当前版本才能执行更新 redis乐观锁, 即CAS(check-and-set)机制, 客户端A在修改key之前先监控key, 如果key被其他客户端修改, 那么客户端A的修改就会失败, 返回 nil. 注意: 客户端A的修改要与事务一起使用
127.0.0.1:6379> watch mykey
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set mykey 789
QUEUED
127.0.0.1:6379> exec
(nil)
Redis事务的三个特性
单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题 不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚
Redis事务执行的3个阶段
开启:以MULTI开始一个事务 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面 执行:由EXEC命令触发事务
Redis的发布订阅
进程间的一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。 命令
订阅频道:subscribe channel 批量订阅:psubscribe channel* 取消订阅:unsubscribe channel 在指定的频道中发布消息,返回值为接收到该消息的订阅者数量:publish channel content
Redis的复制(Master/Slave)
Redis的复制即主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主 使用
配从(库)不配主(库) 从库配置:slaveof [主库IP] [主库端口]
每次slave与master断开后,都需要重新连接,除非你配置进redis.conf文件,键入info replication 可以查看redis主从信息 修改配置文件细节 常用3招
一主二仆:一个Master,两个Slave,Slave只能读不能写;当Slave与Master断开后需要重新slave of连接才可建立之前的主从关系;Master挂掉后,Master关系依然存在,Master重启即可恢复。 薪火相传:上一个Slave可以是下一个Slave的Master,Slave同样可以接收其他slaves的连接和同步请求,那么该slave作为了链条中下一个slave的Master,如此可以有效减轻Master的写压力。如果slave中途变更转向,会清除之前的数据,重新建立最新的 反客为主:当Master挂掉后,Slave可键入命令 slaveof no one使当前redis停止与其他Master redis数据同步,转成Master redis 复制原理
Slave启动成功连接到master后会发送一个sync命令 Master接到命令启动后的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步 全量复制:而slave服务在数据库文件数据后,将其存盘并加载到内存中 增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步 但是只要是重新连接master,一次完全同步(全量复制)将被自动执行 哨兵模式(sentinel)
反客为主的自动版,能够后台监控Master库是否故障,如果故障了根据投票数自动将slave库转换为主库。一组sentinel能同时监控多个Master 步骤
在Master对应redis.conf同目录下新建sentinel.conf文件,名字绝对不能错 配置哨兵,在sentinel.conf文件中填入内容:sentinel monitor 被监控数据库名字(自己起名字) ip port 1 启动哨兵模式:命令键入:redis-sentinel /myredis/sentinel.conf 复制的缺点
延时,由于所有的写操作都是在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使得这个问题更加严重。
与springboot结合
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
stringRedisTemplate类操作5中类型
stringRedisTemplate.opsForValue();
stringRedisTemplate.opsForHash();
stringRedisTemplate.opsForList();
stringRedisTemplate.opsForZSet();
stringRedisTemplate.opsForSet();