基于redis做缓存分页

基于redis做缓存分页,第1张

在实际业务中我们会将一些热数据缓存到redis里面,这时候数据量比较大的话,我们就要对这些热数据进行分页,分页的方式有2种:

第一:从redis拿出所有数据后,再做内存分页(不推荐),热点数据小的时候可以这样做,性能相差不是很大,但是当数据量大的时候,分页期间就会占用大量内存,或撑爆;

第二:基于redis的数据结构做缓存分页,这里又分2种

①:基于redis的list数据结构,直接通过list的数据结构,用range方法可以进行分页,在数据量大的时候,性能也很可观,但是当存在接口高并发访问时,这个list可能会无限延长,且里面的数据会存在很多重复,这就会影响到正常的业务(不是很推荐);

②:基于redis的ZSet数据结构,通过Zset这个有序集合我们也可以做分页,同样也是用range方法,但是这里比较麻烦的是在初始化数据的时候Zset必须存放TypedTuple类型的数据,这个类型是一个value和score的键值对,具体可以查百度,这个score的生成比较麻烦我这边测试时用的是当前数据在这个list的位置,然后Zset是根据这个score值来排序的,默认是从小到大;用这个的好处是,即使在高并发情况下Zset中也不会存在重复数据从而影响正常的业务;而且分页效率也和list结构差不多;

③:用hash和Zset来一起实现;这个是问了一个朋友和得知的,Zset中存储有序的id字段,通过分页后拿到id,然后再用id去hash中取,感觉应该效率相差不大的,只是中间多了层从hash结构取,还需要维护又一个hash;(为何这样做我也不清楚);

贴一张我测试list和ZSet的结果图

String、Hash、List、Set和Zset。

等同于java中的, Map<String,String> string 是redis里面的最基本的数据类型,一个key对应一个value。

应用场景 :String是最常用的一种数据类型,普通的key/value存储都可以归为此类,如用户信息,登录信息和配置信息等;

实现方式 :String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr、decr等 *** 作(自增自减等原子 *** 作)时会转成数值型进行计算,此时redisObject的encoding字段为int。

Redis虽然是用C语言写的,但却没有直接用C语言的字符串,而是自己实现了一套字符串。目的就是为了提升速度,提升性能。 Redis构建了一个叫做简单动态字符串(Simple Dynamic String),简称SDS。

Redis的字符串也会遵守C语言的字符串的实现规则,即 最后一个字符为空字符。然而这个空字符不会被计算在len里头。

Redis动态扩展步骤:

Redis字符串的性能优势

常用命令 :set/get/decr/incr/mget等,具体如下;

ps:计数器(字符串的内容为整数的时候可以使用),如 set number 1。

补充:

等同于java中的: Map<String,Map<String,String>> ,redis的hash是一个string类型的field和value的映射表, 特别适合存储对象。 在redis中,hash因为是一个集合,所以有两层。第一层是key:hash集合value,第二层是hashkey:string value。所以判断是否采用hash的时候可以参照有两层key的设计来做参考。并且注意的是, 设置过期时间只能在第一层的key上面设置。

应用场景 :我们要存储一个用户信息对象数据,其中包括用户ID、用户姓名、年龄和生日,通过用户ID我们希望获取该用户的姓名或者年龄或者生日;

实现方式 :Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口。如,Key是用户ID, value是一个Map。 这个Map的key是成员的属性名,value是属性值 。这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 也就是通过 key(用户ID) + field(属性标签) 就可以 *** 作对应属性数据。 当前HashMap的实现有两种方式 :当HashMap的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,这时对应的value的redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时redisObject的encoding字段为int。

常用命令 :hget/hset/hgetall等,具体如下:

等同于java中的 Map<String,List<String>> ,list 底层是一个链表,在redis中,插入list中的值,只需要找到list的key即可,而不需要像hash一样插入两层的key。 list是一种有序的、可重复的集合。

应用场景 :Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现;

实现方式 :Redis list的实现为一个 双向链表 ,即可以支持反向查找和遍历,更方便 *** 作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括 发送缓冲队列 等也都是用的这个数据结构。

常用命令 :lpush/rpush/lpop/rpop/lrange等,具体如下:

性能总结 :

它是一个字符串链表,left、right都可以插入添加。

等同于java中的 Map<String,Set<String>> ,Set 是一种无序的,不能重复的集合。并且在redis中,只有一个key它的底层由hashTable实现的,天生去重。

应用场景 :Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动去重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且 set提供了判断某个成员是否在一个set集合内的重要接口 ,这个也是list所不能提供的;如保存一些标签的名字。标签的名字不可以重复,顺序是可以无序的。

实现方式 :set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。

常用命令 :sadd/spop/smembers/sunion等,具体如下:

ZSet(Sorted Set:有序集合) 每个元素都会关联一个double类型的分数score,分数允许重复,集合元素按照score排序( 当score相同的时候,会按照被插入的键的字典顺序进行排序 ),还可以通过 score 的范围来获取元素的列表。

应用场景 :Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以 通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。 当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。

底层实现 : zset 是 Redis 提供的一个非常特别的数据结构,常用作排行榜等功能,以用户 id 为 value ,关注时间或者分数作为 score 进行排序。实现机制分别是 zipList 和 skipList 。规则如下:

zipList:满足以下两个条件

skipList:不满足以上两个条件时使用跳表、组合了hash和skipList

为什么用skiplist不用平衡树?

主要从内存占用、对范围查找的支持和实现难易程度这三方面总结的原因。

拓展:mysql为什么不用跳表?

常用命令 :zadd/zrange/zrem/zcard等;

官网地址: >

当同时满足以下条件时,使用ziplist编码:

SpringBoot—实现n秒内出现x个异常报警

思路:

借助Redis的zSet集合,score存储的是异常时的时间戳,获取一定时间范围内的set集合。判断set个数是否满足条件,若满足条件则触发报警;

注意点:

相关API:

Redis实现延迟队列方法介绍

基于Redis实现DelayQueue延迟队列设计方案

相关API:

SpringBoot2x—使用Redis的bitmap实现布隆过滤器(Guava中BF算法)

布隆过滤器: 是专门用来检测集合中是否存在特定元素的数据结构。

存在误差率: 即将不在集合的元素误判在集合中。

所以布隆过滤器适合查询准确度要求没这么苛刻,但是对时间、空间效率比较高的场景。

实现方式:Redis实现布隆过滤器——借鉴Guava的BF算法:

SpringBoot2x中使用Redis的bitmap结构(工具类)

注意:bitmap使用存在风险,若仅仅计算hash值,会导致bitmap占用空间过大。一般需要对hash值进行取余处理。

根据Redis是否存在key,判断锁是否被获取;

锁应该是一个对象,记录持有锁的线程信息、当前重入次数。所以应该使用Redis的Hash结构来存储锁对象。

31 网络波动造成释放锁失败怎么解决?

需要为锁加上超时时间;

32 任务未执行完毕时,锁由于超时时间被释放?

线程一旦加锁成功,可以启动一个后台线程,每隔多少秒检查一次,如果线程还持有锁,可以不断延长锁的生存时间。

主从切换时,从服务器上没有加锁信息,导致多个客户端同时加锁。

list结构底层是ziplist/quicklist(可看着一个双端队列)。常用命令

使用list作为对象的缓存池。通过rpush放入对象,通过lpop取出对象。

若是阻塞取,可以使用blpop命令实现。

Redis和Lua脚本(实现令牌桶限流)

数据结构选择hash。

hash里面维护:最后放入令牌时间、当前桶内令牌量、桶内最大数量、令牌放置速度(元数据)。

被动式维护:

命令:incr原子累加;

对一段固定时间窗口内的请求进行计数,如果请求数超过了阈值,则舍弃该请求;如果没有达到设定的阈值,则接受该请求,且计数加1。当窗口时间结束,重置计数器为0。

优点:实现简单,容易理解;

缺点:流量曲线可能不够平滑,有“突刺现象”。

1 一段时间内(不超过时间窗口)系统服务不可用。 比如窗口大小1s,限流为100,恰好某个窗口第1ms来了100个请求,然后2ms-999ms请求都会被拒绝。这段时间用户会感觉系统服务不可用(即不够平滑)。

2 窗口切换时可能会出现两倍于阈值流量的请求。 比如窗口大小1s,限流大小100,然后在某个窗口的第999ms有100个请求,窗口前期没有请求。所以这100个请求都会通过。然后下一个窗口的第1ms又来100个请求,然后全部通过。其实也是1ms内通过的200个请求。

命令:Redis的incr命令

是对固定窗口计数器的优化,解决的是切换窗口两倍阈值流量的场景。

具体解决方案是:将限流窗口分为多个小的限流窗口,各个限流窗口分别计数。当前时间大于窗口最大时间时,将头部的小窗口数据舍弃,尾部新增小窗口来处理新请求。

优点:本质上是对固定窗口的优化

[Redis] redis-cli 命令总结

Redis提供丰富命令(command)数据库各种数据类型进行 *** 作些commandLinux终端使用

编程比使用Redis Java语言包些命令都应面Redis提供命令做总结

官网命令列表: (英文)

1、连接 *** 作相关命令

quit:关闭连接(connection)

auth:简单密码认证

2、value *** 作命令

exists(key):确认key否存

del(key):删除key

type(key):返值类型

keys(pattern):返满足给定pattern所key

randomkey:随机返key空间key

rename(oldname, newname):key由oldname重命名newname若newname存则删除newname表示key

dbsize:返前数据库key数目

expire:设定key间(s)

ttl:获key间

select(index):按索引查询

move(key, dbindex):前数据库key转移dbindex索引数据库

flushdb:删除前选择数据库所key

flushall:删除所数据库所key

3、String *** 作命令

set(key, value):给数据库名称keystring赋予值value

get(key):返数据库名称keystringvalue

getset(key, value):给名称keystring赋予value

mget(key1, key2,…, key N):返库string(名称key1key2…)value

setnx(key, value):存名称keystring则向库添加string名称key值value

setex(key, time, value):向库添加string(名称key值value)同设定期间time

mset(key1, value1, key2, value2,…key N, value N):同给string赋值名称key istring赋值value i

msetnx(key1, value1, key2, value2,…key N, value N):所名称key istring都存则向库添加string

名称key i赋值value i

incr(key):名称keystring增1 *** 作

incrby(key, integer):名称keystring增加integer

decr(key):名称keystring减1 *** 作

decrby(key, integer):名称keystring减少integer

append(key, value):名称keystring值附加value

substr(key, start, end):返名称keystringvalue串

4、List *** 作命令

rpush(key, value):名称keylist尾添加值value元素

lpush(key, value):名称keylist添加值value 元素

llen(key):返名称keylist度

lrange(key, start, end):返名称keyliststart至end间元素(标0始同)

ltrim(key, start, end):截取名称keylist保留start至end间元素

lindex(key, index):返名称keylistindex位置元素

lset(key, index, value):给名称keylistindex位置元素赋值value

lrem(key, count, value):删除count名称keylist值value元素

count0删除所值value元素count>0至尾删除count值value元素count<0尾删除|count|值value元素

lpop(key):返并删除名称keylist首元素 rpop(key):返并删除名称keylist尾元素

blpop(key1, key2,… key N, timeout):lpop命令block版本

即timeout0若遇名称key ilist存或该list空则命令结束

timeout>0则遇述情况等待timeout秒问题没解决则keyi+1始list执行pop *** 作

brpop(key1, key2,… key N, timeout):rpopblock版本参考命令

rpoplpush(srckey, dstkey):返并删除名称srckeylist尾元素并该元素添加名称dstkeylist部

5、Set *** 作命令

sadd(key, member):向名称keyset添加元素member

srem(key, member) :删除名称keyset元素member

spop(key) :随机返并删除名称keyset元素

smove(srckey, dstkey, member) :member元素名称srckey集合移名称dstkey集合

scard(key) :返名称keyset基数

sismember(key, member) :测试member否名称keyset元素

sinter(key1, key2,…key N) :求交集

sinterstore(dstkey, key1, key2,…key N) :求交集并交集保存dstkey集合

sunion(key1, key2,…key N) :求并集

sunionstore(dstkey, key1, key2,…key N) :求并集并并集保存dstkey集合

sdiff(key1, key2,…key N) :求差集

sdiffstore(dstkey, key1, key2,…key N) :求差集并差集保存dstkey集合

smembers(key) :返名称keyset所元素

srandmember(key) :随机返名称keyset元素

6、zset(sorted set) *** 作命令

zadd(key, score, member):向名称keyzset添加元素memberscore用于排序该元素已经存则根据score更新该元素顺序

zrem(key, member) :删除名称keyzset元素member

zincrby(key, increment, member) :名称keyzset已经存元素member则该元素score增加increment;

否则向集合添加该元素其score值increment

zrank(key, member) :返名称keyzset(元素已按score排序)member元素rank(即index0始)

若没member元素返nil

zrevrank(key, member) :返名称keyzset(元素已按score排序)member元素rank(即index0始)

若没member元素返nil

zrange(key, start, end):返名称keyzset(元素已按score排序)indexstartend所元素

zrevrange(key, start, end):返名称keyzset(元素已按score排序)indexstartend所元素

zrangebyscore(key, min, max):返名称keyzsetscore >= min且score <= max所元素

zcard(key):返名称keyzset基数 zscore(key, element):返名称keyzset元素element

score zremrangebyrank(key, min, max):删除名称keyzsetrank >= min且rank <= max所元素

zremrangebyscore(key, min, max) :删除名称keyzsetscore >= min且score <= max所元素

zunionstore / zinterstore(dstkeyN, key1,…,keyN, WEIGHTS w1,…wN, AGGREGATE SUM|MIN|MAX):Nzset求并集交集

并集合保存dstkeyN于集合每元素score进行AGGREGATE运算前都要乘于WEIGHT参数

没提供WEIGHT默认1默认AGGREGATESUM即结集合元素score所集合应元素进行SUM运算值MINMAX指

结集合元素score所集合应元素值值

7、Hash *** 作命令

hset(key, field, value):向名称keyhash添加元素fieldvalue

hget(key, field):返名称keyhashfield应value

hmget(key, field1, …,field N):返名称keyhashfield i应value

hmset(key, field1, value1,…,field N, value N):向名称keyhash添加元素field ivalue i

hincrby(key, field, integer):名称keyhashfieldvalue增加integer

hexists(key, field):名称keyhash否存键field域

hdel(key, field):删除名称keyhash键field域

hlen(key):返名称keyhash元素数

hkeys(key):返名称keyhash所键

hvals(key):返名称keyhash所键应value

hgetall(key):返名称keyhash所键(field)及其应value

8、持久化

save:数据同步保存磁盘

bgsave:数据异步保存磁盘

lastsave:返功数据保存磁盘Unix戳

shundown:数据同步保存磁盘关闭服务

9、远程服务控制

info:提供服务器信息统计

monitor:实转储收请求

slaveof:改变复制策略设置

config:运行配置Redis服务器

以上就是关于基于redis做缓存分页全部的内容,包括:基于redis做缓存分页、Redis --- 八种数据类型(基本命令)、Redis使用bitmap、zset、hash、list等结构完成骚 *** 作等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/10169126.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-06
下一篇 2023-05-06

发表评论

登录后才能评论

评论列表(0条)

保存