自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Redis與本地緩存組合食用,味道更佳!

開發(fā) 后端
高頻數(shù)據(jù)流處理系統(tǒng)中,Redis的壓力也會很大,同時I/0開銷才是耗時的主要原因,這時候為了降低Redis讀寫壓力我們可以用到本地緩存,Guava為我們提供了優(yōu)秀的本地緩存API,包含了過期策略等等,編碼難度低,個人非常推薦。

前言

我們開發(fā)中經(jīng)常用到Redis作為緩存,將高頻數(shù)據(jù)放在Redis中能夠提高業(yè)務(wù)性能,降低MySQL等關(guān)系型數(shù)據(jù)庫壓力,甚至一些系統(tǒng)使用Redis進行數(shù)據(jù)持久化,Redis松散的文檔結(jié)構(gòu)非常適合業(yè)務(wù)系統(tǒng)開發(fā),在精確查詢,數(shù)據(jù)統(tǒng)計業(yè)務(wù)有著很大的優(yōu)勢。

但是高頻數(shù)據(jù)流處理系統(tǒng)中,Redis的壓力也會很大,同時I/0開銷才是耗時的主要原因,這時候為了降低Redis讀寫壓力我們可以用到本地緩存,Guava為我們提供了優(yōu)秀的本地緩存API,包含了過期策略等等,編碼難度低,個人非常推薦。

設(shè)計示例

Redis懶加載緩存

數(shù)據(jù)在新增到MySQL不進行緩存,在精確查找進行緩存,做到查詢即緩存,不查詢不緩存

流程圖

代碼示例

// 偽代碼示例 Xx代表你的的業(yè)務(wù)對象 如User Goods等等
public class XxLazyCache {
@Autowired
private RedisTemplate<String, Xx> redisTemplate;
@Autowired
private XxService xxService;// 你的業(yè)務(wù)service
/**
* 查詢 通過查詢緩存是否存在驅(qū)動緩存加載 建議在前置業(yè)務(wù)保證id對應(yīng)數(shù)據(jù)是絕對存在于數(shù)據(jù)庫中的
*/
public Xx getXx(int id) {
// 1.查詢緩存里面有沒有數(shù)據(jù)
Xx xxCache = getXxFromCache(id);
if(xxCache != null) {
return xxCache;// 衛(wèi)語句使代碼更有利于閱讀
}
// 2.查詢數(shù)據(jù)庫獲取數(shù)據(jù) 我們假定到業(yè)務(wù)這一步,傳過來的id都在數(shù)據(jù)庫中有對應(yīng)數(shù)據(jù)
Xx xx = xxService.getXxById(id);
// 3.設(shè)置緩存、這一步相當(dāng)于Redis緩存懶加載,下次再查詢此id,則會走緩存
setXxFromCache(xx);
return xx;
}
}
/**
* 對xx數(shù)據(jù)進行修改或者刪除操作 操作數(shù)據(jù)庫成功后 刪除緩存
* 刪除請求 - 刪除數(shù)據(jù)庫數(shù)據(jù) 刪除緩存
* 修改請求 - 更新數(shù)據(jù)庫數(shù)據(jù) 刪除緩存 下次在查詢時候就會從數(shù)據(jù)庫拉取新的數(shù)據(jù)到緩存中
*/
public void deleteXxFromCache(long id) {
String key = "Xx:" + xx.getId();
redisTemplate.delete(key);
}
private void setXxFromCache(Xx xx) {
String key = "Xx:" + xx.getId();
redisTemplate.opsForValue().set(key, xx);
}
private Xx getXxFromCache(int id) {
// 通過緩存前綴拼裝唯一主鍵作為緩存Key 如Xxx信息 就是Xxx:id
String key = "Xx:" + id;
return redisTemplate.opsForValue().get(key);
}
}
// 業(yè)務(wù)類
public class XxServie {
@Autowired
private XxLazyCache xxLazyCache;
// 查詢數(shù)據(jù)庫
public Xx getXxById(long id) {
// 省略實現(xiàn)
return xx;
}
public void updateXx(Xx xx) {
// 更新MySQL數(shù)據(jù) 省略
// 刪除緩存
xxLazyCache.deleteXxFromCache(xx.getId());
}
public void deleteXx(long id) {
// 刪除MySQL數(shù)據(jù) 省略
// 刪除緩存
xxLazyCache.deleteXxFromCache(xx.getId());
}
}
// 實體類
@Data
public class Xx {
// 業(yè)務(wù)主鍵
private Long id;
// ...省略
}

優(yōu)點

  • 保證最小的緩存量滿足精確查詢業(yè)務(wù),避免冷數(shù)據(jù)占用寶貴的內(nèi)存空間
  • 對增刪改查業(yè)務(wù)入侵小、刪除即同步
  • 可插拔,對于老系統(tǒng)升級,歷史數(shù)據(jù)無需在啟動時初始化緩存

缺點

  • 數(shù)據(jù)量需可控,在無限增長業(yè)務(wù)場景不適用
  • 在微服務(wù)場景不利于全局緩存應(yīng)用

總結(jié)

  • 空間最小化
  • 滿足精確查詢場景
  • 總數(shù)據(jù)量可控推薦使用
  • 微服務(wù)場景不適用

Redis結(jié)合本地緩存

微服務(wù)場景下,多個微服務(wù)使用一個大緩存,流數(shù)據(jù)業(yè)務(wù)下,高頻讀取緩存對Redis壓力很大,我們使用本地緩存結(jié)合Redis緩存使用,降低Redis壓力,同時本地緩存沒有連接開銷,性能更優(yōu)

流程圖

業(yè)務(wù)場景

在流處數(shù)處理過程中,微服務(wù)對多個設(shè)備上傳的數(shù)據(jù)進行處理,每個設(shè)備有一個code,流數(shù)據(jù)的頻率高,在消息隊列發(fā)送過程中使用分區(qū)發(fā)送,我們需要為設(shè)備code生成對應(yīng)的自增號,用自增號對kafka中topic分區(qū)數(shù)進行取模,這樣如果有10000臺設(shè)備,自增號就是0~9999,在取模后就進行分區(qū)發(fā)送就可以做到每個分區(qū)均勻分布。

這個自增號我們使用redis的自增數(shù)生成,生成后放到redis的hash結(jié)構(gòu)進行緩存,每次來一個設(shè)備,我們就去這個hash緩存中取,沒有取到就使用自增數(shù)生成一個,然后放到redis的hash緩存中,這時候每個設(shè)備的自增數(shù)一經(jīng)生成是不會再發(fā)生改變的,我們就想到使用本地緩存進行優(yōu)化,避免高頻的調(diào)用redis去獲取,降低redis壓力。

下面鏈接是關(guān)于kafka分區(qū)消費的文章,大家可以去看看

  • https://juejin.cn/post/6995746569580445709

代碼示例

/**
* 此緩存演示如何結(jié)合redis自增數(shù) hash 本地緩存使用進行設(shè)備自增數(shù)的生成、緩存、本地緩存
* 本地緩存使用Guava Cache
*/
public class DeviceIncCache {
/**
* 本地緩存
*/
private Cache<String, Integer> localCache = CacheBuilder.newBuilder()
.concurrencyLevel(16) // 并發(fā)級別
.initialCapacity(1000) // 初始容量
.maximumSize(10000) // 緩存最大長度
.expireAfterAccess(1, TimeUnit.HOURS) // 緩存1小時沒被使用就過期
.build();
@Autowired
private RedisTemplate<String, Integer> redisTemplate;
/**
* redis自增數(shù)緩存的key
*/
private static final String DEVICE_INC_COUNT = "device_inc_count";

/**
* redis設(shè)備編碼對應(yīng)自增數(shù)的hash緩存key
*/
private static final String DEVICE_INC_VALUE = "device_inc_value";

/**
* 獲取設(shè)備自增數(shù)
*/
public int getInc(String deviceCode){
// 1.從本地緩存獲取
Integer inc = localCache.get(deviceCode);
if(inc != null) {
return inc;
}
// 2.本地緩存未命中,從redis的hash緩存獲取
inc = (Integer)redisTemplate.opsForHash().get(DEVICE_INC_VALUE, deviceCode);
// 3. redis的hash緩存中沒有,說明是新設(shè)備,先為設(shè)備生成一個自增號
if(inc == null) {
inc = redisTemplate.opsForValue().increment(DEVICE_INC_COUNT).intValue;
// 添加到redis hash緩存
redisTemplate.opsForHash().put(DEVICE_INC_VALUE, deviceCode, inc);
}
// 4.添加到本地緩存
localCache.put(deviceCode, inc);
// 4.返回自增數(shù)
return inc;
}
}

優(yōu)點

  • redis保證數(shù)據(jù)可持久,本地緩存保證超高的讀取性能,微服務(wù)共用redis大緩存的場景能有效降低redis壓力
  • guava作為本地緩存,提供了豐富的api,過期策略,最大容量,保證服務(wù)內(nèi)存可控,冷數(shù)據(jù)不會長期占據(jù)內(nèi)存空間
  • 服務(wù)重啟導(dǎo)致的本地緩存清空不會影響業(yè)務(wù)進行
  • 微服務(wù)及分布式場景使用,分布式情況下每個服務(wù)實例只會緩存自己接入的那一部分設(shè)備的自增號,本地內(nèi)存空間最優(yōu)
  • 在示例業(yè)務(wù)中,自增數(shù)滿足了分布區(qū)發(fā)送的均勻分布需求,也可以滿足統(tǒng)計設(shè)備接入數(shù)目的業(yè)務(wù)場景,一舉兩得

缺點

  • 增加編碼復(fù)雜度,不直接
  • 只適用于緩存內(nèi)容只增不改的場景

總結(jié)

  • 本地緩存空間可控,過期策略優(yōu)
  • 適用于微服務(wù)及分布式場景
  • 緩存內(nèi)容不能發(fā)生改變
  • 性能優(yōu)

后記

redis提供了豐富的數(shù)據(jù)類型及api,非常適合業(yè)務(wù)系統(tǒng)開發(fā),統(tǒng)計計數(shù)(increment,decrement),標(biāo)記位(bitmap),松散數(shù)據(jù)(hash),先進先出、隊列式讀?。╨ist);

guava緩存作為本地緩存,能夠高效的讀取的同時,提供了大量api方便我們控制本地緩存的數(shù)據(jù)量及冷數(shù)據(jù)淘汰;我們充分的學(xué)習(xí)這些特性能夠幫助我們在業(yè)務(wù)開發(fā)中更加輕松靈活,在空間與時間上找到一個平衡點。

責(zé)任編輯:龐桂玉 來源: Python開發(fā)
相關(guān)推薦

2024-11-01 16:18:52

2023-11-11 19:43:12

緩存數(shù)據(jù)庫

2025-03-26 03:25:00

SpringGuavaCaffeine

2016-03-29 09:58:17

RedisMemcached緩存

2023-08-11 09:00:00

2023-03-10 13:33:00

緩存穿透緩存擊穿緩存雪崩

2019-10-12 14:19:05

Redis數(shù)據(jù)庫緩存

2023-05-12 11:52:21

緩存場景性能

2022-05-27 09:25:12

攜程酒店本地緩存查詢服務(wù)

2018-11-06 12:32:02

多云云平臺云計算

2024-04-07 00:00:02

Redis雪崩緩存

2024-04-11 13:45:14

Redis數(shù)據(jù)庫緩存

2021-06-05 09:01:01

Redis緩存雪崩緩存穿透

2018-03-29 14:51:59

智能公廁AI

2022-08-01 09:33:50

Redis開源工具

2018-11-01 09:14:42

CNNRNN神經(jīng)網(wǎng)絡(luò)

2025-04-17 08:00:00

前端UniApp數(shù)據(jù)存儲

2025-02-12 00:29:58

2022-03-08 00:07:51

緩存雪崩數(shù)據(jù)庫

2024-01-17 09:10:19

點贊
收藏

51CTO技術(shù)棧公眾號