---
# System prepended metadata

title: Redis
tags: [redis]

---

****

快得原理
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: `資料庫相關`