redis

nosql简介

主要作用:降低io读,串行+单线程+多路io复用技术
nosql不依赖业务逻辑方式存储,而以简单的key-value形式存储。大大增加了数据库的扩展能力

简单命令

  • set key value
  • keys *
  • exists key
  • type key
  • del key
  • unlink//非异步阻塞
  • expire key seconds
  • ttl key//-1永不过期,-2已经过期
  • select 5
  • dasize
  • flushdb
  • flushall

常用数据类型

String

String的数据结构为简单动态字符串。是可以修改的字符串,内部结构有点类似于java的arrayList,采用预分配冗余空间的方式来减少内存的频繁分配。他是二进制安全的,意味着String包含任何数据,比如图片或者序列化对象

扩容方式:实际分配空间一般高于字符串长度,当字符串小于1M时,扩容都是现有空间加倍扩容。超过1M每次扩容1M,最高512M

常用命令
  • set key value
  • get key
  • append key
  • strlen key
  • setnx key value
  • incr key//具有原子性:不会被线程调度机制打断的操作叫原子操作
    • 这种操作一旦开始,就一直运行到结束,中间不会有任何context switch(切换到另一个线程)
      1.在单线程中,能够在单条指令中完成的操作都可以认为是原子操作,因为终端命令只发生在命令之间。
      2.在多线程中,不能被其他线程(进程)打断的操作就叫原子操作
      redis单命令的原子性操作得益于他的单线程
  • decr key
  • incrby key 步长
  • decrby key 步长
  • mget//同时设置一个或多个key-value
  • mset//同时获取一个或多个key-value
  • msetnx//具有原子性,要么全成功或全失败
  • getrange key <起始范围> <结束范围>
  • serrange key <起始范围> <结束范围>
  • setex key <过期时间>
  • getset key value

List

redis列表是简单的字符串列表,按照插入顺序排序。他的底层实际是个双向链表,对双端的操作性能很高,通过索引下标的操作中间节点性能会差

list的数据结构为快速链表quickList。首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,即压缩列表,

它将所有的元素紧挨这一起储存,分配的是一块连续的内存,当数据量比较多的时候才会改为quicklist。因为普通链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里只存int的类型的数据,结构上还需要两个额外的指针prev和next

redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太多的空间冗余

常用命令
  • lpush//从左插入一到多个值
  • rpush//从右插入一到多个值
  • lpop key//从左吐出一个值,吐完键也删除
  • rpop key//从右吐出一个值
  • rpoplpush key1 key2//从key1左边取一个值放到key2左边
  • lrange key <起始范围> <结束范围>//-1取所有
  • lindex key index/按索引下标获取指定位置元素(从左到右,0开始)
  • llen key
  • linsert key before value newvalue//在value后插入newvalue
  • linsert key after value newvalue//在value前插入newvalue
  • lrem key n value//从左边删除n个value元素
  • lset key index value//替换

Set

Set功能类似与list,特殊之处是可以去重。Set是String类型的无序集合,他底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)。

常用命令
  • sadd key value1 value2
  • smember key
  • sismember key value//是否包含value
  • scard key//返回value中的个数
  • srem key value1 value2//移除key中的value1 value2
  • spop key//随机从key中吐出一个值
  • srandmember key n//随机取出n个值,不从集合中删除
  • smove key1 key2 value//从key1中取出value移动到key2
  • sinter key1 key2//返回两个集合中的交集数据
  • sunion key1 key2//返回两个集合中的并集数据
  • sdiff key1 key2//返回两个集合中的差集元素(只包含key1,不包含key2的)

Hash

hash是一个键值对集合。

redis hash是一个String类型的field和value的映射表,hash特别适合储存对象。类似于java中的map

hash类型对应的数据结构是两种:ziplist,hashtable。当数据少时,使用ziplist,多是使用hashtable

常用命令
  • hset key field value
  • hget key field
  • hmset key field1 value field2 value2…
  • hexists key field
  • hkeys key//列出所有field
  • hval key//列出所有value
  • hincrby key field increment//field的值增加increment
  • hsetnx key field value//是否成功添加field value的键值对,field不可重复

Zset

有序集合zset和普通set非常相似,是个没有重复元素的有序字符串集合
不同之处是有序集合的每一个成员都关联了一个评分(score),这个评分被用来按照从最低到最高的方式排序集合中的元素。集合中的元素是唯一的,但是评分可以重复。

因为元素有序,所以你可以很快的根据评分或者次序来获取一个范围的元素

访问有序集合的元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表

sortedSet是Redis提供的非常特殊的一个数据结构,一方面它等价于java中的map<String,Double>,可以给每一个元素赋予一个权重score,另外一方面他又类似于TreesSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次,还可以通过score的范围获取元素的列表。

zset底层使用了两个数据结构

1.hash,hash的作用就是关联了value和score,保障了value的唯一性,还可以通过value找到对应的score

2.跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素
在这里插入图片描述

常用方法
  • zadd key score1 value1 score2 value2
  • zrange key start end [WHTHSCORES]
  • zrangebyscore key min max [WITHSCORES]
  • zrevrangebyscore key max min [WITHSCORES]
  • zincrby key increment value
  • zrem key value
  • zcount key min max
  • zrank key value 返回该值在集合中的排名(0开始)

事务和锁机制

事务简介

redis事务是一个单独的隔离操作:事务中的所有命令都会被序列化,按顺序执行。事务在执行过程中不会被打断
redis事务的主要作用就是串联多个命令防止别的命令插队

命令

  • multi//组队阶段
  • discard//放弃组队
  • exec//执行阶段

悲观锁:每次操作前先上锁,中间别人使用只能等你用完才能用。这种做法同一时间只能一人操作,效率较低

乐观锁:每次操作不上锁,再提交时判断下别人有没有提交,可以使用版本号时间戳等。乐观锁适用于多读应用,这样可以提高吞吐量,

命令
  • watch key…:事务开启之前使用watch命令监视多个key,key有变化事务提交失败
  • unwatch:取消所有key的监视

数据持久化

RDB

在指定的时间间隔内将内存中的数据集快照写入磁盘,恢复时是将快照文件读到内存中

dump.rdb//打开配置文件save 3600

配置

  • save:手动保存,只做保存,其余全阻塞
  • bgsave:redis会在后台做异步快照,同时还正常响应请求
  • stop-writes-on-bgsave-error:磁盘满时关闭写操作,推荐yes
  • rdbcompression:是否压缩
备份

redis单独创建一个子进程来进行持久化,会先将数据写入到一个临时文件中,等持久化文件都结束了,再将这个再将这个临时文件替换持久化文件,整个过程中,主进程是不需要任何IO操作的,这就确保了极高的性能,如果需要大规模的数据恢复,且对于数据的完整性不是非常敏感,那RDB方式要比AOF方式更加高效,RDB的缺点是最后一次持久化文件可能丢失

AOF

aof是以日志的形式来记录每个写操作(增量保存),将redis执行过的所有写指令记录下来,只需追加文件但不许改文件,redis启动之初会读取该文件重新构建数据

异常修复

1.修改默认配置appendonly no为yes
2.如果遇到文件损坏,可以通过reids-check-aof–fixappendonly.aof进行修复
3.备份被写坏的aof文件
4.恢复:重启redis,然后重新加载

优略势

备份机制更稳健,丢失数据概率更低

占用更多磁盘空间,恢复备份速度更慢,每次读写都同步,性能还有一定压力

两个同时开启默认读取aof

使用建议

官方建议都是用,如果对数据不敏感,可单独选用rdb

不建议单独使用aof,因为可能会出现bug

如果只是做缓存,可以都不使用

应用问题解决

缓存穿透

当用户查询一个数据时,redis中没有命中,直接访问数据库,这样的查询变多的时候,会给数据库造成高IO的压力,这就是缓存穿透。
还有一种情况就是用户造假数据,redis中根本没有,在访问数据库,数据库中也没有,本次查询失败,访问增高时会造成服务器瘫痪

解决方案
  1. 对空值缓存:如果一个查询返回空值,直接在redis中对空结果进行缓存,设置一个较短的过期时间,比如5分钟
  2. 设置白名单:使用bitmaps类型定义一个可以访问的白名单,名单id作为bitmaos的偏移量,每次访问和bitmaps里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问
  3. 采用布隆过滤器:它是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)
  4. 实时监控:如果发现redis命中低急速降低,配合运维设置白名单

缓存击穿

redis中的某个key过期了,大量访问这个key,或者包含这个key

数据库访问压力瞬间增加

redis没有出现大量的key过期

redis运行正常,数据库崩溃

解决方案
  1. 预先设置热门数据:在redis访问高峰前,先给热门数据提前存入到redis中,并加时长
  2. 实时调整:现场监控热门数据,实时调整key的过期时长

雪崩

在极少时间段,大量key过期

解决方案
  1. 构建多级缓存架构:nginx缓存+redis缓存+ehcache缓存等
  2. 将缓存失效时间分散开:我们可以在原有失效时间上加一个随机值,比如1-5分钟,这样很难集体失效
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值