目录
redis是干什么的
1、redis属于nosql(非关系型的数据库),一般用于存储和处理高频、波段性的热点信息
2、redis应关注于提供基础数据,不应有过多业务层的操作
redis运行高速的原因
-
完全基于内存操作
-
数据结构简单,数据操作也简单
-
使用多路I/O复用模型
数据类型
string
基本操作
增:
(1)单数据操作:set key val
(2)多数据操作:mset key1 val1 key2 val2 ... ...
查:
(1)单数据操作:get key
(2)多数据操作:get key1 key2 key3 ...
删:del key
注:每条指令除了执行耗时间,发送指令到redis和返回执行结果一样也耗费时间,理智选择单数据操作还是多数据操作,单指令执行多数据操作不一定就是最好,在单线程环境下一条指令处理过多数据会造成阻塞。
其他操作
strlen key //获取字符串长度
append key value //有则追加,无则新建
setnx key value //不存在就设置,存在就不设置
incr key //自增 1
incrby key num //给key的值增加num(int 类型),num 正数则为加,num 为负数 则为减
incrbyfloat key num //给key的值增加num(float 类型)
decr key //自减 1
decrby key num //给key的值减num
setex key second value //设置key的值为value存活时间为second秒
psetex key millisecond value //设置key的值为value存活时间为millisecond毫秒
数据最大存储量
512MB
string类型应用场景
例如:
set user:id:00798:fans 123456 //只改单一字段
or json格式
set user:id:00798 {id:00798,fans:123456,blogs:789} //一改全改
hash
相当于将value再拆分成一个field-value键值对。
基本操作
增:
(1)单数据操作:hset key field value
(2)多数据操作:hmset key field1 value1 field2 value2 ... ...
查:
(1)单数据操作:hget key field
(2)多数据操作:hmget key field1 field2 ...
(3)查key内的所有field:hgetall key
删:hdel key field1 field2 ...
其他操作
hlen key //查看有多少个field
hexisits key field //查看是否存在某字段
hkeys key // 查看所有field
hvals key //查看所有value
hincrby key field increment
hincrbyfloat key field increment
hsetnx key field value //已有这个field就不动他,没有就加上去
注意事项
(1)value只能存储string类型,不能嵌套哈希
(2)每个hash可存2^32-1个键值对
list
底层实现:双向链表
基本操作
增:
(1)左加:lpush key value1 value2 ...
(2)右加:rpush key value1 value2 ...
查:
(1)范围查找:lrange key start stop //下标从0开始,若想查到结尾,stop设为-1
(2)下标查找单个:lindex key index
(3)长度:llen key
pop:
(1)经典版:
lpop key
rpop key
(2)阻塞版(等待给定的时间,有数据就直接拿):
blpop key1 ...keyn timeout
brpop key2 ...keyn timeout
删:lrem key count value //可删多个具有重复值的元素
set
hash的变形,用于存储大量数据,不含重复,方便查询
基本操作
增:sadd key member1 ...membern
查:smembers key
删:srem key member1 ...membern
查总量:scard key
是否存在某数据:sismember key member
其他操作
srandmember key [count] //随机取任意个数据
spop key[count] //随机pop任意个数据
sinter/sunion/sdiff key1 ...keyn //求多个集合的交、并、差集
sinterstore/sunionstore/sdiffstore destination key1 ...keyn //求多个集合的交、并、差集并存放
smove source destination member //移走指定数据
sorted_set
在set的基础上加了一个score字段用于排序
基本操作
增:zadd key score1 member1 ... ...
查:
(1)按下标查:zrange/zrevrange key start stop [withscores] //可带上排序字段
(2)按排序字段查:zrangebyscore/zrevrangebyscore key max min [withscores] [limit offset count] //可加上限制从下标offset开始查count个
删:
(1)删单个:zrem key member ...
(2)删多个:
zremrangebyrank key start stop //按下标删
zremrangebyscore key min max //按排序字段删
查总量:
zcard key
zcount key min max
集合交、并操作:
zinterstore/zunionstore destination numkeys key... [aggregate sum|min|max] //可选择相同字段合并后score的操作方式
其他操作
zrank key member //获取排名,从0开始
zrevrank key member //反向排名
zscore key member //取score
zincrby key increment member //修改所选数据的score
注意事项
(1)score取值范围:-9007199254740992~9007199254740992
(2)score可用双精度浮点数,但会丢失精度
bitmaps
操作
getbit key offset
setbit key offset value
bitop and|or|not|xor destKey key1 [key2...]
bitcount key [start end] \\记录有多少个1
HyperLogLog
(1)用于基数统计,与集合不同在于放进去的数据无法取出,只记录数量而不记录具体数据
(2)结果带有0.81%标准错误
(3)耗空间极小,每个key只占用12k
操作
添加:pfadd key element [element ...]
统计:pfcount key [key ...]
合并:pfmerge destkey sourcekey [sourcekey ...]
GEO
用于地理位置信息计算
通用指令
key
基本操作
del key //删
exists key //判断是否存在
type key //类型
时间控制操作
(1)设置有效期:
expire key seconds
pexipire key milliseconds
expireat key time_in_seconds_in_unix_timestamp
pexpireat key time_in_milliseconds_in_unix_timestamp
(2)获取有效期:
ttl key //已失效返回-2,永久有效返回-1,其他返回有效时间
pttl key
(3)转换为永久: persist key
查询操作
keys pattern
其他操作
rename key newkey
renamenx key newkey //不存在才改
sort //对list或set或zset的key排序,不改变原列表
数据库
为解决key重复问题,redis为每个服务提供16个数据库,编号从0-15
基本操作
select index //换库 0-15
ping //测试服务器是否连通
quit //退出
echo message //输出到控制台
其他操作
move key db //移动到指定的库
flushdb //清空当前数据库
flushall //清空全部
dbsize //看当前库有多少个key
Linux启动
首先cd到redis目录下
服务端启动
(1)redis-server --port [启动的端口号,不填就默认6379]
(2)推荐!!!:redis-server conf/redis-xxxx.conf //通过配置文件启动,命名方式规范为xxxx填端口号
服务端配置文件的一些配置项
port xxxx //填端口号
daemonize yes|no //设置服务器以守护进程的方式运行,即在后台执行
logfile "端口号.log" //记录日志信息的文件
dir /redis-4.0.0/data //记录日志信息、持久化数据等的文件目录
bind 127.0.0.1 //绑定本机的IP地址,如果指定了bind,则说明只允许来自指定网卡的Redis请求
databases 16 //默认就是16个
loglevel debug|verbose|notice|warning //日志输出量依次递减
maxclients 0 //0就是随便连
timeout 0 //设置多长时间不用自动断开连接,0就是不用,单位为秒
include /path/server_端口号.conf //类似于继承,导入别的服务器的配置
客户端启动
redis-client -p [服务器的端口号,不填就默认6379]
注:客户端启动后输入info可查看一些参数信息
持久化
保存当前执行数据到磁盘,下次启动可恢复
RDB(Relational Database)
保存二进制数据
操作方法
(1)save //阻塞版,立刻执行
(2)bgsave //非阻塞版,后台执行
(3)配置项添加:save second changes //若在second秒内执行了changes次操作,则自动执行bgsave
一些配置项
(1)配置数据文件名称:dbfilename dump-xxxx.rdb //命名规范x填端口号,不设置默认为dump.rdb
(2)开启压缩:rdbcompression yes|no //默认yes
(3)开启格式检查:rdbchecksum yes|no //默认no
应用场景
由于RDB会造成数据丢失,多用于对数据丢失敏感度没那么高的场景,通常服务器每几个小时执行bgsave,将rdb文件拷贝到远程机器,用于灾难恢复。
AOF(Append Only File)
保存每条操作,具有实时性
重写操作
由于AOF会导致持久化文件过大,所以需要重写来对操作列表进行优化,将多条操作合并或删除,如三条连续对同一个key的set操作只保留最后一个,del掉的key删除对他的操作语句,重写有两种实现方式:
(1)手动重写:执行bgrewriteaof
(2)自动重写:配置项配置(见下面)
配置项
(1)开启:appendonly yes|no //默认no
(2)保存策略:appendfsync always | everysec | no(系统控制)
(3)重写:
auto-aof-rewrite-min-size size
auto-aof-rewrite-percentage perccent
触发条件(两个触发一个就自动重写):
aof_current_size > auto-aof-rewrite-min-size
(aof_current_size - aof_base_size)/aof_base_size >= auto-aof-rewrite-percentage
两者对比
(1)对数据敏感,用AOF
(2)对数据不敏感,且追求快速回复,用RDB
(3)灾难恢复用RDB
(4)可同时开启RDB和AOF,redis优先使用AOF
事务
命令
(1)开启事务:multi //把操作进入队列,不立刻执行
(2)结束事务:exec //开始执行每一条操作
(3)取消事务:discard //定义的过程出现问题可随时取消
操作错误
(1)语法错误:销毁当前操作队列,全部不执行,如打错关键字的情况
(2)运行时错误:仅错误的语句不执行,其他执行,如lpush了一个string的情况
FBI warning:redis事务没有回滚操作!录入错了要程序员手动恢复数据
监视
(1)监视:watch key1 ...keyn //开启事务之前监控一个或多个key,若在事务过程中监控的key发生改变就不执行此事务,exec会返回空
(2)取消监视:unwatch //会取消掉所有监视
分布式锁
通过 setnx实现一个互斥锁,执行操作前先setnx公共锁,如果返回0说明此锁存在,有人正在用此互斥量,返回1则可用,操作完后del掉这个公共锁
注:可通过expire或pexpire对锁加上时效,防止获取锁的客户端宕机造成死锁
删除策略
时效性数据的存储结构
以哈希的方式存储数据地址与其对应的过期时间
数据删除策略的目标
在内存占用与CPU占用之间寻找一种平衡,在CPU空闲的时候删除数据释放内存
定时删除
创建定时器,到时间后将对应地址的数据拿掉
用处理器性能换存储空间(时间换空间)
优点
节省内存,到点就释放,快速释放不需要内存
缺点
CPU压力很大,会抢占队列,影响指令吞吐量,redis对外服务的质量降低
惰性删除
数据到期先不删除,下次访问时再管
拿数据先执行expireIfNeeded()判断是否过期
拿存储空间换处理器性能(空间换时间)
优点
节约CPU性能,发现必须删除时才删除
缺点
内存压力大,会出现长期的内存占用的效果
定期删除(redis采用)
用轮询的思想,采用随机抽取、重点抽查的策略,属于一种折中的方案
周期性抽查存储空间
步骤
每100ms执行一次,每次执行25ms,相当于只占用CPU四分之一的资源
参数配置
(1)ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP:就是上述W值
(2)current_db:记录activeExpireCycle()执行到哪个数据库,若函数执行时间到期,下次从current_db继续向下执行
逐出算法
前面讲的是时效性数据,逐出算法考虑的是永久性数据,内存不足的情况。
执行命令前,调用freeMemoryIfNeeded()检测内存是否充足,不满足要求就临时删除一些数据腾出空间。
逐出算法不是100%能清理出可用内存,不成功则反复尝试,尝试完毕不能满足要求就会出现错误信息。
相关配置
(1)最大可用内存:maxmemory
(2)每次选取删除数据的个数:maxmemory-samples
(3)删除策略(见下):maxmemory-policy
三类删除策略
主从复制
多服务器连接方案
为避免单点redis服务器故障,将数据的副本保存在多个服务器上并互相连接在一起。
采用主从复制的方案,将master中的数据及时、有效地复制到slave中
特征:master对应slave为一对多关系
工作流程
建立连接阶段
建立slave到master的连接,使master能够识别slave,并保存 slave端口号
slave三种方式连接master:
(1)slave客户端连接到slave服务器后执行slaveof指令
(2)slave服务器启动命令后添加 --s slaveof指令
(3)slave服务器的配置文件添加slaveof信息
slave断开连接:slaveof no one
数据同步阶段
注意配置项:
repl-backlog-size 1mb //设置复制缓冲区大小,如果设置过小可能导致复制缓冲区溢出,部分复制无法执行,不得不再次执行全量复制,浪费时间
slave-serve-stale-data yes|no //防止slave进行复制时阻塞,关闭此期间对外服务
命令传播阶段
根据心跳机制同步命令
复制缓冲区
一个队列,由偏移量和字节值组成
工作原理
- 通过offset区分不同的slave数据传播的差异
- slave记录自己接收到信息的offset
- master也要记录不同slave的offset,防止断电造成数据传输中断,可以通过比对双方保存的offset恢复
要点
- 入队元素过多时,先进队的会弹出,就只能执行全量复制
- 每台服务器启动,只要开启AOF或称为master节点,都会创建复制缓冲区
- 只记录set、select等改变数据的指令
- 数据来源:主客户端的指令,master除了执行还要将其进队
心跳机制
命令传播阶段master与slave进行信息交换,用心跳机制维护
注意配置项
slave多数掉线或延迟过高,master为保持稳定性,会拒绝所有信息同步操作,拒绝触发条件按如下配置
min-slaves-to-write 2 //最低slave数量
min-slaves-max-lag 8 //最高延迟
哨兵
一台不提供数据服务的redis服务器,对主从结构每台服务器进行监控,master出故障了通过投票选新master,并将所有slave连到新master
相关配置
port 26379
dir /redis-4.0.0/data
sentinel monitor mymaster 127.0.0.1 6379 2 //命名master节点并配置端口号,并说明有2(通常设定为哨兵个数+1)个哨兵认为master挂了他才是挂了
sentinel down-after-milliseconds mymaster 30000(ms) //多长时间没响应认定为挂
sentinel parallel-syncs mymaster 1 //新的上任后一次有多少个开始同步,根据性能设置
sentinel failover-timeout mymaster 180000(ms) //认定同步超时的时间
启动
redis-sentinel conf/sentinel-2xxxx.conf //配置文件启动法
- 哨兵启动后配置文件会自动发生重写
- 多个监听同个master的哨兵会互相识别,将对方的runid添加到自己的配置文件中
工作原理
阶段一:监控阶段
- sentinel获取master信息
- sentinel获取从属master的slave的信息
- 别的sentinel也获取
- sentinel之间形成一个信息网络,发布订阅,拿到信息后快速扩散
阶段二:通知阶段
维护长期信息对等
阶段三:故障转移阶段
(1)监测阶段发现master下线
flags:SRI_S_DOWN //主观下线:有sentinel发现master挂了
flags:SRI_O_DOWN //客观下线:超过半数sentinel认为他挂了
(2)sentinel之间票选处理此次时间的领头羊
(3)挑选备选master
- 断线的out
- 响应慢的out
- 与原master的连接中关系没那么密切的out
- 优先原则
- 优先级
- offset与master接近的优先
- runid小的优先
(4)sentine发送指令
- 向新的master发送slaveof no one (翻身做主人
- 向其他slave发送slaveof新的masterIP端口
集群
- 分散单台服务器的访问压力,实现负载均衡
- 分散单台服务器的存储压力,实现可扩展性
- 降低单台服务器宕机带来的业务灾难
数据存储设计
每个机器都有一定数量的槽,当加机器时就把槽分摊给新加的机器, 实现可扩展性
每个数据库会相互通信,保存各个库中槽的编号数据
key访问过程
- 通过CRC16(key)计算出一个哈希值,再%16384得出一个值,表示应该放在几号槽
- 假如槽的号码就在A里面,一次命中
- 一次未命中,通过那个信息表,连接客户端直接去到具体位置,最多两次就可命中
配置项
cluster-enabled yes //是一个cluster结点
cluster-config-file nodes-端口号.conf //区分不同服务器的config文件
cluster-node-timeout 10000 //超时下线时间
cluster-migration-barrier <count> //master连接的slave最小数量(可以不设置)
启动
(1)先安装高版本的ruby和rubygem redis依赖
(2)启动服务器
(3)执行redis下src目录的redis-trib.rb命令:
./redis-trib.rb create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384
- 1表示一个master对应1个slave,数字是多少就表示一个master对应几个slave
- 接着输入若干个地址端口号,前面的设置为master,后面的设置为slave,按照顺序从属前面的master
(4)启动客户端要加上-c,表示是cluster集群
注:和哨兵机制一样,master机掉线重启后会变为slave
Cluster节点操作命令
- 查看集群节点信息:cluster nodes
- 进入一个从节点redis,切换其主节点:cluster replicate <master-id>
- 发现一个新节点,新增主节点:cluster meet ip:port
- 忽略一个没有槽的节点:cluster forget <id>
- 手动故障转移:cluster failover