一、redis中的数据结构

1、字符串(String)

SET key value //存入字符串键值对

MSET key value[key value...] //批量存储字符串键值对

SETNX key value //存入一个不存在的字符串键值对

GET key //获取一个字符串键值

MGET key [key ...] //批量获取字符串键值

DEL key //删除一个键

EXPIRE key seconds //设置一个键的过期时间(秒)

INCR key //将key中存储的数字加1

DECR key //将key中存储的数字减1

使用场景

单值缓存(一般用于库存扣减) SET key value GET key

对象缓存 (常用对象) SET key value(json格式字符串)

分布式锁 SETNX product:10010

计数器(文章阅读量) INCR article:reedcount:0 (因为redis是单线程,能够保证原子性)

Web集群session共享 spring session + redis实现session共享

分布式系统的全局序列号(数据库分库分表???)

2、哈希(hash)类似Map<String Map<String,String>>

HSET key field value //存储一个哈希表key的键值

HGET key field //获取哈希表key对应的field键值

HDEL key field //删除哈希表key中的field键值

HLEN key //返回哈希表key中的数量

HGETALL key //返回哈希表key中的所有键值

HSETNX key field value //存储一个不在的哈希表key的键值

HMSET key field value ... //在一个哈希表key中存储多个键值对

HMGET key field //批量获取哈希表key中的多个键值

使用场景

购物车 以用户id为key 商品id为field 商品数量为value

hset cart:userId productId num(某某用户在购物车中添加某某商品的数量)

a、添加商品 hset: cart:1001 10088 1

b、增加商品 hincrby cart:1001 10088 1

c、商品总数 hlen cart:1001

d、删除商品 hdel cart:1001 10088

e、获取购物车所有商品 hgetall cart:1001

优点:同类数据归类整合存储,方便数据管理、相比string操作消耗内存与cpu更小、相比string存储更节省空间。

缺点:过期功能不能使用在field上,只能用在key上、redis集群架构下不适合大规模使用。

3、列表(list)

LPUSH key value[...] // 将一个或者多个value插入到key列表的表头(最左边)

RPUSH key value[...] //同上(最右边)

LPOP key //移除并返回key列表的头元素

RPOP key //移除并返回key列表中的尾元素

LRANGE key start stop //返回列表key中指定区间内的元素,区间以偏移量start和stop指定

应用场景

常用数据结构 Stack(栈) = LPUSH + LPOP FILO(先进后出)、QUEUE(队列) LPUSH + RPOP (先进先出)、Blocking MQ(阻塞队列) = LPUSH + BRPOP。

微信和微博公众号信息流,列如:我关注了楼市新说、备胎说车等公众号。

a、楼市新说发了公众号,消息id为10018,LPUSH msg:{我--ID} 10018

b、备胎说车发微博 消息id为10086 LPUSH msg:{我--ID} 10086

c、查看最新微博消息 LRANGE msg:{我--ID} 0 5

4、集合(set)

SADD key member[member...] //往集合key中存入元素,元素存在则忽略

SREM key member [memeber...]//从集合key中删除元素

SMEMBERS key //获取集合key的所有元素

SCARD key //获取集合key的元素个数

SISMEMBER key member //判断member元素是否存在于集合key中

SRANDMEMBER key [count] //从集合key中选出count个元素,元素不从key中删除

SPOP key [count] //从集合key中选出count个元素,元素从key中删除

Set运算符

SINTER key //交集运算

SUNION key //并集运算

SDIFF key //差集运算

SINTERSTORE des key //将交集结果存入新集合des中

SUNIONSTORE des key

SDIFFSTORE des key

应用场景

微信抽奖小程序

a、点击参与抽奖加入集合 SADD key {userId}

b、查看参与抽奖所有用户 SMEMBERS key

c、抽取count名中奖者 SRANDMEMBER key [count] / SPOP key [count]

微信微博的点赞,收藏,标签

点赞 SADD like:{消息ID} 用户ID、取消点赞 SIDREM like:{消息ID} 用户ID

检查用户是否点赞 SISMEMBER like:{消息ID} 用户ID

获取点赞列表 SMEMBERS like:{消息ID}、获取点赞用户数 SCARD like:{消息ID}

集合操作:哔哩哔哩关注模型

5、有序集合(zset)

二、Reids分布式锁(主要redis是单线程模型)

synchronized(this){
//获取redis中的库存
int stock = redisTemplate.opsForValue().get("stock");
//判断库存是否大于零
if(stock > 0){
//减库存
int realStock = stock - 1;
//从新往redis中set库存
redisTemplate.opsForValue().set("stock",realStock);
}else{
log.info("库存不足");
}
}
//该场景只支持单体应用,因为synchronized只针对JVM的Java进程,分布式场景不适用。
{
//类似jedis.setnx("lockKey","lock")
String lockKey = "lockKey";
String uuid = UUID.randomUUID().toString
try{
//设置锁超时时间,业务逻辑还没有执行完,锁超时时间已经过了,这时存在风险(锁失效,解锁乱套)。
//在加锁和解锁之间开辟新线程(定时器不断续命,三分之一),用于续命redis中的lockKey
Boolean result = redisTemplate.opsForValue().
setIfAbsent(lockKey,uuid,10,TimeUnit.SECONDS); if(!result){
return "系统繁忙,请稍后重试";
}
//获取redis中的库存
int stock = redisTemplate.opsForValue().get("stock");
//判断库存是否大于零
if(stock > 0){
//减库存
int realStock = stock - 1;
//从新往redis中set库存
redisTemplate.opsForValue().set("stock",realStock);
}else{
log.info("库存不足");
}
}finally{ if(uuid.equals(redisTemplate.opsForValue().get(lockKey))){
//如果在加锁和解锁之间出现异常,就无法解锁(死锁) 因此使用try{}finally{}
//如果在加锁和解锁之间web应用挂了(如手动杀进程),redis怎样释放锁,此时设置锁的有效期。
redisTemplate.delete(lockKey);
} } }

{
try{
redissionLock.lock(30,TimeUnit.SECONDS);
//获取redis中的库存
int stock = redisTemplate.opsForValue().get("stock");
//判断库存是否大于零
if(stock > 0){
//减库存
int realStock = stock - 1;
//从新往redis中set库存
redisTemplate.opsForValue().set("stock",realStock);
}else{
log.info("库存不足");
}
}finally{
redissionLock.unlock();
}
}

  

三、持久化

1、RDB(默认开启,文件名dump.rdb,该文件的位置和redis.conf中的配置有关)

原理是redis会单独创建(fork)一个与当前进程一模一样的子进程来进行持久化,这个子进程的所有数据(变量、环境变量、程序计数器等)都和原进程一模一样,会先将数据写入一个临时文件中,待持久化结束再将这个临时文件替换上次持久化好的文件,整个过程主进程不进行任何io操作,这可以保证极高的性能。

触发时机

a、shutdown 前提是没有开启aof。redis.conf使用的默认快照配置。

b、执行save或者bgsave,save是不开辟新进程,此时其他操作全部阻塞,bgsave 会fork子进程,异步进行。

2、aof(相比rdb更不容易丢失数据,几乎每秒执行一次备份)

原理是将redis的操作日志(格式redis协议、库、命令)以追加的形式写入文件,读操作不记录。

触发时机

no:表示等操作系统进行数据缓存同步到磁盘(快,持久化没保证)。

always:同步持久化,每次发生数据变更时,立即记录到磁盘(慢,安全)。

everysec:表示每秒同步一次(默认值,很快,但可能会丢失一秒以内的数据)

aof重写机制(文件瘦身)

当AOF文件增长到一定大小时Redis能够调用bgrewriteaof对日志文件进行重写。当AOF文件大小的增长率大于该配置(auto-aof-rewrite-percentage 100 超过原大小的100%)时自动开启重写,还有一种场景就是当AOF文件大小大于该配置(auto-aof-rewrite-min-size 64mb)时仍自动开启重写。

注意:redis提供了rdb持久化方案,为什么还提供aof,主要目的是优化数据丢失,并且当rdb和aof同时开启时,aof的优先级高于rdb。redis主从集群是无法关闭rdb持久化的,因为从机需要使用该机制同步数据。一般rdb和aof都会同时开启。

四、集群

1、redis单机架构存在的问题:单机故障、容量瓶颈、qps(Queries-per-second)瓶颈
2、主从复制(读写分离、容灾备份)==》主要能解决 qps(Queries-per-second)瓶颈

主机挂了,不会重新推选主机。只能认为干涉

3、哨兵模式(主从复制的升级版)主要解决单机故障,但是再转移期间不可用。

监控主机,如果主机挂了,会通过哨兵节点重新从从机中推选出主机。

4、redis cluster集群

多主集群,每个主都有从,存数据之前会先hash key,根据hash后的值存放到不同的主机上。其中一个主机挂了,其他主机仍可用,并且会自动迁移。

五、缓存

1、缓存穿透

指使用不存在的key进行大量的高并发查询,这导致缓存无法命中,每次请求都需要穿透到后端数据库系统进行查询,数据库压力过大。

解决方案:将空值缓存起来 ,布隆过滤器(目前不了解)

2、缓存击穿

缓存中没有但是数据库中有数据(可以理解缓存时间到期了),这时由于并发用户特别多,同时读取缓存没有读取到数据,只能去读取数据库,导致数据库压力过大。

解决方案:互斥锁 如果项目不会多部署则可以使用JVM锁,如果会多部署使用分布式锁

3、缓存雪崩

指缓存服务器重启(挂了)或者大量缓存数据集中在某一段时间内失效。

解决方案:搭建高可用集群,保证机器的高可用。另一种就是对数据使用不同的失效时间,甚至对相同的数据,不同的请求使用不同的失效时间。

4、缓存与数据库数据一致性(两个线程更新相同id的信息,一个先更新缓存后更新数据库,一个先更新数据库后更新缓存)

先删除缓存,在修改数据库。如果数据库修改失败,那么数据库中是旧数据,缓存中是空,那么数据不会不一致,因为读的时候缓存没有,需要从数据库获得,然后再set到缓存中。但是仍然存在问题,就是在删除缓存以后B线程查询该key,发现不存在,只能从数据库查询此时A线程还没有更新该数据,这时缓存中的数据还是原本的。

解决方案:延时双删、串行化(通过队列方式)

缓存击穿和缓存雪崩本质都是缓存穿透的特殊表现

redis的数据结构、使用场景、持久化方式以及常见面试问题的更多相关文章

  1. redis各种数据结构使用场景

    一.redis 数据结构使用场景 原来看过 redisbook 这本书,对 redis 的基本功能都已经熟悉了,从上周开始看 redis 的源码.目前目标是吃透 redis 的数据结构.我们都知道,在 ...

  2. Redis的两种数据持久化方式比较

    RDB(Redis Database) 本质:基于时间点的快照 优点: 1.RDB格式文件体积小. 2.可以通过脚本执行bgsave(非阻塞)或者save(阻塞)命令自定义时间点进行备份. 3.可以保 ...

  3. redis内存数据的持久化方式

    转: http://blog.csdn.net/wzqzhq/article/details/64920996 概述 Redis的强大性能很大程度上都是因为所有数据都是存储在内存中的,然而当Redis ...

  4. 一文带你深入了解 Redis 的持久化方式及其原理

    Redis 提供了两种持久化方式,一种是基于快照形式的 RDB,另一种是基于日志形式的 AOF,每种方式都有自己的优缺点,本文将介绍 Redis 这两种持久化方式,希望阅读本文后你对 Redis 的这 ...

  5. Update(stage3):第1节 redis组件:7、持久化

    7.redis的持久化 由于redis是一个内存数据库,所有的数据都是保存在内存当中的,内存当中的数据极易丢失,所以redis的数据持久化就显得尤为重要,在redis当中,提供了两种数据持久化的方式, ...

  6. Redis 详解 (七) AOF 持久化

    目录 1.AOF简介 2.AOF 配置 3.开启 AOF 4.AOF 文件恢复 5. AOF 重写 6.AOF的优缺点 上一篇文章我们介绍了Redis的RDB持久化,RDB 持久化存在一个缺点是一定时 ...

  7. Redis学习笔记(4)——Redis五大数据结构介绍以及应用场景

    出处:https://www.jianshu.com/p/f09480c05e42 Redis是典型的Key-Value类型数据库,Key为字符类型,Value的类型常用的为五种类型:String.H ...

  8. 2017-4-20/Redis的数据结构及应用场景

    1. 谈谈你对redis的理解,它的应用场景. Redis是一个key-value存储系统,它支持存储的value类型包括string字符串.list链表.set集合.sorted Set有序集合和h ...

  9. Redis 数据结构使用场景

    转自http://get.ftqq.com/523.get 一.redis 数据结构使用场景 原来看过 redisbook 这本书,对 redis 的基本功能都已经熟悉了,从上周开始看 redis 的 ...

随机推荐

  1. java例题_50 题目:有五个学生,每个学生有 3 门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成 绩),计算出平均成绩,将原有的数据和计算出的平均分数存放在磁盘文件"stud"中。

    1 /*50 [程序 50 文件 IO] 2 题目:有五个学生,每个学生有 3 门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成 3 绩),计算出平均成绩,将原有的数据和计算出的平均分数存放 ...

  2. SqlServer游标的创建与使用

    前言 大家都对SqlServer视图.存储过程.触发器的创建与使用有一定的了解了,我们来看下什么是游标,怎么使用,什么时候用. SqlServer视图的创建与使用 SqlServer存储过程的创建与使 ...

  3. Dapper, Ef core, Freesql 插入大量数据性能比较(一)

    需求:导入9999行数据时Dapper, Ef core, Freesql 谁的性能更优,是如何执行的,级联增加谁性能更佳. 确认方法:sql server 的 sys.dm_exec_query_s ...

  4. WPF -- 使用当前进程打开自定义文件的一种方式

    问题描述 当双击打开自定义格式的文件时,希望使用当前正在运行的进程,而不是另起一个进程. 本文介绍一种方式解决如上问题,方案参考user3582780的解答 设置自定义文件格式的默认打开方式 参考链接 ...

  5. 个人阅读作业#2——软工模式&CI/CD

    项目 内容 这个作业属于哪个课程 2021春季软件工程(罗杰 任健) 这个作业的要求在哪里 个人阅读作业#2 我在这个课程的目标是 从实践中学习软件工程相关知识(结构化分析和设计方法.敏捷开发方法.软 ...

  6. 关于C语言解决汉诺塔(hanoi)问题

    C语言解决汉诺塔问题 汉诺塔是典型的递归调用问题: hanoi简介:印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔.不论白天黑夜,总有一个僧侣 ...

  7. Go+gRPC-Gateway(V2) 微服务实战,小程序登录鉴权服务(五):鉴权 gRPC-Interceptor 拦截器实战

    拦截器(gRPC-Interceptor)类似于 Gin 中间件(Middleware),让你在真正调用 RPC 服务前,进行身份认证.参数校验.限流等通用操作. 系列 云原生 API 网关,gRPC ...

  8. docker安装mysql5.6镜像并进行主从配置

    docker安装mysql镜像并进行主从配置 1.去DaoCloud官网(dockerhub可能因为网速问题下载的慢)查找需要的mysql版本镜像 docker pull daocloud.io/li ...

  9. 【pytest官方文档】解读Skipping test functions,跳过测试用例详解

    有时候,为了满足某些场景的需要,我们知道有些测试函数在这时候肯定不能执行,或者执行了也会失败.那么我们 可以选择去跳过这个测试函数,这样也就不会影响整体的测试函数运行效果,不至于在你运行的众多绿色通过 ...

  10. 让你的Windows/Linux玩上Switch!

    1 前言 某天在Github上面看到了两个Switch的模拟器: yuzu Ryujinx 于是就想动手想尝试一下在Linux上面玩上Switch. 本文首先简单介绍一下两个模拟器,接着是两个模拟器的 ...