首页 > 数据库 >Redis学习经验

Redis学习经验

时间:2023-06-22 22:56:09浏览次数:38  
标签:经验 元素 Redis 指定 value 学习 线程 key

Redis

各位读者朋友你们好,我是你们的好朋友IT黑铁,最近巩固加深Redis中将经验记录了下来,其中若有错误请多指教!

学习途径:

   B站黑马程序员的Redis视频

    注:由于部分ppt图片过于的好和部分知识基本不需要扩展,我就直接截取了黑马程序员的ppt图片,万分感谢!

概述

Redis是一款键值对(key-value)的非关系型(Not Only SQL)数据库,它是基于内存的,存储各种类型的数据。
SQL与NOSQL的比较
1. SQL存储结构化数据,NoSQL存储的数据是非结构化。
2. SQL存储有的是关联的数据,而NoSQL无关联的。
3. 查询命令不相同
4. SQL满足事务ACID的特性,NoSQL基本满足数据一致性(BASE)。

(一) 数据结构及命令

A、 通用命令

Redis的key层次结构:项目名:业务名:类型:id,方便管理。
KEYS:查看符合模板的所有key,不建议在生产环境设备上使用
DEL:删除一个指定的key
EXISTS:判断key是否存在
EXPIRE:给一个key设置有效期,到期后该key被自动删除
TTL:查看一个KEY的剩余有效期

B、 String

该存储类型,value是字符串,最大空间不超过512M,不过根据字符串的格式不同,又可以分为三类:string,普通字符串;int,整数类型,可以做自增、自减操作;float,浮点类型,也可以做自增、自减操作。
不过不管哪种格式,底层都是字节数组形式存储,只是编码方式不同。
SET:添加或者修改已经存在的一个String类型的键值对
GET:根据key获取String类型的value
MSET:批量添加多个String类型的键值对
MGET:根据多个key获取多个String类型的value
INCR:让一个整型的key的value自增1
INCRBY:让一个整型的key的value自增并指定步长
INCRBYFLOAT:让一个浮点类型的数字自增并指定步长
SETNX:根据是否存在,添加一个String类型的键值对
SETEX:添加一个人String类型的键值对,并且指定有效期


C、 HASH

散列类型的value是一个无需字典,类似于Java中的HashMap结构。
Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD。
HSET key filed value:添加或者修改hash类型key的field的value
HGET key field:获取一个hash类型key的field的value
HMSET:批量添加多个hash类型key的field的value
HMGET:批量获取多个hash类型key的field的value
HGETALL:获取一个hash类型的key中的所有的field和value
HKEYS:获取一个hash类型的key中所有的field
HVALS:获取一个hash类型的key中所有的value
HINCRBY:获取一个hash类型key的字段value自增并指定步长
HSETNX:判断field是否存在,添加一个hash类型的key的field的value



D、 List类型

Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。该类型有序、元素可以重复、插入删除快、查询速度一般。
LPUSH key element:向列表左侧插入一个或多个元素
LPOP key:移除并返回列表左侧的第一个元素
RPUSH key element:向列表右侧插入一个或多个元素
RPOP key:移除并返回列表右侧的第一个元素
LRANGE key star end:返回一段角标范围内所有元素
BLPOP和BRPOP:阻塞式取元素。

E、 Set类型

Redis的Set结构与Java中的HashSet类似,可以看做是一个value为null的HashMap。其特征:无序、元素不可重复、查找快、支持交集并集差集等功能。
SADD key member:向set中添加一个或多个元素
SREM key member:移除set中的指定元素
SCARD key:返回set中元素的个数
SISMEMBER key member:判断一个元素是否存在于set中
SMEMBERS:获取set中的所有元素
SINTER key1 key2:求key1与key2的交集
SDIFF key1 key2:求key1与key2的差集





F、 SortedSet类型

Redis中的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加hash表。其特性:可排序、元素不重复、查询速度快。
ZADD key score member:添加一个或多个元素到sorted set,已经存在就更新
ZREM key member:删除sorted set中的一个元素
ZSCORE key member:获取sorted set中指定元素的score的value
ZRANK key member:获取sorted set中指定元素的排名
ZCARD key:获取sorted set中的元素个数
ZCOUNT key min max:统计score值在给定范围内的所有元素的个数
ZINCRBY key increment member:让sorted set中的指定元素自增指定步长
ZRANGE key min max:按照score排序后,获取指定排名范围内的元素
ZRANGEBYSCORE key min max:按照score排序后,获取指定score范围内的元素
ZDIFF、ZINTER‘ZUNION:求差集、并集、交集

H、 GEO类型

GEO代表地理坐标,在Redis3.2版本中加入了对GEO的支持,允许存储地理坐标信息,帮助我们根据经纬度来检索数据。

GEOADD:添加一个地理空间信息。
GEODIST:计算指定的两个点之间的距离并返回。
GEOHASH:将指定member的坐标转为hash字符串形式并返回
GEOPOS:返回指定的member坐标。
GEORADIUS:指定圆心、半径,找到该圆内包含的所有member,并按照与圆心直接的距离排序后返回。6.2版本已废弃。
GEOSEARCH:在指定范围内搜索member,并按照与指定点之间的距离排序后返回。范围可以是圆形或矩形。6.2版本新功能。
GEOSEARCHSTORE:与GEOSEARCH功能一致,不过可以把结果存储到一个指定的key。6.2新功能。

I、 BitMap

Redis利用String类型数据结构实现BitMap,因此最大上限是512M,转换为bit则是2^32个bit位。
SETBIT:向指定位置(offset)存入一个0或1
GETBIT:获取指定位置(offset)的bit值
BITCOUNT:统计BitMap中值为1的bit位的数量
BITFIELD:操作(查询、修改、自增)BitMap中bit数组中的指定位置(offset)的值
BITFIELD_RO:获取BitMap中bit数组,并以十进制形式返回
BITOP:将多个BitMap的结果做位运算(与、或异或)
BITPOS:查找bit数组中指定范围内第一个0或1出现的位置

J、 HyperLogLog

HyperLogLog(HLL)是从LogLog算法派生的概率算法,用于确定非常大的集合的基数,而不需要存储其所有值。Redis的HLL基于String结构实现,单个HLL内存永远小于16kb,内存占用低的令人发指!作为代价,其测量结果是概率性的,有小于0.81%的误差。
PFADD
PFCOUNT
PFMERGE

(二) SpringDataRedis

简介

A、 RedisTemplate的API

B、 RedisTemplate的序列化方式
第一种方式:RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列为字节形式,默认是采用JDK序列化。缺点:可读性差;内存占用较大。
第二种方式:自定义序列化方式。key和hashkey采用string序列化,value和hashValue采用JSON序列化。缺点:为了反序列化,JSON序列化会将class类型写入json结果中,存入Redis,带来额外的内存开销。
第三种方式:手动地转JSON。Spring提供了StringRedisTemplate类,其key和value的序列方式都是String方式,省去自定义过程。

(三) Redis解决集群session不共享问题

(四) Redis缓存更新策略

A、 更新时机

B、 更新策略

选择第一种的原因:第二种还未有该产品服务;第三种虽然效率高,但编码复杂且存在并发问题。

第三个问题:先操作数据库,再删除缓存。因为数据库写操作一般比读操作慢。
C、 小结

(五) 缓存穿透、缓存击穿、缓存雪崩




(六) Redis的其他应用
A、 全局ID生成

解决问题:如果使用数据库自增ID会存在规律性明显、单表数据量的限制(京东淘宝这样的店铺)、唯一性不能保证(分布式数据库里的问题)。

B、 秒杀下单

存在的问题:所有事情都在Tomcat里做,性能较低。

解决方案:将并发安全判断由从数据库取出判断改为在Redis里做。这样做的好处有两点:一、Redis可使用Lua脚本保证原子性,不会引发多线程并发安全问题,就不需要再使用锁,后续使用锁只是兜底的作用,预防万一。二、从Redis里查库存比起数据库里查库存更加高效。


虽然效率问题得到改善,但存在一个问题:异步处理阻塞队列中的数据,是使用Java提供的阻塞队列,这样简陋地处理消息,存在JVM内存限制问题和数据安全问题。
解决方案:引入Redis消息队列MQ。
存在问题:大部分的事情仍然还是费时的。
解决方案:使用多级缓存机制。
C、 超卖问题

小记:悲观锁是任何时候都可用,乐观锁只有更新数据时才能用。


乐观锁虽然能解决并发安全问题,但如果用得不恰当,会导致业务失败率高的问题,如:乐观锁为查询的库存是等于当前查到的库存,该锁会让其他线程不能修改数据成功,但这样并不理想,比如一个优惠券有很多张,而一个在抢,其他人就不能抢了,这并不恰当。所以乐观锁应当是控制安全范围,比如查询的库存大于0就行了。
D、 一人一单(分布式锁问题)

 synchronized (userId.toString().intern()){
// Spring是通过代理做的事务,要得到代理对象,还需在启动类上配置@EnableAspectJAutoProxy(exposeProxy = true)
IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
// createVoucherOrder调用等同于this.createVoucherOrder,这样是非代理对象的调用不具备事务功能。
// return proxy.createVoucherOrder(voucherId);
return proxy.createVoucherOrder(voucherId);
}
 一人一单必须判断订单是否存在,查的时候一个用户可能发起多个线程,就会导致并发安全问题,这里就只能采用悲观锁,且锁的应该是用户id,而不是整个流程方法。
 锁住用户id值(而不锁方法),toString内部也会再创建一个对象,而intern()是去字符串常量池找相同值的对象。
该流程存在的问题:锁是由JVM控制,一个JVM控制多个线程访问共享资源的锁。在集群情况下,有多台JVM,各个JVM只能控制它管辖的线程,外面进程里的线程它就管不着了,就会出现并发安全问题。

解决办法:采用分布式锁。



由于锁有超时时间,存在一个问题:二次释放锁,即当一个线程得到锁后,久久不释放锁,因为超时而被动释放锁,在之后该线程完成了后续操作又手动释放锁。此时如果别的线程得到一个锁,还没等它自己释放自己的锁,就被上一个线程释放掉了(因为锁是唯一的)。这样又有下一个线程可以得到锁,第一个线程和第二个线程这时是“同时”进行修改共享资源,就会出现并发安全问题。

解决办法:锁加入线程标识,释放的时候就可以避免上一个线程释放别人的锁的问题。


按理说上述解决方案已经不会发生释放别人锁的问题了,因为多了一个判断锁值是否是自己的逻辑,而就算是超时了也不会释放别人的锁。但还有更恐怖的情况,如:GC垃圾回收时会阻塞所有代码块,而此时若是上一个线程执行到判断了锁值是自己的,正要进行下面的释放锁流程,而就被阻塞了,导致锁超时被其他JVM的线程得到锁,等到被阻塞的线程恢复了它在阻塞前已经判断了是自己的锁,就会出现误删别人锁的情况。这时第二个线程的锁被释放了,被第三个线程拿到,而第二个线程还没有执行完业务,产生并发安全问题。

解决办法:保证释放锁的原子性,即要么同时成功,要么同时失败,Redis提供了Lua脚本功能。

虽然已经比较完善,但仍然存在下面的问题。

解决方案:第三方Redisson提供了众多Redis解决方案,就包括了分布式锁。

可重入锁是指:一个线程得到一把锁后,其内执行方法若要再申请一把锁,则还能够用这把锁。

可重试实现解决方案:利用了等待时间,剩余存活时间,消息订阅,信号量等机制。
超时释放解决方案:延时任务续约。

主从一致解决方案:联锁,多个节点的锁必须同时申请成功,才能得到一把联锁。

E、 消息队列










F、 点赞排行榜

H、 Feed流







I、 签到


J、 UV统计

(七)分布式Redis

A、 持久化
Redis有两种持久化机制,一种是RDB,一种是AOF。
RDB默认开启,即当Redis关机(服务停止)时,重启会使用RDB恢复数据。





B、 集群架构

通过配置slaveof(永久生效)或客户端连接slave命令(临时),建立主从关系后,主结点可以知道从节点信息。




C、 哨兵




使用redis-sentinel服务来根据不同的配置文件(配置端口,监听的主节点,以及工作目录等)启动哨兵结点,这与redis服务一样。
D、 分片集群

使用redis-server服务根据自定义集群配置文件启动后,再使用redis-cli服务使用创建集群选项建立集群。

扩容:利用redis-cli服务使用选项add node来添加结点,然后再使用选项reshard来转移插槽。
故障转移:不需要使用哨兵,Redis集群自动进行数据迁移。手动故障转移使用failover命令。
(八)多级缓存

本地进程缓存:Caffeine
业务Nginx缓存:OpenResty




(九)缓存预热和缓存同步策略


异步通知有两种方式:一种是基于MQ,一种是基于Canal(零侵入)。


(十)最佳实践

note:key这里指一个数据整体。









Spring封装的template已经实现了并行slot。










(十一) 原理
A、 底层数据结构
动态字符串SDS


note:还有很多不同字节编码的sds结构体

IntSet



Dict







ZipList





QuickList



SkipList

RedisObject



B、 网络模型




阻塞IO

非阻塞IO

IO多路复用







信号驱动IO

异步IO

C、 RESP通信协议


D、 内存策略
过期策略





淘汰策略




相关CASE
(1) RDM安装包:Releases · lework/RedisDesktopManager-Windows (github.com)
(2)
(3) RedisTemplate的哨兵模式
在配置文件中指定Sentinel的信息就行,不需要指定Redis服务集群信息。
(4) 集群配置读写分离

标签:经验,元素,Redis,指定,value,学习,线程,key
From: https://www.cnblogs.com/itdaling/p/17498502.html

相关文章

  • Markdown学习
    Markdown学习标题三级标题四级标题 字体Hello,World!Hello,World!Hello,World!Hello,World! 引用选择狂神说Java,走向人生巅峰 分割线三个-,或者三个* 图片 超链接点击跳转到犬汰twitter  列表ABCABC 表格 名字......
  • 深度学习能量模型/能力学习相关论文、会议、博客资源整理分享
       基于能量的模型(EBM)是生成模型(GM)的一种形式。GM通过分析样本数据集学习基础数据分布。训练后,GM可以产生其他与数据分布相匹配的数据集。EBM为许多此类学习的概率和非概率方法(尤其是图形和其他结构化模型的训练)提供了统一的框架。   EBM学习目标数据集的特征并生成相似但......
  • 一文回顾深度学习发展史上最重要经典模型
        这篇文章的目的是回顾经过时间考验的,被广泛采用的想法。我将介绍一小部分技术,这些技术涵盖了解现代深度学习研究所必需的许多基本知识。如果你是该领域的新手,那么这是一个很好的起点。         深度学习是一个瞬息万变的领域,大量的研究论文和想法可能会令人不知所......
  • 关于我的Shader学习笔记
    由于发布的博客是笔记性质,肯定会在一些方面描述的不够详细。如果对于我的笔记有什么疑问,欢迎私信我提问!本笔记参考书籍:《UnityShader入门精要》冯乐乐著《3D游戏与计算机图形学中的数学方法》《Introductionto3DGameProgrammingwithDir......
  • 基于强化学习的推荐系统相关研究进展、经典论文整理分享
    深度学习与NLP专注深度学习、NLP相关技术、资讯,追求纯粹的技术,享受学习、分享的快乐。677篇原创内容公众号    推荐系统把用户模型中兴趣需求信息和推荐对象模型中的特征信息匹配,同时使用相应的推荐算法进行计算筛选,找到用户可能感兴趣的推荐对象,然后推荐给用户。推荐系统......
  • 深度学习网络架构搜索(NAS)最新必读论文分享
        在过去的很多年深度学习在视觉、语音等方面都已经取得了巨大的成功,其中一个很大的原因就是出现了很多新颖的网络结构——ResNet、MobileNet、ShuffleNet等。随着网络结构越来越复杂,人工设计网络的试错成本和时间成本会难以承受。    超参数的自动搜索优化是一个古老的......
  • 学习笔记-第12天-命令合集11
    1.passwd给用户设置密码用户自己给自己设置密码直接:passwd.[root@localhost~]#passwdChangingpasswordforuserroot.Newpassword:BADPASSWORD:Thepasswordisshorterthan8charactersRetypenewpassword:passwd:allauthenticationtokensupdatedsuccessfu......
  • 跟我一起学Redis之五种基本类型及其应用场景举例
    前言来啦,老弟?来啦,上一篇就当唠唠嗑,接下来就开始进行实操撸命令,计划是先整体单纯说说Redis的各种用法和应用,最后再结合代码归纳总结。Redis默认有16个数据库(编号为0~15),默认使用第0个,通过命令select任意切换数据库,和MySql切换数据库一个道理;各数据库之间的数据是隔离的,先启动服......
  • 学习总结
    这次实训实践操作了对于一款天气系统手机软件的最基本逻辑框架的搭建,学习了OPENHARMONY这个插件的相关使用和学习途径的获取。具体实训内容为:使用了API9的开发版本,实现主要功能构成,主要是理解学习掌握天气软件的具体开发代码和思路,偏向前端开发。学习过程中经常遇到很多配......
  • Redis–内存淘汰机制(涉及到过期策略)
    这个博客的内容包括以下几个点:1.redis内存淘汰机制2.若有大量的key需要设置同一时间过期,一般需要注意什么?3.过期键删除策略4.redis如何保证数据都是热点数据一、redis内存淘汰机制1,概念:内存淘汰机制:redis配置文件可以设置maxmemory,内存的最大使用量,达到限度会执行内存淘汰......