一、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. apktool 回编译报错:No resource identifier found for attribute 'xxxxxx' in package 'android' W:

    C:\xxxx\app-release\res\layout-v26\xxxx.xml:5: error: No resource identifier found for attribute 'xx ...

  2. python2 虚拟环境

    1.安装virtualenv pip install virtualenv 2.创建虚拟环境 virtualenv 虚拟环境名称  3.激活虚拟环境 source 虚拟环境目录/bin/activat ...

  3. python3 虚拟环境 venv

    创建一个虚拟环境: python -m venv test            (test 为创建的虚拟环境目录) 激活虚拟环境: test\Scripts\activate            ...

  4. 如何配置Nginx,实现http访问重定向到https?

    现在越来越多的网站,当我们输入域名时,会自动重定向到https,我们只需要简单修改下Nginx配置文件/usr/local/nginx/conf/nginx.conf(根据个人的实际存储路径)即可. ...

  5. java进阶(40)--wait与notify(生产者与消费者模式)

    文档目录: 一.概念 二.wait的作用 三.notify的作用 四.生产者消费者模式 五.举例 ---------------------------------------分割线:正文------ ...

  6. 使用pr进行视频的剪辑

    本人作为一个经常浪迹在各个小视频的网站的视频界"gai溜子",很是喜欢一些人上传的综艺或者电影的搞笑搞笑小桥段,有的剪辑下来的片段甚至会比我们自己去看还要有意思的多.我认为视频剪辑 ...

  7. SpringCloudAlibaba—微服务概念及SpringCloudAlibaba介绍

    目录 1.1 系统架构演变 1.1.1 单体应用架构 1.1.2垂直应用架构 1.1.3 分布式架构 1.1.4 SOA架构 1.1.5 微服务架构 1.2 微服务架构介绍 1.2.1 微服务架构的常 ...

  8. Leedcode算法专题训练(栈和队列)

    1. 用栈实现队列 232. Implement Queue using Stacks (Easy) Leetcode / 力扣 class MyQueue { Stack<Integer> ...

  9. Docker工具的使用

    初识 Docker jdk的版本问题,环境造成的问题很常见,称为代码的水土不服 把环境和代码一起传过去 软件跨环境迁移的问题就解决了 Docker 是一个开源的应用容器引擎 诞生于 2013 年初,基 ...

  10. 网络编程NIO之Reactor线程模型

    目录 单Reactor线程模型 基于工作线程的Reactor线程模型 多Reactor线程模型 多Reactor线程模型示例 结束语 上篇文章中写了一些NIO相关的知识以及简单的NIO实现示例,但是示 ...