首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
182 阅读
2
php接口优化 使用curl_multi_init批量请求
144 阅读
3
《从菜鸟到大师之路 ElasticSearch 篇》
107 阅读
4
2024年备考系统架构设计师
104 阅读
5
PHP 文件I/O
92 阅读
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
登录
Search
标签搜索
php函数
php语法
性能优化
安全
错误和异常处理
问题
vue
Composer
Session
缓存
框架
Swoole
api
并发
异步
正则表达式
php-fpm
mysql 索引
开发规范
协程
dafenqi
累计撰写
786
篇文章
累计收到
28
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
10
篇与
的结果
2023-08-30
Redis 使用的 10 个小技巧
Redis 使用的 10 个小技巧Redis 在当前的技术社区里是非常热门的。从来自 Antirez 一个小小的个人项目到成为内存数据存储行业的标准,Redis已经走过了很长的一段路。随之而来的一系列最佳实践,使得大多数人可以正确地使用 Redis。下面我们将探索正确使用 Redis 的10个技巧。1、停止使用 KEYS *Okay,以挑战这个命令开始这篇文章,或许并不是一个好的方式,但其确实可能是最重要的一点。很多时候当我们关注一个redis实例的统计数据,我们会快速地输入”KEYS *”命令,这样key的信息会很明显地展示出来。平心而论,从程序化的角度出发往往倾向于写出下面这样的伪代码:for key in 'keys *': doAllTheThings()但是当你有1300万个key时,执行速度将会变慢。因为KEYS命令的时间复杂度是O(n),其中n是要返回的keys的个数,这样这个命令的复杂度就取决于数据库的大小了。并且在这个操作执行期间,其它任何命令在你的实例中都无法执行。作为一个替代命令,看一下 SCAN 吧,其允许你以一种更友好的方式来执行… SCAN 通过增量迭代的方式来扫描数据库。这一操作基于游标的迭代器来完成的,因此只要你觉得合适,你可以随时停止或继续。2、找出拖慢 Redis 的罪魁祸首由于 Redis 没有非常详细的日志,要想知道在 Redis 实例内部都做了些什么是非常困难的。幸运的是 Redis 提供了一个下面这样的命令统计工具:127.0.0.1:6379> INFO commandstatsCommandstatscmdstat_get:calls=78,usec=608,usec_per_call=7.79 cmdstat_setex:calls=5,usec=71,usec_per_call=14.20 cmdstat_keys:calls=2,usec=42,usec_per_call=21.00 cmdstat_info:calls=10,usec=1931,usec_per_call=193.10通过这个工具可以查看所有命令统计的快照,比如命令执行了多少次,执行命令所耗费的毫秒数(每个命令的总时间和平均时间)只需要简单地执行 CONFIG RESETSTAT 命令就可以重置,这样你就可以得到一个全新的统计结果。3、 将 Redis-Benchmark 结果作为参考,而不要一概而论Redis 之父 Salvatore 就说过:“通过执行GET/SET命令来测试Redis就像在雨天检测法拉利的雨刷清洁镜子的效果”。很多时候人们跑到我这里,他们想知道为什么自己的Redis-Benchmark统计的结果低于最优结果 。但我们必须要把各种不同的真实情况考虑进来,例如:可能受到哪些客户端运行环境的限制?是同一个版本号吗?测试环境中的表现与应用将要运行的环境是否一致?Redis-Benchmark的测试结果提供了一个保证你的 Redis-Server 不会运行在非正常状态下的基准点,但是你永远不要把它作为一个真实的“压力测试”。压力测试需要反应出应用的运行方式,并且需要一个尽可能的和生产相似的环境。4、Hashes 是你的最佳选择以一种优雅的方式引入 hashes 吧。hashes 将会带给你一种前所未有的体验。之前我曾看到过许多类似于下面这样的key结构:foo:first_name foo:last_name foo:address上面的例子中,foo 可能是一个用户的用户名,其中的每一项都是一个单独的 key。这就增加了 犯错的空间,和一些不必要的 key。使用 hash 代替吧,你会惊奇地发现竟然只需要一个 key :127.0.0.1:6379> HSET foo first_name "Joe" (integer) 1 127.0.0.1:6379> HSET foo last_name "Engel" (integer) 1 127.0.0.1:6379> HSET foo address "1 Fanatical Pl" (integer) 1 127.0.0.1:6379> HGETALL foo 1) "first_name" 2) "Joe" 3) "last_name" 4) "Engel" 5) "address" 6) "1 Fanatical Pl" 127.0.0.1:6379> HGET foo first_name "Joe"5、设置 key 值的存活时间无论什么时候,只要有可能就利用key超时的优势。一个很好的例子就是储存一些诸如临时认证key之类的东西。当你去查找一个授权key时——以OAUTH为例——通常会得到一个超时时间。这样在设置key的时候,设成同样的超时时间,Redis就会自动为你清除!而不再需要使用KEYS *来遍历所有的key了,怎么样很方便吧?6、 选择合适的回收策略既然谈到了清除key这个话题,那我们就来聊聊回收策略。当 Redis 的实例空间被填满了之后,将会尝试回收一部分key。根据你的使用方式,我强烈建议使用 volatile-lru 策略——前提是你对key已经设置了超时。但如果你运行的是一些类似于 cache 的东西,并且没有对 key 设置超时机制,可以考虑使用 allkeys-lru 回收机制。我的建议是先在这里查看一下可行的方案。7、如果你的数据很重要,请使用 Try/Except如果必须确保关键性的数据可以被放入到 Redis 的实例中,我强烈建议将其放入 try/except 块中。几乎所有的Redis客户端采用的都是“发送即忘”策略,因此经常需要考虑一个 key 是否真正被放到 Redis 数据库中了。至于将 try/expect 放到 Redis 命令中的复杂性并不是本文要讲的,你只需要知道这样做可以确保重要的数据放到该放的地方就可以了。8、不要耗尽一个实例无论什么时候,只要有可能就分散多redis实例的工作量。从3.0.0版本开始,Redis就支持集群了。Redis集群允许你基于key范围分离出部分包含主/从模式的key。完整的集群背后的“魔法”可以在这里找到。但如果你是在找教程,那这里是一个再适合不过的地方了。如果不能选择集群,考虑一下命名空间吧,然后将你的key分散到多个实例之中。关于怎样分配数据,在redis.io网站上有这篇精彩的评论。9、内核越多越好吗?!当然是错的。Redis 是一个单线程进程,即使启用了持久化最多也只会消耗两个内核。除非你计划在一台主机上运行多个实例——希望只会是在开发测试的环境下!——否则的话对于一个 Redis 实例是不需要2个以上内核的。10、高可用到目前为止 Redis Sentinel 已经经过了很全面的测试,很多用户已经将其应用到了生产环境中(包括 ObjectRocket )。如果你的应用重度依赖于 Redis ,那就需要想出一个高可用方案来保证其不会掉线。
2023年08月30日
13 阅读
0 评论
0 点赞
2023-08-30
Redis 16大应用场景
Redis 16大应用场景1、缓存String类型 例如: 热点数据缓存(例如报表、明星出轨),对象缓存、全页缓存、可以提升热点数据的访问数据。2、数据共享分布式String 类型,因为 Redis 是分布式的独立服务,可以在多个应用之间共享 例如: 分布式Session<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>3、分布式锁String 类型setnx方法,只有不存在时才能添加成功,返回truepublic static boolean getLock(String key) { Long flag = jedis.setnx(key, "1"); if (flag == 1) { jedis.expire(key, 10); } return flag == 1; } public static void releaseLock(String key) { jedis.del(key); }4、全局IDint类型,incrby,利用原子性 incrby userid 1000 分库分表的场景,一次性拿一段5、计数器int类型,incr方法 例如: 文章的阅读量、微博点赞数、允许一定的延迟,先写入Redis再定时同步到数据库6、限流int类型,incr方法 以访问者的ip和其他信息作为key,访问一次增加一次计数,超过次数则返回false7、位统计String类型的bitcount (1.6.6的bitmap数据结构介绍)字符是以8位二进制存储的set k1 a setbit k1 6 1 setbit k1 7 0 get k1 /* 6 7 代表的a的二进制位的修改 a 对应的ASCII码是97,转换为二进制数据是01100001 b 对应的ASCII码是98,转换为二进制数据是01100010 因为bit非常节省空间(1 MB=8388608 bit),可以用来做大数据量的统计。 */例如: 在线用户统计,留存用户统计setbit onlineusers 01 setbit onlineusers 11 setbit onlineusers 20支持按位与、按位或等等操作BITOPANDdestkeykey[key...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。 BITOPORdestkeykey[key...] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey 。 BITOPXORdestkeykey[key...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。 BITOPNOTdestkeykey ,对给定 key 求逻辑非,并将结果保存到 destkey 。计算出7天都在线的用户BITOP "AND" "7_days_both_online_users" "day_1_online_users" "day_2_online_users" ... "day_7_online_users"8、购物车String 或hash。所有String可以做的hash都可以做key:用户id;field:商品id;value:商品数量。+1:hincr。-1:hdecr。删除:hdel。全选:hgetall。商品数:hlen。9、用户消息时间线timelinelist,双向链表,直接作为timeline就好了。插入有序10、消息队列List提供了两个阻塞的弹出操作:blpop/brpop,可以设置超时时间blpop:blpop key1 timeout 移除并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。brpop:brpop key1 timeout 移除并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。上面的操作。其实就是java的阻塞队列。学习的东西越多。学习成本越低队列:先进先除:rpush blpop,左头右尾,右边进入队列,左边出队列栈:先进后出:rpush brpop11、抽奖自带一个随机获得值spop myset12、点赞、签到、打卡假如上面的微博ID是t1001,用户ID是u3001 用 like:t1001 来维护 t1001 这条微博的所有点赞用户点赞了这条微博:sadd like:t1001 u3001取消点赞:srem like:t1001 u3001是否点赞:sismember like:t1001 u3001点赞的所有用户:smembers like:t1001点赞数:scard like:t1001是不是比数据库简单多了。13、商品标签老规矩, 用 tags:i5001 来维护商品所有的标签。sadd tags:i5001 画面清晰细腻 sadd tags:i5001 真彩清晰显示屏 sadd tags:i5001 流程至极14、商品筛选// 获取差集 sdiff set1 set2 // 获取交集(intersection ) sinter set1 set2 // 获取并集 sunion set1 set2假如:iPhone11 上市了sadd brand:apple iPhone11 sadd brand:ios iPhone11 sad screensize:6.0-6.24 iPhone11 sad screentype:lcd iPhone 11赛选商品,苹果的、ios的、屏幕在6.0-6.24之间的,屏幕材质是LCD屏幕sinter brand:apple brand:ios screensize:6.0-6.24 screentype:lcd15、用户关注、推荐模型follow 关注 fans 粉丝相互关注:sadd 1:follow 2 sadd 2:fans 1 sadd 1:fans 2 sadd 2:follow 1我关注的人也关注了他(取交集):sinter 1:follow 2:fans可能认识的人:用户1可能认识的人(差集):sdiff 2:follow 1:follow 用户2可能认识的人:sdiff 1:follow 2:follow16、排行榜id 为6001 的新闻点击数加1:zincrby hotNews:20190926 1 n6001 获取今天点击最多的15条:zrevrange hotNews:20190926 0 15 withscores
2023年08月30日
46 阅读
0 评论
0 点赞
2023-08-30
Redis 缓存的三大问题及其解决方案
Redis 缓存的三大问题及其解决方案
2023年08月30日
10 阅读
0 评论
0 点赞
2023-08-30
用 Redis 实现一个轻量级的搜索引擎
用 Redis 实现一个轻量级的搜索引擎
2023年08月30日
9 阅读
0 评论
0 点赞
2023-08-12
Redis[快问快答系列]
[Redis[快问快答系列]](https://learnku.com/articles/75382)什么是 Redis?Redis 是一种基于内存的数据库,对数据的读写操作都是在内存中完成,因此读写速度非常快,常用于缓存,消息队列、分布式锁等场景。Redis 提供了多种数据类型来支持不同的业务场景,比如 String (字符串)、Hash (哈希)、 List (列表)、Set (集合)、Zset (有序集合)、Bitmaps(位图)、HyperLogLog(基数统计)、GEO(地理信息)、Stream(流),并且对数据类型的操作都是原子性的,因为执行命令由单线程负责的,不存在并发竞争的问题。除此之外,Redis 还支持事务 、持久化、Lua 脚本、多种集群方案(主从复制模式、哨兵模式、切片机群模式)、发布 / 订阅模式,内存淘汰机制、过期删除机制等等。Redis 和 Memcached 有什么区别?Memcached 只支持最简单的 key-value 数据类型Redis 支持数据的持久化,Memcached 重启或者挂掉后,数据就没了Redis 原生支持集群模式,Memcached 没有原生的集群模式Redis 支持发布订阅模型、Lua 脚本、事务等功能,而 Memcached 不支持为什么用 Redis 作为 MySQL 的缓存?Redis 具备高性能,高并发,Redis 单机的 QPS 能轻松破 10w,而 MySQL 单机的 QPS 很难破 1w。Redis 数据类型以及使用场景分别是什么?String:缓存对象:SET user:1 '{"name":"xiaolin", "age":18}'计数器:INCR count:1001分布式锁:SET lock_key unique_value NX PX 10000共享 session: 适用分布式系统List:消息队列:消息保序:使用 LPUSH + RPOP;阻塞读取:使用 BRPOP;重复消息处理:生产者自行实现全局唯一 ID;消息的可靠性:使用 BRPOPLPUSHHash:缓存对象一般对象用 String + Json 存储,对象中某些频繁变化的属性可以考虑抽出来用 Hash 类型存储。存储一个哈希表uid:1的键值HMSET uid:1 name Tom age 152存储一个哈希表uid:2的键值HMSET uid:2 name Jerry age 132获取哈希表用户id为1中所有的键值HGETALL uid:11) "name"2) "Tom"3) "age"4) "15"购物车添加商品:HSET cart:{用户id} {商品id} 1添加数量:HINCRBY cart:{用户id} {商品id} 1商品总数:HLEN cart:{用户id}删除商品:HDEL cart:{用户id} {商品id}获取购物车所有商品:HGETALL cart:{用户id}Set:聚合计算场景主从集群中,为了避免主库因为 Set 做聚合计算(交集、差集、并集)时导致主库被阻塞,我们可以选择一个从库完成聚合统计点赞uid:1 用户对文章 article:1 点赞SADD article:1 uid:1uid:1 取消了对 article:1 文章点赞。SREM article:1 uid:1获取 article:1 文章所有点赞用户 :SMEMBERS article:11) "uid:3"2) "uid:2"获取 article:1 文章的点赞用户数量:SCARD article:1(integer) 2判断用户 uid:1 是否对文章 article:1 点赞了:SISMEMBER article:1 uid:1(integer) 0 # 返回0说明没点赞,返回1则说明点赞了共同关注Set 类型支持交集运算,所以可以用来计算共同关注的好友、公众号等。uid:1 用户关注公众号 id 为 5、6、7、8、9SADD uid:1 5 6 7 8 9uid:2 用户关注公众号 id 为 7、8、9、10、11SADD uid:2 7 8 9 10 11获取共同关注SINTER uid:1 uid:21) "7"2) "8"3) "9"给 uid:2 推荐 uid:1 关注的公众号:SDIFF uid:1 uid:21) "5"2) "6"验证某个公众号是否同时被 uid:1 或 uid:2 关注:SISMEMBER uid:1 5(integer) 1 # 返回0,说明关注了SISMEMBER uid:2 5(integer) 0 # 返回0,说明没关注抽奖活动存储某活动中中奖的用户名 ,Set 类型因为有去重功能,可以保证同一个用户不会中奖两次。key 为抽奖活动名,value 为员工名称,把所有员工名称放入抽奖箱 :SADD lucky Tom Jerry John Sean Marry Lindy Sary Mark(integer) 5如果允许重复中奖,可以使用 SRANDMEMBER 命令。抽取 1 个一等奖:SRANDMEMBER lucky 11) "Tom"抽取 2 个二等奖:SRANDMEMBER lucky 21) "Mark"2) "Jerry"抽取 3 个三等奖:SRANDMEMBER lucky 31) "Sary"2) "Tom"3) "Jerry"如果不允许重复中奖,可以使用 SPOP 命令。抽取一等奖1个SPOP lucky 11) "Sary"抽取二等奖2个SPOP lucky 21) "Jerry"2) "Mark"抽取三等奖3个SPOP lucky 31) "John"2) "Sean"3) "Lindy"Zset:排行榜arcticle:1 文章获得了200个赞ZADD user:xiaolin:ranking 200 arcticle:1文章 arcticle:1 新增一个赞ZINCRBY user:xiaolin:ranking 1 arcticle:1查看某篇文章的赞数ZSCORE user:xiaolin:ranking arcticle:4获取文章赞数最多的 3 篇文章ZREVRANGE user:xiaolin:ranking 0 2 WITHSCORES获取100赞到200 赞的文章ZRANGEBYSCORE user:xiaolin:ranking 100 200 WITHSCORES电话和姓名排序使用有序集合的 ZRANGEBYLEX 或 ZREVRANGEBYLEX 可以帮助我们实现电话号码或姓名的排序BitMap:签到第一步,执行下面的命令,记录该用户 6 月 3 号已签到。SETBIT uid:sign:100:202206 2 1第二步,检查该用户 6 月 3 日是否签到。GETBIT uid:sign:100:202206 2 第三步,统计该用户在 6 月份的签到次数。BITCOUNT uid:sign:100:202206用户登录状态第一步,执行以下指令,表示用户已登录。SETBIT login_status 10086 1第二步,检查该用户是否登陆,返回值 1 表示已登录。GETBIT login_status 10086第三步,登出,将 offset 对应的 value 设置成 0。SETBIT login_status 10086 0布隆过滤器HyperLogLog:只需要花费 12 KB 内存,就可以计算接近 2^64 个元素的基数,统计结果是有一定误差的,标准误算率是 0.81%。百万计网页 UV 计数在统计 UV 时,你可以用 PFADD 命令把访问页面的每个用户都添加到 HyperLogLog 中。PFADD page1:uv user1 PFADD page1:uv user2用 PFCOUNT 命令直接获得 page1 的 UV 值了PFCOUNT page1:uvGEO:GEO 本身并没有设计新的底层数据结构,而是直接使用了 Sorted Set 集合类型。查找用户附近的网约车把 ID 号为 33 的车辆的当前经纬度位置存入 GEO 集合中:GEOADD cars:locations 116.034579 39.030452 33当用户想要寻找自己经纬度(116.054579,39.030452 )为中心的 5 公里内的车辆信息GEORADIUS cars:locations 116.054579 39.030452 5 km ASC COUNT 10Stream:消息队列 比 list 高级Redis 线程模型Redis 单线程指的是「接收客户端请求 -> 解析请求 -> 进行数据读写等操作 -> 发送数据给客户端」这个过程是由一个线程(主线程)来完成的,这也是我们常说 Redis 是单线程的原因。Redis 程序不是单线程的,后台还会有三个线程处理关闭文件,AOF 刷盘,释放内存Redis 采用单线程为什么还这么快?Redis 采用单线程模型可以避免了多线程之间的竞争,省去了多线程切换带来的时间和性能上的开销,而且也不会导致死锁问题。Redis 采用了 I/O Epoll 多路复用机制处理大量的客户端 Socket 请求Redis 6.0 之后为什么引入了多线程?在 Redis 6.0 版本之后,也采用了多个 I/O 线程来处理网络请求,** 但是对于命令的执行,Redis 仍然使用单线程来处理,Redis 6.0 版本引入的多线程 I/O 特性对性能提升至少是一倍以上。Redis 如何实现数据不丢失?AOF 日志:每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里;RDB 快照:将某一时刻的内存数据,以二进制的方式写入磁盘;混合持久化方式:Redis 4.0 新增的方式,集成了 AOF 和 RBD 的优点;AOF 日志是如何实现的?Redis 在执行完一条写操作命令后,就会把该命令以追加的方式写入到一个文件里,然后 Redis 重启时,会读取该文件记录的命令,然后逐一执行命令的方式来进行数据恢复。Redis 提供了 3 种 AOF 写回硬盘的策略,在 Redis.conf 配置文件中的 appendfsync 配置项Always,每次写操作命令执行完后,同步将 AOF 日志数据写回硬盘;Everysec,每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,然后每隔一秒将缓冲区里的内容写回到硬盘;No,意味着不由 Redis 控制写回硬盘的时机,由操作系统决定何时将缓冲区内容写回硬盘。AOF 日志过大,会触发压缩机制 bgrewriteaofRDB 做快照时会阻塞线程吗?执行了 save 命令,就会在主线程生成 RDB 文件,由于和执行操作命令在同一个线程,会阻塞主线程;执行了 bgsave 命令,会创建一个子进程来生成 RDB 文件,这样可以避免主线程的阻塞;Redis 还可以通过配置文件的选项来实现每隔一段时间自动执行一次 bgsave 命令save 900 1 //900 秒之内,对数据库进行了至少 1 次修改;save 300 10 //300 秒之内,对数据库进行了至少 10 次修改;save 60 10000 // 60 秒之内,对数据库进行了至少 10000 次修改。RDB 在执行快照的时候,数据能修改吗?可以的,执行 bgsave 过程中,Redis 依然可以继续处理操作命令的,也就是数据是能被修改的,关键的技术就在于多进程的写时复制技术(Copy-On-Write, COW)。为什么会有混合持久化?Redis 4.0 提出了混合持久化,既保证了 Redis 重启速度,又降低数据丢失风险。Redis 如何实现服务高可用?主从复制:一主多从的模式,且主从服务器之间采用的是「读写分离」的方式。哨兵模式:主从服务器出现故障宕机时,需要手动进行恢复。所以 Redis 增加了哨兵模式,因为哨兵模式做到了可以监控主从服务器,并且提供主从节点故障转移的功能。Redis Cluster: 分布式集群,采用哈希槽,来处理数据和节点之间的映射关系Redis 使用的过期删除策略是什么?Redis 使用的过期删除策略是「惰性删除 + 定期删除」这两种策略配和使用。惰性删除策略的做法是,不主动删除过期键,每次从数据库访问 key 时,都检测 key 是否过期,如果过期则删除该 key。定期删除策略的做法是,每隔一段时间「随机」从数据库中取出一定数量的 key 进行检查,并删除其中的过期 key。Redis 主从模式中,对过期键会如何处理?主库在 key 到期时,会在 AOF 文件里增加一条 del 指令,同步到所有的从库Redis 内存满了,会发生什么?在 Redis 的运行内存达到了配置项设置的 maxmemory,就会触发内存淘汰机制Redis 内存淘汰策略有哪些?noeviction: 默认的内存淘汰策略,不淘汰任何数据,而是不再提供服务,直接返回错误。在设置了过期时间的数据中进行淘汰volatile-random:随机淘汰设置了过期时间的任意键值;volatile-ttl:优先淘汰更早过期的键值。volatile-lru:淘汰所有设置了过期时间的键值中,最久未使用的键值;volatile-lfu:淘汰所有设置了过期时间的键值中,最少使用的键值;在所有数据范围内进行淘汰:allkeys-random:随机淘汰任意键值;allkeys-lru:淘汰整个键值中最久未使用的键值;allkeys-lfu:淘汰整个键值中最少使用的键值。如何避免缓存雪崩?将缓存失效时间随机打散,在原有的失效时间基础上增加一个随机值设置缓存不过期,通过业务逻辑来更新缓存数据如何避免缓存击穿互斥锁方案(Redis 中使用 SET EX NX)不给热点数据设置过期时间,由后台异步更新缓存如何避免缓存穿透判断求请求参数是否合理,请求参数是否含有非法值、请求字段是否存在,如果判断出是恶意请求就直接返回错误可以针对查询的数据,在缓存中设置一个空值或者默认值返回给应用,而不会继续查询数据库。使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在Redis 如何实现延迟队列?在 Redis 可以使用有序集合(ZSet)的方式来实现延迟消息队列的,ZSet 有一个 Score 属性可以用来存储延迟执行的时间。zadd score1 value1 命令就可以一直往内存中生产消息。 zrangebyscore 查询符合条件的所有待处理的任务, 通过循环执行队列任务即可。Redis 的大 key 如何处理?一般而言,下面这两种情况被称为大 key:String 类型的值大于 10 KB;Hash、List、Set、ZSet 类型的元素的个数超过 5000 个;//最好选择在从节点上执行该命令。因为主节点上执行时,会阻塞主节点,只能返回每种类型中最大的那个 bigkey,无法得到大小排在前 N 位的 bigkey,对于集合类型来说,只统计集合元素个数的多少,而不是实际占用的内存量。redis-cli -h 127.0.0.1 -p6379 -a "password" -- bigkeysscan命令,配合key类型再用对应的命令计算内存//使用 RdbTools 第三方开源工具,可以用来解析 Redis 快照(RDB)文件,找到其中的大 key。rdb dump.rdb -c memory --bytes 10240 -f redis.csv如何删除大 key?分批次删除异步删除(Redis 4.0 版本以上)推荐使用从 Redis 4.0 版本开始,可以采用异步删除法,用 unlink 命令代替 del 来删除。这样 Redis 会将这个 key 放入到一个异步线程中进行删除,这样不会阻塞主线程。我们还可以通过配置参数,达到某些条件的时候自动进行异步删除。Redis 管道有什么用?把多条命令拼接到一起,当成一次请求发出去,结果也是拼接到一起发回来,免去了每条命令执行后都要等待的情况,从而有效地提高了程序的执行效率。Redis 事务支持回滚吗?Redis 中并没有提供回滚机制如何用 Redis 实现分布式锁的?SET lock_key unique_value NX PX 10000 lock_key 就是 key 键;unique_value 是客户端生成的唯一的标识,区分来自不同客户端的锁操作;NX 代表只在 lock_key 不存在时,才对 lock_key 进行设置操作;PX 10000 表示设置 lock_key 的过期时间为 10s,这是为了避免客户端发生异常而无法释放锁。解锁需要 Lua 脚本保证原子性// 释放锁时,先比较 unique_value 是否相等,避免锁的误释放if redis.call("get",KEYS[1]) == ARGV[1] thenreturn redis.call("del",KEYS[1])elsereturn 0end基于 Redis 实现分布式锁有什么缺点?超时时间不好设置。集群情况下的不可靠性。Redis 如何解决集群情况下分布式锁的可靠性?为了保证集群环境下分布式锁的可靠性,Redis 官方已经设计了一个分布式锁算法 Redlock(红锁)。它是基于多个 Redis 节点的分布式锁,官方推荐是至少部署 5 个 Redis 节点,而且都是主节点为什么用跳表而不用平衡树?从内存占用上来比较,跳表比平衡树更灵活一些。在做范围查找的时候,跳表比平衡树操作要简单从算法实现难度上来比较,跳表比平衡树要简单得多如何保证缓存和数据库数据的一致性?更新数据库 + 更新缓存如果我们的业务对缓存命中率有很高的要求,我们可以采用「更新数据库 + 更新缓存」的方案,但是在两个更新请求并发执行的时候,会出现数据不一致的问题所以我们得增加一些手段来解决这个问题,这里提供两种做法:在更新缓存前先加个分布式锁,保证同一时间只运行一个请求更新缓存,当然对于写入的性能就会带来影响。在更新完缓存时,给缓存加上较短的过期时间,缓存的数据也会很快过期,先删除缓存 + 更新数据库延迟双删删除缓存redis.delKey(X)更新数据库db.update(X)睡眠Thread.sleep(N)再删除缓存redis.delKey(X)
2023年08月12日
13 阅读
0 评论
0 点赞
1
2