Redis
历史
- 单机:单数据库
- 多机:多数据库,数据库读写分离
- 增加缓存区:优化读的效率
- 设置多个集群(多个读写数据库作为一个集群),提高单点访问量
- 分库分表,MySQL=>memcache
- NoSQL(not only SQL,键值对存储,细粒度缓存,效率高,随取随用),存储高数据量,实时变化的数据。通过缓存存储数据,一定条件下再持久化。
- 3V:海量、多样、实时
- 3高:高并发、高可拓、高性能
Redis命令
一般返回值长度,boolean显示0-1。
string
select []
: 选择数据库,默认0-15flushdb
[] /flushall
: 清除数据库move [key] [db]
:移除当前keykeys *
: 查看数据库所有的keyset [key] [value]
、get [key] [value]
: 使用:分隔符同样可以做到批量插入,set k1:v1 k2 v2.....
exists [key]
: 是否存在keyexpire [key] [time/s]
: 设定自动过期ttl[key]
: 时间type [key]
: 返回键值类型append [key] [string]
: 追加字符串(若key不存在,自动生成key)strlen [key]
: 获取字符串长度incr/decr [key]
: 增1/减1(原子性操作)incrby/decrby [key] [step]
:getrange [key] [start] [end]
: string 读范围[start,end]setrange [key] [offset] [value]
: 替换指定位置开始字符串setex [key] [time/s] [value]
: 设置过期键值setnx [key] [value]
: 如果key不存在,设置键值(分布式锁)mset [key] [value]....
:批量添加键值msetnx
:批量添加键值,原子性操作(一起成功或一起失败)getset [key] [value]
: 先获取再设值
List:
双向链表结构。l开头表示往左插入,r开头表示往右插入.最后一个元素下标为-1,所有元素表示[0,-1]。
lpush/rpush [key] [value]
: 加入队列lpop/rpop [key]
: 移除队头/队尾lindex [key] [index]
: 获取当前index下的值llen [key]
: 返回队列长度lrem [key][count][value]
:移除当前key下指定个数的值,精确匹配ltrim [key][start][end]
: 截取[start,end]的listrpoplpush [source][destination]
: 组合命令lset [key][index][value]
: 添加元素,前提是key存在linsert [key][before/after][element][value]
: 插入第一个遇到的元素的前面或后面,element为具体值。
set:
无序不重复,s开头
sadd [key][value]...
: 加入集合smembers [key]
: 返回所有元素sismember [key][value]
:返回是否有该值scard [key]
: 返回元素个数srem [key][value]...
: 删除指定值srandmember [key][count]
: 随机选取count个元素spop [key]
: 随机移除元素smove [source][destination][member]
: 转移sdiff/sunion/sinter [key] [key]...
: 差集/交集/并集
Hash
map集合,更适合于对象的存储。h开头,key-value—>key-[key-value]
hset [key][field][value]...
hget [key][field]
hmset/hmget
hgetall [key]
: 获得所有的key和valuehdel [key][field]
hlen [key]
hkeys/hvals [key]
:只获取key/valuehincrby/hdecrby [key][field][increment]
- …结合string都差不多。
Zset
有序集合,z开头,在set基础上加了个值用于排序。
-
zadd [key][score][value]
: score提供排序优先级 -
zrangebyscore [key][min][max](withscores)
: 从小到大排序 -
zrevrangebyscore [key][max][min](withscores)
: 从大到小排序 -
zrevrange [key][start][stop]
: 从大到小排(按元素下标) -
zrem [key][value]
-
zcard [key]
: 获取集合中元素个数 -
zcount [key][min][max]
: score在[min,max]区间的元素个数
geospatial
使用 geohash 保存地理位置的坐标,使用有序集合(zset)保存地理位置的集合,适用于zset命令
- 1、GEOADD:增加某个地理位置的坐标
- 2、GEOPOS:获取某个地理位置的坐标
- 3、GEODIST:获取两个地理位置的距离
- 4、GEORADIUS:根据给定地理位置坐标获取指定范围内的地理位置集合
- 5、GEORADIUSBYMEMBER:根据给定地理位置获取指定范围内的地理位置集合
- 6、GEOHASH:获取某个地理位置的 geohash 值,二维的经纬度转化为一维的字符串,字符串越接近表示距离越近。
Hyperloglog
基数统计,占用内存固定,只需12KB。
pfadd
pfcount
: 计数(去重)pfmerge [destkey][sourcekey]...
: 所有source合并为destkey
Bitmaps
位存储,位图,操作二进制位进行记录,0:1。优化了空间存储,提高效率。
setbit [key][offset][value]
bitcount [count]
介绍
Redis 是单线程的,多线程是为处理IO请求
Redis 基于内存操作,无CPU瓶颈。Redis也有事务,本质是一组命令的集合。具有一次性、顺序性、排他性。没有隔离级别的概念。
单条命令保证原子性但事务不保证原子性。
multi
: 开启事务
exec
: 执行事务(根据命令顺序执行)
- 编译型异常:指令有误,所有指令都不执行。
- 运行时异常:运行时出错,其他指令依然可正常执行。(不符合原子性)
discard
: 取消事务
悲观锁
无论什么情况都会加锁
乐观锁
监视数据
watch [key]...
: 充当乐观锁操作
unwatch
: 解锁
误区
- 高性能服务器一定是多线程
- 多线程一定比单线程效率高
原理
Redis将所有数据全部存于内存中且无上下文切换,所有使用单线程时效率很高。
Redis配置文件
Redis持久化
RDB机制
Redis DateBase,Redis默认模式
Redis单独创建一个fork进程,负责将当前时刻的数据以快照(Snapshot)的形式持久化到磁盘中(覆盖原来的rdb文件),持久化过程中主进程不能进行任何IO操作。当要恢复时将快照文件直接读到内存即可。
保存的文件默认名称:dump.rdb
config文件:
save [interval][times]
: 每隔interval时间的数据修改超过times次,就触发rdb操作,及生成dump.rdp文件
触发机制:
save
: 自动触发rdbflushall
shutdown
:退出后自动生成rdb文件
恢复:
- dump文件在默认目录下即可,redis启动时会自动恢复其中的数据。
优点:
- 适合大规模数据恢复
- 对数据完整性要求不高
缺点:
- 它以时间间隔定期保存,一部分数据可能丢失。
- fork进程,会占用一定内存空间
AOF机制
Append Only File
redis会将每一个收到的写命令都通过write函数追加到文件中。通俗的理解就是日志记录。
config配置:
appendonly no
—>appendonly yes
: 开启aof,与adb同时开启时,优先启用aof(安全性更高)
appendfsync always
: 每次修改都会同步,效率低
appendfsync everysec
: 默认开启。每秒执行一次同步,可能丢失数据
appendfsync no
:不执行同步,有操作系统执行数据同步,速度快
修复aof文件:
aof文件损坏时,redis服务将无法开启。可以使用redis-check-aof --fix appendonly.aof
命令修复aof文件(删除了错误数据,只保留正确数据)。
重写:
在当前的快照保存工作结束后,开启一个子进程,将AOF文件进行重写,合并set命令等操作到一个临时文件,达到缩小文件大小的目的。重写结束后后将临时文件替换为新的AOF文件(重写过程中如果有新的redis操作命令,会提交到缓存中,重写结束后追加到AOF文件内)
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64m #aof文件大于64mb时,fork一个新的进程将aof文件进行重写。
优点:
- 每一次修改都同步,文件完整性、一致性好。
缺点:
- 相对于数据文件来说,aof远大于rdb,修复速度也较慢。
- aof 是一种 IO操作,效率要比rdb慢,
Security
requirepass 123456 : 设置密码
config set requirepass [password]
: 设置密码[临时性的]
config get requirepass
auth [password] : 登录操作
订阅和发布
Redis命令
subscribe [channel]
: 创建频道(订阅端)publish [channel][massage]
: 发布信息(发布端)pubsub channels [pattern]
: 返回当前的活跃频道pubsub numsub [channel]..
: 返回频道订阅数量
原理
服务器中维护着一个pubsub_channels字典,所有的频道和订阅关系都存储在这里。字典的键为频道的名称,而值为订阅频道的客户端链表。
发布端发布信息时,服务器会遍历pubsub_channels中对应键的链表,向每一个客户端发送信息。
主从复制
从机负责读,主机负责写。配置文件默认为主机
配置文件:
- 设置从机
-
命令行配置:
slaveof [host][port]
: 临时性配置主从关系slaveof no one
: 重新成为master
复制原理
Slave启动成功连接到master后,发送sync命令。Master接到命令后启动后台存盘进程,同时收集所接受到用于修改的数据集命令,在后台进程执行完毕后,master传送整个数据文件到slave,完成一次完全同步。
-
全量复制
slave服务在接受到数据库文件数据后,将其存盘并加载到内存中。
-
增量复制
master继续将新的所收集到的修改命令依次传给slave,完成同步。
只要是重新连接master,一次完全同步(全量复制)将被自动执行。
哨兵模式(sentinel)
主从切换技术,即当master宕机后,自动配置新的master ,免去了手动配置,提高高可用性。
原理:
后台监控主机是否发生故障,若发生故障则根据投票数自动将从库转化为主库。
哨兵模式作为一种特殊的模式。哨兵作为一个独立的进程,独立运行。哨兵通过发送命令,等待Redis服务器响应,从而监控多个Redis实例。
具体作用:
- 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
- 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅的模式通知其他的从服务器,修改配置文件,让他们切换主机。
哨兵:
sentinel.conf
sentinel monitor [name] [host][port] 1
: 1表示设置投票机制。通过 redis-sentinel [config] 启动哨兵(master转移需要一定时间–心跳包)
单个哨兵进程对Redis服务器监控可能会发生一些问题,这时可以设置多个哨兵进行监控,各个哨兵之间同样会进行监控,形成多哨兵模式。(简单说就是怕哨兵坏了)
具体流程
多个哨兵监视各个主机、从机。当某个哨兵认为该主服务器发生宕机时,即主观下线时,并不会马上进行failover过程,而是需要其他哨兵对该主服务器进行判断,当认定它宕机的数量达到一定值时,才认定它已宕机。此时各个哨兵将进行一次投票,投票最终结果决定新的主服务器,由一个哨兵发起该结果并进行failover故障转移操作(从机–>主机),成功后,通过发布订阅模式,让各个哨兵将各自监控的从服务器实现切换主机,即客观下线。
优点
- 基于主从配置,有它所有的优点
- 主从可切换,故障可转移,高可用
- 手动到自动,更加健壮
缺点
-
Redis不好在线扩容,集群容量一旦达到上限,在线扩容就十分麻烦
-
实现哨兵模式(哨兵集群)的配置十分麻烦。
port 26379 daemonize yes logfile "26379.log" dir "./" sentinel monitor mymaster 192.168.250.132 7000 2 #必要 sentinel down-after-milliseconds mymaster 30000 sentinel parallel-syncs mymaster 1 #默认转移时间 sentinel failover-timeout mymaster 15000 sentinel auth-pass mymaster 123 bind 192.168.250.132 127.0.0.1
Redis 缓存穿透、击穿和缓存雪崩
缓存穿透
缓存穿透,是指查询一个数据库一定不存在的数据。正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。
假如有恶意攻击,就可以利用这个漏洞,对数据库造成压力,甚至压垮数据库。即便是采用UUID,也是很容易找到一个不存在的KEY,进行攻击。
- 采用缓存空值。如果从数据库查询的对象为空,也放入缓存,只是设定的缓存过期时间较短,比如设置为60秒。
缓存击穿
缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
- 互斥锁
- 设置热点key永不过期
缓存雪崩
缓存雪崩,是指在某一个时间段,缓存集中过期失效。
产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。
Redis应用场景
-
计数器
-
统计多单位数量:关注数、浏览量等
-
对象缓存存储
-
消息队列,消息排队 :list
-
共同爱好、共同好友 :set
sdiff/sunion/sinter
-
排行榜 :zset
-
附近的人:geo
-
计算在线用户量:hyperloglog
-
记录打卡信息。。:bitmaps
-
实时聊天,聊天室、订阅、关注:订阅、发布