**** 快得原理 https://learn.lianglianglee.com/%e4%b8%93%e6%a0%8f/Redis%20%e6%a0%b8%e5%bf%83%e6%8a%80%e6%9c%af%e4%b8%8e%e5%ae%9e%e6%88%98/03%20%20%e9%ab%98%e6%80%a7%e8%83%bdIO%e6%a8%a1%e5%9e%8b%ef%bc%9a%e4%b8%ba%e4%bb%80%e4%b9%88%e5%8d%95%e7%ba%bf%e7%a8%8bRedis%e8%83%bd%e9%82%a3%e4%b9%88%e5%bf%ab%ef%bc%9f.md https://mp.weixin.qq.com/s?__biz=MzI0MDQ4MTM5NQ==&mid=2247537510&idx=2&sn=d33f3c4ed393ee49a9103f75f0ced0fc&chksm=e918367ade6fbf6cf439b29a8afd7521e17da4712ced1a0c4104f87d1792c3094214c59ffbc8&scene=21#wechat_redirect # Redis https://www.youtube.com/watch?v=G1rOthIU-uo 還未看 https://learnku.com/articles/57510 要用cli 記得進去redis後要輸入 redis-cli windos簡單安裝介紹 https://www.youtube.com/watch?v=DYv5_illdFY&list=PLBjZhzRvV2CiObno8yYFo476dcODKM3-v&index=2 apt裝 wsl service啟動 再跑start ping他 面試考題 基本 https://www.quanxiaoha.com/java-interview/redis-data-type.html ## redis pubsub原理 https://jameshfisher.com/2017/03/01/redis-pubsub-under-the-hood/ Redis Pub/Sub: 適合低延遲、實時通訊,但消息一旦發佈,不在連線狀態的訂閱者將無法補獲消息。 其保證屬於「至多一次」(at most once),並非「至少一次」 ## redis 6.0多線程 https://blog.csdn.net/chenssy/article/details/142110498 ## 快跟db差異 為什麼 Redis 的非阻塞 I/O 更優? 單線程設計:Redis 通過單線程來處理所有請求,這避免了多線程系統中常見的線程切換和鎖競爭問題。即使在處理 I/O 操作時,它也能保持較低的延遲。 內存存儲:Redis 是基於內存的資料庫,因此它的 I/O 操作主要是內存讀寫,這比磁碟 I/O 要快得多。即使是非阻塞的磁碟 I/O 操作,也不如內存操作那麼快速。 事件驅動和 I/O 多路復用:Redis 使用事件驅動和 I/O 多路復用技術來高效處理大量並發請求,這使得 Redis 能夠在單一線程中處理大量的 I/O 請求,而不需要為每個請求啟動新的線程。 ![image](https://hackmd.io/_uploads/ryux8akp1l.png) ![image](https://hackmd.io/_uploads/HJOXIak6ke.png) ![image](https://hackmd.io/_uploads/H1E48aJTye.png) ![image](https://hackmd.io/_uploads/HkcZw616Jx.png) ## pubsub ![image](https://hackmd.io/_uploads/Bk-RIja7ke.png) 都是零拷貝io ## 過期隊列 https://javaguide.cn/database/redis/redis-delayed-task.html#redis-%E8%BF%87%E6%9C%9F%E4%BA%8B%E4%BB%B6%E7%9B%91%E5%90%AC%E5%AE%9E%E7%8E%B0%E5%BB%B6%E6%97%B6%E4%BB%BB%E5%8A%A1%E5%8A%9F%E8%83%BD%E7%9A%84%E5%8E%9F%E7%90%86 ## 復原 ![image](https://hackmd.io/_uploads/SJFlW92Fyl.png) ## golang lock https://github.com/go-redsync/redsync ## 大概說一下命令執行 https://my.oschina.net/u/3715845/blog/5062140 ## 一致 使用Binlog实时更新/删除Redis缓存。利用Canal,即将负责更新缓存的服务伪装成一个MySQL的从节点,从MySQL接收Binlog,解析Binlog之后,得到实时的数据变更信息,然后根据变更信息去更新/删除Redis缓存 ## redis資料結構應用 ![image](https://hackmd.io/_uploads/HyS18q8ap.png) ![image](https://hackmd.io/_uploads/HJrgUcUaa.png) ![image](https://hackmd.io/_uploads/rJjhUc8Tp.png) ## 基本介紹 redis跟一般資料庫不一樣 他不是存在硬體,他是存在內存(Ram),所以他非常快,但缺點是不穩定,如果電腦突然崩潰,資料會全部不見,除非你有備份他, set key value get key 支援多樣數據庫 ![](https://i.imgur.com/1s55adE.png) 如果我資料庫包含關係 可以用graph的 json的可以用 firestore mongo ![](https://i.imgur.com/iCJS9pG.png) 然後再使用搜尋的去找 ![](https://i.imgur.com/s2SzAN7.png) redis数据库一般会将存入的数据先存在 内存中,当存储的内容达到一定数量或者经过一定时间后,才将内容存 储到磁盘上,所以redis数据库对数据的存储和操作非常快,因为大部分 数据操作是在内存中完成的。同时,redis数据库要比MemCache功能更 强,因为它可以实现数据的持久化存储 Laravel框架是通过添加“predis/predis”资源包来实现与redis数据库的交 互,该资源包目前只支持前六种数据结构 ## 擴張 memcached 官方没有提供集群特性,一般第三方会使用一致性哈希算法来进行负载均衡实现集群扩展。 redis 官方的集群选择把数据根据key来哈希分配到固定数量的 slot 上,然后把 slot 再分配到具体的redis实例上来实现集群,当需要扩展时,只需要把 slot 分配一些到新加入的 redis 实例即可。这种多加一层来实现集群扩展的方式,类似于我们数据库分表时使用的索引表 ## 注意要点 https://mp.weixin.qq.com/s?__biz=MzkyMzU5Mzk1NQ==&mid=2247506058&idx=1&sn=b5d0f0eb59c348b86c38f69b8308a512&source=41#wechat_redirect ## On-demand Look-aside Cache https://tachunwu.github.io/posts/gravity-router/ ## 基本操作 redis有0~15數據庫, 默認訪問0號 ![](https://i.imgur.com/7rZzxRs.png) ## string ![](https://hackmd.io/_uploads/SJCGbK75h.png) ![image](https://hackmd.io/_uploads/SymH574h0.png) ![image](https://hackmd.io/_uploads/S1kI9X42C.png) https://segmentfault.com/a/1190000040177140 ## hash table key - field - value ## list(有序可以重複) ![](https://i.imgur.com/2BUNZGJ.png) 從頭推入 ex 1, 2, 3, 4, 5 這樣就是1先放2 . 3 . 4這樣 ## set(無序不能重複) ![](https://i.imgur.com/QRhOYLI.png) ![](https://i.imgur.com/wKzMbNK.png) ## 有續集合 zset ![](https://i.imgur.com/lFZsZlx.png) ![](https://i.imgur.com/1wNebZe.png) ## laravel lock https://learnku.com/articles/4211/unlock-the-correct-position-of-the-redis-lock ## redis 缓存和 mysql 数据一致性 ``` 方式: 1. 先更新redis 再更新数据库 场景:update set value = 10 where value = 9 1. redis更新成功:redis value = 10 2. 数据库更新失败:mysql value = 9 3. 数据不一致 2. 先更新数据库,再更新redis 场景: A进程update set value = 10 where value = 9 ;B进程 update set value = 11 where value = 9; 1. A 进程先更新数据库,还未写入缓存:mysql value = 10 ;redis value = 9 2. B 进程更新数据库并且提交事务,写入缓存:mysql value = 11;redis value = 11; 3. A 进程处理完请求提交事务,写入缓存:redis value = 10; 4. 最终 mysql value = 11; redis value = 10 3. 先删除缓存再更新数据库 场景:A进程update set value = 10 where value = 9 ;B进程查询value; 1. A 进程先删除缓存 还没来得及修改数据或者事务未提交 2. B 进程开始查询,没有命中缓存,所以查库并写入缓存 redis value = 9 3. A 进程更新数据库完成 mysql value = 10 4. 最终 mysql value = 10;redis value = 9 解决方案: 1. 延时双删除 场景:A进程update set value = 10 where value = 9 ;B进程查询value; 1. A 进程先删除缓存 还没来得及修改数据或者事务未提交 2. B 进程开始查询,没有命中缓存,所以查库并写入缓存 redis value = 9 3. A 进程更新数据库完成 mysql value = 10 4. A 进程估算延时时间,sleep之后再次删除缓存 5. 最终mysql value = 10;redis value 为空(下次查询直接查库) 6. 延时的原因时防止B进程在A进程更新完之后B进程还没来得及写入缓存 2. 请求串行化 1. 创建两个队列 :更新队列和查询队列 2. 当缓存不存在需要查库的时候将key存入更新队列 3. 如果查询未完成之前有新的请求进来,并且发现更新队列中还存在key则将key放入查询队列,则等待;不存在则重复第二步 4. 如果查询的数据发现查询队列已经存在则不需要再次写入队列 4. 数据更新完成之后rpop更新队列,同时rpop查询队列,释放查询请求 5. 查询请求可以使用while + sleep 查询缓存并且设置最大延迟时间,还没有完成则返回空 ``` ## redis 的数据类型及应用场景 ``` 1. string : 普通的key/value存储 2. hash: hashmap:键值队集合,存储对象信息 3. list: 双向链表:消息队列 4. set: value永远为null的hashMap:无序集合且不重复:计算交集、并集、差集、去重值 5. zset: 有序集合且不重复:hashMap(去重) + skiplist跳跃表(保证有序):排行榜 ``` ### zset ![](https://hackmd.io/_uploads/SkuubnQq2.png) ## redis 更新 ![](https://hackmd.io/_uploads/Syw9HK-kp.png) ![](https://hackmd.io/_uploads/S1vIx075h.png) 內存淘汰 https://xiaolincoding.com/redis/module/strategy.html#%E5%86%85%E5%AD%98%E6%B7%98%E6%B1%B0%E7%AD%96%E7%95%A5 ### cache aside pattern ![](https://hackmd.io/_uploads/r1Ik6aQ5h.png) ![](https://hackmd.io/_uploads/BywUS4Zkp.png) ![](https://hackmd.io/_uploads/r1e7Auw92.png) ## 最佳化 redis應該跟資料庫區別,因該要有redis跟資料庫,這樣當你資料有在redis裡面就能快速撈取,沒有再從資料庫拉,這樣是最佳化 ## 发布、订阅消息 。redis是通过`publish`和`subscribe subscribe`指令提供消息的发布和订阅的,通过 订阅一个“队列”用于监听消息,当有消息通过pubish指令发布到 “队 列”中时,订阅程序就会监听到消息并进行响应。为了实现上述功能, 可以使用artisan命令 ``` “php artisan make:console SubscribeMsg -- command=Sub:Msg” ``` 来创建一个订阅消息类,并修改该类的handle()函 数,通过Redis::`subscribe subscribe`()方式订阅一个“队列”,这里定义的队列名称 为“redis-msg”。但是,只创建一个控制台指令类还是不行的,需要将该 类在控制台核心类(App\Console\ Kernel)的“$commands”属性中进行注册 才能生效 ### list ![](https://hackmd.io/_uploads/ryTPNtZJp.png) ### pubusb ![](https://hackmd.io/_uploads/S1c6dKWyT.png) ![](https://hackmd.io/_uploads/ryK7KFWk6.png) ## stream 單消費者 ![](https://hackmd.io/_uploads/BynmqYWkT.png) ![](https://hackmd.io/_uploads/r1eYqt-1p.png) ![](https://hackmd.io/_uploads/B198nKZJT.png) ![](https://hackmd.io/_uploads/ByOY2tbka.png) 多消費者 ![](https://hackmd.io/_uploads/SkyEptWkp.png) ![](https://hackmd.io/_uploads/HyULCtZ1T.png) ![](https://hackmd.io/_uploads/HJTP0Y-1p.png) ![](https://hackmd.io/_uploads/rkXWs5-yp.png) ![](https://hackmd.io/_uploads/HJmqi9-ya.png) 如果生產者發送問題 或者 消息有順序 那就需要更強大的queue https://www.bilibili.com/video/BV1cr4y1671t?p=77&spm_id_from=pageDriver&vd_source=f726dd30598fe01d9fbc9c5a988d6408 ## 緩存更新 ![](https://hackmd.io/_uploads/B1ozHKbkp.png) 內存做法 可以用最新的 https://xiaolincoding.com/redis/module/strategy.html ## 操作 ### 基本 crud `set name value` `get name value` `DEL name` `exists name` 判斷有沒有 找全部的key `keys *` 刪除全部的 `flushall` ![](https://i.imgur.com/BzPMu00.png) ### 生存時間 `ttl 加上name名稱` -1代表沒有期限 -2 代表消失了 `expire naem 時間` ### list 可以看成array lpush 推一個到左邊 right 推一個ㄘㄨ從右邊 放 lpush friends john 拿 lrange friends 0 -1 這代表抓全部 刪除呢 一樣用 lpop rpop ![](https://i.imgur.com/1bG7Zip.png) ### set ![image](https://hackmd.io/_uploads/rk_JOiVR1e.png) ![image](https://hackmd.io/_uploads/ByfgOiVAke.png) 可以當成js的那個 有唯一值的 SADD name value 查看全部 smembers 刪除 srem ![](https://i.imgur.com/6SdiaiL.png) ### hashes 你不能往它裡面放嵌套 你可以把她想成json Hset Hget HgetAll 看全部 刪除 hdel 他其實是兩層的 ![](https://i.imgur.com/8HMMdG1.png) ## 指令 setex 如果有 覆蓋舊的 ## pipeline ![](https://i.imgur.com/IHsgUNJ.png) before ![](https://i.imgur.com/YxNoZqX.png) after ![](https://i.imgur.com/sTHYZCk.png) 有前後關西不能用 後面需要前面不能用 跟一般的管道不太一樣 ## 事務 ![](https://i.imgur.com/fyoyIOn.png) ## watch ![](https://i.imgur.com/nZmpVie.png) ## LFU ## Redis server-assisted client side caching https://www.51cto.com/article/707706.html https://www.51cto.com/article/617014.html Guava Cache等本地緩存 ## refresh時機 主動被動 主動會去找更新 被動 在觸發CDC (Change Data Capture) 後去改動 ## 事務 https://www.cnblogs.com/makemylife/p/17299566.html 記住事物不會rollback ###### tags: `資料庫相關`