记录一份
REDIS
一、什么是redis?
是一个完全开源免费、遵守BSD协议、高性能的NOSQL的Key-Value形式的数据库。
二、特点
(1)基于内存
(2)支持持久化
(3)单个Key可存入512M
(4)支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
(5)支持多种数据类型
(6)支持集群(0 - 15)16个库
(7)支持消息队列
三、安装(基于Linux)
Step1: yum -y install gcc automake autoconf libtool make
Step2: wget 地址 -P 路径
wget http://download.redis.io/releases/redis-5.0.7.tar.gz
Step3: 解压
Step4: 进入解压后的目录,执行make MALLOC=libc
Step5: make PREFIX=/usr/local/redis install (PREFIX没有--)
四、启动
启动服务端:./redis-server [配置文件] [--port xxx] [--slaveof ip port]
启动客户端:./redis-cli -h <IP地址>
-p <端口>(默认端口为6379)
-a <密码>
--no-auth-warning # 在命令行输入密码的时候,不显示警告
--raw 避免中文乱码
-c 连接集群
-n <db_number>
检测服务端是否启动:
在客户端下执行:ping即可,出现PONG字样即成功
redis-server --version 查看版本信息
redis-server --help 帮助信息
五、配置文件
默认的配置文件在解压目录下,redis.conf
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
# units are case insensitive so 1GB 1Gb 1gB are all the same.
# bind 绑定主机地址,意思是允许来自哪个网卡的redis请求
bind 192.168.1.102 127.0.0.1
bind 0.0.0.0
# daemonize 守护进程,yes表示以守护进程方式启动
daemonize yes | no
# pidfile 当redis以守护进程启动时,将pid写入一个文件
pidfile /var/run/redis_6379.pid
# protected-mode
protected-mode yes
# port 监听端口
port 6379
# timeout 当客户端闲置多长时间后关闭,指定为0,表示关闭该功能
timeout 0
# loglevel 日志记录级别(debug, verbose, notice, warning)
loglevel verbose
# logfile 日志记录方式,默认标准输出。如果redis以守护进程方式启动,而这里又配置了stdout,则redis将日志输出到/dev/null
logfile stdout
# databases 数据库数量,默认16个,dbid范围0 - 15
databases 16
# save 指定在多少秒内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合使用
# 满足以下条件将会同步数据:
# 900秒(15分钟)内有1个更改
# 300秒(5分钟)内有10个更改
# 60秒内有10000个更改
# Note: 可以把所有“save”行注释掉,这样就取消同步操作了
save 900 1
save 300 10
save 60 10000
# rdbcompression yes表示压缩,采用LZF压缩方式。为了节省CPU时间,可以关闭,但会导致数据文件巨大
rdbcompression yes | no
# dbfilename 数据库文件名
dbfilename dump.db
# dir 指定数据库文件存放目录
dir ./
# slaveof 设置本机为slave后,在redis启动时,它会自动从master进行数据同步
slaveof <masterip> <masterport>
# masterauth 当master服务设置了密码保护时,slave服务连接master的密码
masterauth <master-password>
# requirepass 设置redis连接密码。redis 3.0以后必须设置。如果设置了连接时通过:
(1)redis-cli -a 密码
(2)连接进去后,通过auth 密码 验证
requirepass foobared
# maxclients 设置同一时间最大客户端连接数,默认无限制(也就是注释状态,或者设置为0)
如果到达限制,redis会关闭新的连接并向客户端返回max number of clients reached信息
maxclients 0
# maxmemory 指定最大内存,redis启动时会加载数据文件到内存。到达最大后,redis会尝试清除已到期或即将到期的key
当此方法处理后,仍到达最大,将无法再进行写入操作,但仍可以读取。redis的新VM机制,会把key存入内存,value存入swap
maxmeory <bytes>
# LRU means Least Recently Used
# LFU means Least Frequently Used
# volatile-lru -> Evict using approximated LRU among the keys with an expire set.
# allkeys-lru -> Evict any key using approximated LRU.
# volatile-lfu -> Evict using approximated LFU among the keys with an expire set.
# allkeys-lfu -> Evict any key using approximated LFU.
# volatile-random -> Remove a random key among the ones with an expire set.
# allkeys-random -> Remove a random key, any key.
# volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
# noeviction -> Don't evict anything, just return an error on write operations.
# maxmemory-policy noeviction
# appendonly 是否在每次更新操作之后进行日志记录
appendonly no
# appendfilename 指定更新日志文件名
appendfilename appendonly.aof
# appendfsync 指定日志更新条件
# no:表示等操作系统进行数据缓存同步到磁盘(快,完全依赖OS,性能最好,持久化没保证)
# always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
# everysec:表示每秒同步一次(折衷,默认值)
appendfsync everysec
# vm-enabled 指定是否启用虚拟内存机制,默认no
# VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中
# 把vm-enabled设置为yes,根据需要设置好接下来的三个VM参数,就可以启动VM了
vm-enabled no | yes
# vm-swap-file redis交换文件最好的存储是SSD
虚拟内存文件路径,不可多个redis实例共享
vm-swap-file /tmp/redis.swap
# vm-max-memory 将所有大于vm-max-memory的数据存入虚拟内存,
无论vm-max-memory设置多少,所有索引数据都是内存存储的
(redis的索引数据就是keys)
vm-max-memory 0
# Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,
# 但一个page上不能被多个对象共享,vm-page-size是要根据存储的数据大小来设定的。
# 建议如果存储很多小对象,page大小最后设置为32或64bytes;
如果存储很大的对象,则可以使用更大的page,如果不确定,就使用默认值
vm-page-size 32
# vm-pages
# 设置swap文件中的page数量由于页表(一种表示页面空闲或使用的bitmap)是存放在内存中的,在磁盘上每8个pages将消耗1byte的内存
# swap空间总容量为 vm-page-size * vm-pages
vm-pages 134217728
# vm-max-threads
# 设置访问swap文件的I/O线程数,最后不要超过机器的核数,
# 如果设置为0,那么所有对swap文件的操作都是串行的,
# 可能会造成比较长时间的延迟,默认值为4
vm-max-threads 4
# 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法
hash-max-zipmap-entries 512
hash-max-zipmap-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
# 指定是否激活重置哈希,默认为开启
activerehashing yes
################################## INCLUDES ###################################
# 指定包含其他的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各实例又拥有自己的特定配置文件
# include /path/to/local.conf
# include /path/to/other.conf
六、关闭服务
Step1: 连接到redis后
Step2: shutdown [save | nosave] 默认将内存中的数据保存到数据文件中
七、Redis命名规范
1. 单个Key可存入512MB
2. key名字不超过1024B
3. 不要太短,降低可读性
4. 区分大小写
5. 使用:分隔(行业规定),例如:username:id:1
八、数据类型
nil
string
hash
list
set
sorted set
bitmap
HyperLogLog
################################## Redis命令 ###################################、
(一)公共命令
auth password 验证密码
ping [message] 测试服务器是否运行
echo message 输出一个message
time
lastsave
clear 清屏
quit 关闭当前连接
shutdown [save | nosave] 关闭服务,默认将内存中的数据保存到数据文件中
save 同步保存数据
bgsave 异步保存数据
sync 主从同步
config get cfname cfval 获取配置信息
1) "daemonize"
2) "yes"
config set cfname cfval 设置配置信息
dbsize 查看当前数据库有多少key,包括过期的
keys * | ? | [] 查看keys(* | ?是通配符,*表示任意个任意字符,?表示一个任意的字符)
有效的
randomkey 随机地从当前数据库返回一个key,没有,返回nil
move key dbid 把当前库中的key移动到指定的数据库,返回1,如果key在数据库存在,返回0,并且不移动;
select dbid 切换数据库
flushdb [async] 删除当前数据库所有的key,选项async表示异步执行删除操作(也就是在后台执行)
flushall [async] 删除所有数据库中的所有key,选项async表示异步执行删除操作(也就是在后台执行)
dump key 序列化key
type key 检测key的数据类型
rename key newkey 给key改名,如果newkey存在,则直接覆盖
renamenx key newkey 当key不存在时改名,并且返回1,否则返回0,不改名
del key [key ...] 删除存在的key,并返回成功删除个数
exists key [key ...] 检查key是否存在,并返回存在的key的个数
expire key seconds 给key设置过期时间(秒),默认永久(-1)
成功返回1,当key不存在或者不能设置时,返回0
pexpire key miliseconds 给key设置过期时间(毫秒)
expireat key seconds 接受Unix时间戳
pexpireat key miliseconds
ttl key 查看key的剩余时间(秒)(time to live)(-2 无效)
当key不存在或者过期,返回-2
pttl key 查看key的剩余时间(毫秒)
persist key 移除key的过期时间
当过期时间移除成功时,返回 1 。
如果 key 不存在或 key 没有设置过期时间,返回 0 。
pfadd key elm [elm ...] 添加一个或多个基数,有一个被添加就返回1,没有就返回0,不重复
pfcount key [key ...] 返回key中基数的个数,如果是多个key,则累加返回
pfmerge deskey skey [...] 合并,成功返回OK
(二)string
string是二进制安全的,可以包含任何数据,例如,图片等
二进制安全:在传输数据时,保证二进制数据的安全。也就是不会被篡改、破译等,
如果被攻击,能及时检测出来。
特点:
1. 编解码发生在客户端,执行效率高
2. 不需要频繁的编解码,不会发生乱码
set key value [EX seconds | PX miliseconds] [NX | XX] 设置key-value,如果key存在,就覆写
EX,过期时间(秒)
PX,过期时间(毫秒)
NX,只有name不存在时,当前set操作才执行
XX,只有name存在时,当前set操作才执行
setnx key value 当key不存在时,就设置key-value,返回1;如果存在,返回0
setex key seconds value 为指定的 key 设置值及其过期时间 如果 key 已经存在, SETEX 命令将会替换旧的值
psetex key miliseconds value
mset key value [key value ...] 一次性设置多个key-value键值对
msetnx key value [key value ...] 当所有 key 都成功设置,返回 1
如果所有给定 key 都设置失败(至少有一个 key 已经存在),那么返回 0
setrange key offset value 用指定的字符串覆盖给定 key 所储存的字符串值,覆盖的位置从偏移量 offset 开始,返回字符串字节总长度
append key value 将value追加到key原有的值后面,并且返回追加后的长度;如果key不存在,就赋值并且返回字符串字节总长度
get key 获取key的value,如果key不存在,返回nil,如果存在但类型不是string,报错
mget key [key ...] 一次性获取多个key的value,如果key不存在,当前key返回nil
getrange key start end 获取key的value一部分[start, end],start、end都支持负索引(都取得到),start、end如果超过了原有string的长度,没有关系,会尽最大能力获取
例如:getrange strin2 0 -1 getrange -3 -1
getbit key offset 获取key的value在偏移量上的位值
getset key value 先获取,再赋值
strlen key 获取key的value的字节长度,不存在返回0,存在但类型不是string,报错
incr key 让key的value自增1(value必须为整型,否则报错),并且返回
如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作
decr key 让key的value自减1(value必须为整型),并且返回
incrby key increment 让key的value自增increment指定的整型值(value必须为整型,可以为负整数),并且返回
decrby key increment 让key的value自减increment指定的整型值(value必须为整型),并且返回
incrbyfloat key increment 让key的value自增increment指定的浮点型 | 整型值,并且返回
(三)hash
每个hash可以存2^32 - 1键值对(40多亿)
如果把key中所有的键值对删除了,那么该key也就被回收了
hset key field value [field value ...] 在指定的key中设置field-value(相当于Python中key = {field: value}
返回设置的个数;如果是覆写返回0;如果既有覆写也有设置,返回设置的个数
hsetnx key feild value
hmset key field value [field value ...] 一次性在key中设置多个field-value键值对,永远返回True
hget key field 在指定的key中获取field的value;不存在,返回nil
hmget key field [field ...] 一次性在key中获取多个field的value
hgetall key 获取key中所有的field和value
hkeys key 获取key中所有的field
hvals key 获取key中所有的value
hlen key 统计key中有多少个键值对
hstrlen key field 返回哈希表中给定域相关联的值的字符串长度
如果key or filed不存在返回0
hdel key field [field ...] 删除key中的field键值对(如果把key中所有的键值对删除了,那么key也就被回收了)
hexists key field 检查key中是否存在field,key or field不存在返回0
hincrby key field increment 让key中field的value自增increment指定的整型值(value必须为整型),并且返回
如果哈希表的不存在
一个新的哈希表被创建并执行 HINCRBY 命令
如果指定的键(key)不存在
那么在执行命令前,字段的值先被初始化为0
hincrbyfloat key field increment 让key中field的value自增increment指定的浮点型 | 整型值 ,并且返回
(四)list
每个list最多可包含2^32 - 1个元素
如果list没有元素了,则该key被删除
lpush key value [value ...] 往key的左侧添加一个或多个value,返回添加后的长度
lpushx key value [value ...] 往已存在的key的左侧添加一个value,返回添加后的长度,否则返回0
rpush key value [value ...] 往key的右侧添加一个或多个value,返回添加后的长度
rpushx key value [value ...] 往已存在的key的右侧添加一个或读个value,返回添加后的长度,否则返回0
lrange key start end 按照start和end指定的范围查看key中value
lindex key index 查看key中index(可以使用负索引)的value,超过范围,返回nil
llen key 查看key的长度,不存在,返回0,若存在但不是list,报错
lpop key 从key的左侧移除并且返回一个元素,如果列表为空或者不存在,返回nil
rpop key 从key的右侧移除并且返回一个元素,如果列表为空,返回nil
blpop key [key ...] timeout 按照key的顺序,谁有值就从其左侧移除并且返回一个值;
如果都没有值,则阻塞指定的timeout时间,返回nil
或者直到发现key中有可弹出的元素为止。
返回的结果:
1)哪个key弹出的
2)弹出的值
brpop key [key ...] timeout 按照key的顺序,谁有值就从其右侧移除并且返回一个值;
如果都没有值,则阻塞指定的timeout时间,返回nil
或者直到发现key中有可弹出的元素为止。
返回的结果:
1)哪个key弹出的
2)弹出的值
lrem key count value 根据参数 COUNT 的值,移除列表中与参数 VALUE 相等的元素。
count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。
count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。
count = 0 : 移除表中所有与 VALUE 相等的值。
返回被移除元素的数量。 列表不存在时返回 0 。
ltrim key start stop 按照start和end指定的范围保留key中的value,其余的都舍弃
lset key index value 将key中的index位置上的值改为value,如果key不存在,则报错
linsert key before | after v1 value2 往key中的v1之前 | 之后插入value2,返回插入后的长度,如果v1不存在,返回-1,key不存在返回或者为空列表,返回0
rpoplpush source destination 将source右侧最后一个元素移除并且返回,然后插入到destination的左侧
brpoplpush source destination timeout 从source右侧弹出一个值,将弹出的值插入到destination左侧并且返回,
如果source没有元素,则会阻塞列表直到超时或发现可弹出元素为止。
(五)set
集合,无序,唯一,可包含2^32 - 1个成员
sadd key member [member ...] 往key中添加一个或多个成员,返回添加的成员个数
scard key 统计key中的成员个数
smembers key 返回key中所有的成员
sismember key member 判断member是否是key的成员,是,返回1,否,返回0
srandmember key [count] 随机地从key中返回值,默认返回1个,如果key为空,返回nil,如果count超过总大小,没有关系,尽最大能力返回
count 可以为负数,但可能有重复,正数,都是不同的
srem key member [member ...] 从key中删除一个或多个成员,返回成功删除的个数
spop key [count] 从key中随机删除count指定的成员并且返回,默认1个,如果key为空,返回nil,如果count超过总大小,没有关系,尽最大能力删除
smove source destination member 把member从source移动到destination,移动成功(只要member在source存在即可,重不重复无所谓),返回1,失败(member在source中不存在),返回0
当 destination 集合已经包含 member 元素时, SMOVE 命令只是简单地将 source 集合中的 member 元素删除。
集合运算:
差集:
sdiff key1 [key2 ...] key1与key2...等等做差集,去掉key1中在其他集合中存在的成员,剩下的成员返回
sdiffstore destination key [key ...] 将差集的结果存储到destination中,返回存储之后的个数
交集:
sinter key1 [key2 ...] 将共同的成员返回
sinterstore destination key [key ...]将共同的成员存储到destination中,返回存储之后的个数
并集:
sunion key1 [key2 ...] 将多个集合的成员合并
sunionstore destination key [key ...]将合并的成员存储到destination中,返回存储之后的个数
(六)sorted set
有序集合,有序,成员唯一,分数(浮点型)可以重复,可包含2^32 - 1个成员
zadd key score member [score member ...] 往key添加一个或多个带分数的成员,返回添加的成员个数;如果是更新分数的话,返回0,因为不是添加
# ================================================================================================================
zadd key score member [score member ...]
有关zadd命令有两点需要注意: Redis 3.2为zadd命令添加了nx、xx、ch、incr四个选项:
nx:member必须不存在,才可以设置成功,用于添加.
xx:member必须存在,才可以设置成功,用于添加.
ch:返回此次操作后,有序结合元素和分数发生变化的个数.(默认不会对更新分数进行统计)
incr: 对score进行添加操作,相当于后面介绍的zincrby. (在原有分数上增加)
有序集合相比集合提供了排序字段,但是也产生了代价,zadd的时间复杂度是O(log(n)),sadd的时间复杂度为O(1).
# ================================================================== ============================================
zcard key 统计key中的成员个数
zrange key start stop [withscores] 按照start和stop指定的范围获取key中的成员,选项withscores表示分数值也显示(可以使用负索引)
zrevrange key start stop [withscores] 在zrange的基础上,反序输出
zrangebyscore key min max [withscores] [LIMIT <offset> <count>]
zrevrangebyscore key max min [withscores] [LIMIT <offset> <count>] 注意max要反过来
min 和 max 可以是 -inf 和 +inf,这样一来,你就可以在不知道有序集的最低和最高 score 值的情况下,使用 ZRANGEBYSCORE 这类命令。
ZRANGEBYSCORE zset (1 5
返回所有符合条件 1 < score <= 5 的成员,而
ZRANGEBYSCORE zset (5 (10
则返回所有符合条件 5 < score < 10 的成员。
zrangebylex key min max [LIMIT <offset> <count>]
zcount key min max 统计key中成员分数在min - max中的个数
zlexcount key min max 命令计算有序集合中指定字典区间内成员数量
[ 符号
[min 表示返回的结果中包含 min 值
[max 表示返回的结果中包含 max 值
( 符号
(min 表示返回的结果中不包含 min 值
(max 表示返回的结果中不包含 max 值
[MIN,[MAX 可以用 -,+ 代替
- 表示得分最小值的成员
+ 表示得分最大值的成员
zrank key member 返回member在key中排名,按照分数从低到高排序,第一名为0,第二名为1,以此类推。key or member不存在,返回nil,相同的话,按照value的字典顺序排
zrevrank key start stop 分数从高到低排序
zscore key member
zrem key member [member ...] 从key中删除一个或多个成员,返回成功删除的个数
zremrangebyrank key start stop 根据rank删除在start和end指定的范围内的成员,返回成功删除的个数
zremrangebyscore key min max 根据score删除在min和max指定的范围内的成员,返回成功删除的个数
zincrby key increment member # 在原有值基础上增加 increment,返回增加之后的值
# 1. increment 可以为整型和浮点型
# 2. increment 可以为负数
(七)bitmap(位图)
Redis Bitmap 通过类似 map 结构存放 0 或 1 ( bit 位 ) 作为值
Redis Bitmap 可以用来统计状态,如 日活,是否浏览过某个东西
setbit key offset value Redis setbit 命令用于设置或者清除一个 bit 位
offset必须为整型,value必须为0 or 1
每次返回上次的value(一开始返回0)
(七)发布订阅
Redis发布与订阅(pub/sub)是一种消息通信模式。
发送者(pub),发送消息;
订阅者(sub),接收消息;
Redis客户端可以订阅任意数量的频道;
subscribe channel [channel ...] 订阅一个或多个频道
返回值:
1)subscribe
2)频道名
3)序号(从1开始)
psubscribe pattern [pattern ...] 根据模式来订阅一个或多个频道
返回值:
1)subscribe
2)频道模式
3)序号(从1开始)
模式以*作为匹配符
publish channel message 向指定的channel发送message,发送成功即有响应的订阅者接受返回1,反之,返回0
unsubscribe [channel [channel ...]] 取消订阅频道
punsubscribe [channel [channel ...]] 根据模式取消订阅频道
pubsub <subcommand> [argument [argument ...]查看发布者和订阅者状态
subcommand:
channels [pattern ...] 根据模式,如果有,查看相应的频道
numpat 返回用psubscribe订阅的频道个数,其余方式订阅的统统返回0
numsub [channel ...] 判断用subscribe订阅的频道是否存在
(八)事务
Redis中的事务一次可以执行多个命令,并且有以下三个重要保证:
1)批量操作在发送exec命令前被放入队列缓存;
2)收到exec命令后进入事务执行,事务中任意命令执行失败,其余命令依然被执行
3)在事务执行过程中,其他客户端提交的命令请求不会插入到事务执行命令序列中
一个事务从开始到执行会经历以下三个阶段:
1)开始事务
2)命令入队
3)执行事务
单个Redis命令的执行是原子性的,但Redis并没有在事务上增加任何维持原子的机制,所以Redis事务的执行并不是原子性的。
事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,
也不会造成后续指令的不做。
意思就是:事务中,如果是逻辑错误,是不会回滚的;但如果是语法错误,就会回滚。
事务框架:
watch key [key ...] watch命令用于监视一个或多个key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断执行
总是返回OK
multi multi命令用于标记一个事务块的开始
总是返回OK
多条命令入队 返回QUEUED,提示已入队缓存
....
exec exec命令用于执行所有事务块内的命令
返回事务块内所有命令的返回值,
当操作被打断时,返回nil
discard discard命令用于取消事务,放弃执行事务块内的所有命令
总是返回OK
一个事务要么执行,要么不执行,所以exec和discard在一次事务中只能出现一个
unwatch unwatch命令用于取消watch命令对所有key的监视
总是返回OK
unwatch只能在exec或discard之前出现
(九)数据淘汰机制
为了防止内存溢出,可采取以下方法:
在redis中,允许用户设置最大使用内存大小
单台redis服务器,最大内存使用不应超过20G(建议)
maxmemory 512G
方法一:给key设置过期时间
方法二:给maxmemory-policy设置相应的数据淘汰策略
# LRU means Least Recently Used
LRU意思是:最近最少使用。判断最近被使用的时间,目前最远的数据优先被淘汰
# LFU means Least Frequently Used
LFU意思是:最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰
# volatile-lru -> Evict using approximated LRU among the keys with an expire set.
从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
# volatile-lfu -> Evict using approximated LFU among the keys with an expire set.
从已设置过期时间的数据集中,删除一段时间内使用次数最少的数据
# volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
从已设置过期时间的数据集中挑选最近将要过期的数据淘汰
# volatile-random -> Remove a random key among the ones with an expire set.
从已设置过期时间的数据集中,随机挑选数据淘汰
# allkeys-lru -> Evict any key using approximated LRU. ----------------------》 广泛采用的策略
从数据集中挑选最近最少使用的数据淘汰
# allkeys-lfu -> Evict any key using approximated LFU.
从数据集中,删除一段时间内使用次数最少的数据
# allkeys-random -> Remove a random key, any key.
从数据集中随机挑选数据淘汰
# noeviction -> Don't evict anything, just return an error on write operations.
禁止淘汰任何数据(默认配置),对于写操作,返回错误信息
(十)持久化
方式一:RDB
默认dump.rdb,是一种快照,保存一种状态
优点:
保存数据极快,还原极快
适用于灾难备份
缺点:
小内存机器不适用
RDB机制符合要求就会照快照
条件:
1. 服务器正常关闭
2. save条件
方式二:AOF
如果要求不能丢失任何修改,可以采用AOF机制
# appendfsync 指定日志更新条件
# no:表示等操作系统进行数据缓存同步到磁盘(快,完全依赖OS,性能最好,持久化没保证)
# always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
# everysec:表示每秒同步一次(折衷,默认值)
appendfsync everysec
(十一)Redis与数据库一致性
方式一:实时同步
适用于对强一致性要求高的情况下。
即首先查询缓存,查询不到再从数据库查询并且保存到缓存;更新时,首先更新数据库,将缓存的设置过期
(建议不要更新缓存,或者清空
因为会导致“缓存穿透”:
key对应的数据在数据源并不存在,查询一个一定不存在的数据时,由于缓存是在不命中时需要从数据库查询,
数据库查询不到就不会写到缓存,这将导致不存在的数据每次请求都要到数据库去查询,
造成缓存穿透。
解决方案:
数据库查询不到,就给Redis缓存一个空值,
再次查询时,先到缓存中判断这个key存不存在,如果不存在,就往数据库查询;
如果存在,再判断该key的value是否为空,如果是,就返回空,如果不是,就返回结果集。
“缓存雪崩”:
缓存中的内容集中在一段时间失效,造成大量缓存穿透,所有的请求压力都落在底层数据库上。
解决方案:
可以分析用户行为,让缓存失效时间均匀分布;
再缓存失效时,可以考虑加锁或者队列来控制读数据库写缓存的线程数量,
这样就避免失效时大量并发都落在底层数据库上。
“缓存击穿”
key对应的数据存在,但在redis中过期,此时若有大量并发请求过来
,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,
这个时候大并发的请求可能会瞬间把后端DB压垮。
解决方案:
利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试。
)
方式二:异步队列
适用于对并发程度要求高的情况下,使用kafka等消息中间件来处理
方式三:阿里的同步工具Canal
模拟MySQL的Master和Slave同步机制,监控数据库的binary log的日志更新记录来更新缓存
方式四:Redis脚本
编写Redis脚本,使用Lua解释器执行
方式五:UDF自定义函数
面对MySQL的API编程,使用触发器来进行缓存更新
方式六:任务计划
(十二)提升并发性能
(1)垂直扩展:提升单机处理能力
1. 增强单机硬件性能(如果钱不是问题,就可以考虑这个,毕竟商业“时间就是金钱”)
2. 提升单机架构性能
(2)水平扩展:增加服务器数量
# ============================
恢复数据:
恢复数据,只需将备份文件 ( dump.rdb ) 移动到 Redis 安装目录并启动服务即可
# ============================
(十三)主从同步
主Master:写
从Slaves:读
一个主可以有多个从;
一个从只能隶属于一个主
为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内
部署流程:
主Redis无需配置,从Redis需要做以下配置:
Step1: port 6378 (说明:如果是真实的Redis服务器,无需改端口号;因为是虚拟测试,就改端口,来模拟不同的主机服务器)
Step2: slaveof <masterip> <masterport>
slaveof 192.168.1.102 6379
masterauth hardy9sap
step3:从服务端启动
redis-server ./redis.conf --port 6378 --slaveof 192.168.1.102 6379
登录从客户端
redis-cli -p 6378 -a hardy9sap
客户端下执行:
变回主:slaveof no one
变回从:slaveof masterip masterport
(十四)Redis-Cluster集群
Redis 3.0后,必须有3台Master + 3台Slave才能建立集群
redis-cluster是无中心结构,
每个节点保存数据和整个集群状态,
每个节点都和其它节点连接。
(虚拟环境下)部署流程:
Step1: mkdir /usr/local/redis_cluster
Step2: cd redis_cluster
Step3: mkdir 700{1..6}
Step4: cp -a ../redis/redis.conf ./7001
Step5: vim ./7001/redis.conf
1. 将端口改为7001
2. pidfile的6379改为7001
3. requirepass hardy9sap
3. 启用cluster: cluster-enabled yes
4. 启用cluster-config-file, 并且将6379改为7001
5. 启用cluster-node-timeout
step6: 将7001下的redis.conf依次复制到7002 - 7006,并且将以上设置改为对应的数字
Step7: 将redis解压目录下的src/复制到7001 - 7006中
Step8: 将src中的redis-cli复制到/usr/local/bin下,方便操作
Step9: 安装ruby
yum -y install ruby ruby-devel rubygems rpm-build
curl -L get.rvm.io | bash -s stable
source ~/.bashrc
source ~/.bash_profile
find / -name rvm -print
source /usr/local/rvm/scripts/rvm
rvm list known
rvm install install 2.6.3 (安装高于2.2.0即可)
Step10: redis-cli --cluster create 192.168.1.102:7001 192.168.1.102:7002 192.168.1.102:7003
192.168.1.102:7004 192.168.1.102:7005 192.168.1.102:7006
--cluster-replicas 1
-a hardy9sap
Step11: 客户端连接
redis-cli -h 192.168.1.102 -p 7001 -c -a hardy9sap
集群命令:
info replication 当前节点信息
cluster nodes 查看所有的节点