redis 進行緩存實戰-18

使用 Redis 進行緩存

Redis 通常被認為只是一個數據存儲,但它的速度和內存中特性使其成為緩存的絕佳選擇。緩存是一種技術,通過將經常訪問的數據存儲在快速的臨時存儲位置來提高應用程序性能。通過使用 Redis 作為緩存,您可以顯著減少主數據庫的負載并縮短用戶的響應時間。本課將探討如何有效地使用 Redis 進行緩存,涵蓋關鍵概念、策略和最佳實踐。

了解緩存概念

緩存是軟件開發中的一種基本優化技術。它涉及將數據副本存儲在緩存中,緩存是一個高速數據存儲層,以便將來可以更快地處理對該數據的請求。發出請求時,首先檢查緩存。如果在緩存中找到數據(“緩存命中”),則直接從緩存中提供數據。如果未找到數據(“緩存未命中”),則會從原始數據源(例如數據庫)中檢索數據,將其存儲在緩存中,然后提供給用戶。

緩存的好處

  • 改進的性能: 緩存通過從更快的存儲層提供數據來減少延遲并縮短響應時間。
  • 減少數據庫負載: 通過從緩存中提供經常訪問的數據,您可以減少主數據庫的負載,使其能夠處理更復雜的查詢和作。
  • 提高可擴展性: 緩存通過減少后端系統的負載,使您的應用程序能夠處理更多的并發用戶和請求。
  • 節省成本: 通過減少數據庫負載和提高資源利用率,緩存可以節省基礎設施和運營費用方面的成本。

緩存策略

Redis 可以使用多種緩存策略,每種策略都有自己的優點和缺點:

  • Cache-Aside (延遲加載): 應用程序首先檢查緩存中的數據。如果找到數據,則直接返回數據。如果沒有,應用程序將從數據庫中檢索數據,將其存儲在緩存中,然后返回它。此策略易于實施,并確保緩存僅包含已請求的數據。
  • 直寫: 應用程序同時將數據寫入緩存和數據庫。這可確保緩存始終是最新的,但會增加寫入延遲。
  • 回寫 (Write-Behind): 應用程序將數據寫入緩存,緩存將數據異步寫入數據庫。此策略提供最低的寫入延遲,但如果緩存在將數據寫入數據庫之前失敗,則可能導致數據丟失。
  • 通讀: 應用程序與緩存交互,而緩存又與數據庫交互。請求數據時,緩存會檢查它是否包含數據。否則,它將從數據庫中檢索數據,將其存儲在緩存中,然后將其返回給應用程序。

對于大多數使用案例,Cache-Aside 策略是 Redis 最實用且最常用的策略,因為它簡單高效。

使用 Redis 作為緩存

Redis 非常適合緩存,因為它的速度、內存數據存儲和對各種數據結構的支持。以下是將 Redis 用作緩存的方法:

設置和檢索數據

您可以使用 SETGET 命令在 Redis 中存儲和檢索數據。例如:

SET user:123 '{"id": 123, "name": "John Doe", "email": "john.doe@example.com"}'
GET user:123

在此示例中,我們將一個 JSON 字符串存儲在 Redis 中,該字符串表示用戶對象,其鍵為 user:123。使用 GET user:123 檢索數據時,Redis 返回 JSON 字符串。

設置過期時間 (TTL)

為防止緩存無限增長,您可以使用 EXPIRE 命令或帶有 SET 命令的 EX 選項為緩存數據設置過期時間(TTL - 生存時間):

SET user:123 '{"id": 123, "name": "John Doe", "email": "john.doe@example.com"}' EX 3600  # Expires in 3600 seconds (1 hour)
EXPIRE user:123 3600 # Expires in 3600 seconds (1 hour)
TTL user:123 # Check the remaining time to live

這可確保在指定時間段后自動刪除緩存的數據,從而防止提供過時的數據。

數據序列化

緩存復雜數據結構時,您需要在將數據存儲在 Redis 中之前對其進行序列化,并在檢索數據后對其進行反序列化。常見的序列化格式包括 JSON 和 Protocol Buffers。

以下是在 Python 中使用 JSON 的示例:

import redis
import json# Connect to Redis
redis_client = redis.Redis(host='localhost', port=6379, db=0)# Data to cache
user_data = {"id": 123, "name": "John Doe", "email": "john.doe@example.com"}# Serialize the data to JSON
user_data_json = json.dumps(user_data)# Store the JSON string in Redis with an expiration time
redis_client.set('user:123', user_data_json, ex=3600)# Retrieve the data from Redis
cached_user_data_json = redis_client.get('user:123')# Deserialize the JSON string back to a Python dictionary
if cached_user_data_json:cached_user_data = json.loads(cached_user_data_json)print(cached_user_data)
else:print("Data not found in cache")

緩存失效策略

緩存失效是在基礎數據更改時刪除或更新緩存數據的過程。緩存失效有幾種策略:

  • 基于 TTL 的失效: 在指定的 TTL 之后,數據會自動從緩存中刪除。這是最簡單的策略,但如果基礎數據在 TTL 過期之前發生更改,則可能會導致數據過時。
  • 基于事件的失效: 當發生特定事件(例如數據庫更新)時,緩存將失效。此策略可確保緩存始終是最新的,但它需要與數據源進行更復雜的集成。
  • 手動失效: 緩存由管理員或應用程序代碼手動失效。此策略對緩存失效提供了最大的控制,但它需要仔細監控和管理。

示例:緩存數據庫查詢

假設您有一個從數據庫中檢索用戶數據的函數:

import redis
import json
import time# Assume this function fetches data from a database
def get_user_from_db(user_id):# Simulate a database query with a delaytime.sleep(1)user_data = {"id": user_id, "name": f"User {user_id}", "email": f"user{user_id}@example.com"}return user_datadef get_user(user_id, redis_client):"""Retrieves user data from cache if available, otherwise fetches from the database,caches it, and returns it."""cache_key = f'user:{user_id}'cached_user_data = redis_client.get(cache_key)if cached_user_data:# Cache hitprint(f"Cache hit for user {user_id}")user_data = json.loads(cached_user_data)else:# Cache missprint(f"Cache miss for user {user_id}. Fetching from DB.")user_data = get_user_from_db(user_id)user_data_json = json.dumps(user_data)redis_client.set(cache_key, user_data_json, ex=3600)  # Cache for 1 hourreturn user_data# Example usage
redis_client = redis.Redis(host='localhost', port=6379, db=0)user1 = get_user(123, redis_client)
print(user1)user1_cached = get_user(123, redis_client) #This time it will be a cache hit
print(user1_cached)user2 = get_user(456, redis_client)
print(user2)

在此示例中,get_user 函數首先檢查用戶數據在 Redis 緩存中是否可用。如果是,則從緩存中檢索數據并返回數據。否則,將從數據庫中檢索數據,將其存儲在緩存中,過期時間為 1 小時,然后返回。

高級緩存技術

緩存防盜

當大量請求同時命中緩存,并且緩存已過期或為空時,就會發生緩存加速。這可能會使數據庫過載,因為所有請求都嘗試同時檢索數據。

要防止緩存踩踏,可以使用以下技術:

  • Probabilistic Early Expiration(概率提前到期): 您可以向過期時間添加一個小的隨機延遲,而不是為所有緩存條目設置固定的過期時間。這有助于分配數據庫上的負載。
  • 鎖定: 當發生緩存未命中時,您可以獲取一個鎖,以防止其他請求同時嘗試從數據庫中檢索數據。只有第一個請求會檢索數據,將其存儲在緩存中,然后釋放鎖。
  • 后臺刷新: 您可以在緩存過期之前在后臺刷新緩存。這可確保緩存始終是最新的,并降低緩存被踩踏的可能性。

使用 Redis 數據結構進行緩存

Redis 提供了各種可用于緩存不同類型數據的數據結構:

  • Strings: 用于緩存簡單的鍵值對,例如用戶 ID 和名稱。
  • Hashes: 用于緩存具有多個字段的對象,例如用戶配置文件。
  • Lists: 用于緩存有序數據,例如最近的活動源。
  • Sets: 用于緩存唯一數據,例如用戶角色。
  • Sorted Sets: 用于緩存排名數據,例如排行榜。

選擇正確的數據結構可以提高緩存的效率和性能。

示例:緩存博客文章列表

假設您要緩存最近的博客文章列表。您可以使用 Redis 列表來存儲帖子 ID,然后在需要時從數據庫中檢索完整的帖子數據。

import redis
import json# Connect to Redis
redis_client = redis.Redis(host='localhost', port=6379, db=0)# Assume this function fetches blog posts from a database
def get_blog_posts_from_db():# Simulate a database queryblog_posts = [{"id": 1, "title": "Redis Caching", "content": "..."},{"id": 2, "title": "NoSQL Databases", "content": "..."},{"id": 3, "title": "Python Programming", "content": "..."}]return blog_postsdef get_recent_blog_posts(redis_client, limit=10):"""Retrieves recent blog posts from cache if available, otherwise fetches from the database,caches it, and returns it."""cache_key = 'recent_blog_posts'cached_post_ids = redis_client.lrange(cache_key, 0, limit - 1)if cached_post_ids:# Cache hitprint("Cache hit for recent blog posts")post_ids = [int(post_id) for post_id in cached_post_ids]# In a real application, you would fetch the full post data from the database# based on these IDs.  Here, we just return the IDs.return post_idselse:# Cache missprint("Cache miss for recent blog posts. Fetching from DB.")blog_posts = get_blog_posts_from_db()post_ids = [post['id'] for post in blog_posts]# Store the post IDs in Redisfor post_id in reversed(post_ids):  # Add in reverse order to maintain orderredis_client.lpush(cache_key, post_id)redis_client.expire(cache_key, 3600)  # Cache for 1 hourreturn post_ids[:limit]# Example usage
recent_posts = get_recent_blog_posts(redis_client)
print(recent_posts)recent_posts_cached = get_recent_blog_posts(redis_client) #This time it will be a cache hit
print(recent_posts_cached)

實踐練習

  1. 實施 Cache-Aside 策略: 創建一個使用 Redis 緩存 API 調用結果的函數。該函數應首先檢查數據在緩存中是否可用。如果是,則返回緩存的數據。如果沒有,請進行 API 調用,將結果存儲在緩存中并指定過期時間,然后返回結果。
  2. 實施緩存失效: 修改前面的函數,以便在底層數據更改時使緩存失效。您可以通過更新數據庫中的值或調用其他 API 終端節點來模擬數據更改。
  3. 使用 Redis 哈希來緩存對象: 創建一個使用 Redis 哈希緩存用戶配置文件的函數。該函數應將每個用戶配置文件存儲為單獨的哈希值,其中包含 name、email 和其他相關信息的字段。
  4. 實施緩存踩踏防護: 修改 API 緩存功能,以防止使用概率提前過期或鎖定的緩存踩踏。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/81063.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/81063.shtml
英文地址,請注明出處:http://en.pswp.cn/web/81063.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Nginx學習筆記】:Fastapi服務部署單機Nginx配置說明

服務部署單機Nginx配置說明 服務.conf配置文件: upstream asr_backend {server 127.0.0.1:8010; }server {listen 80;server_name your_domain.com;location / {proxy_pass http://localhost:8000;proxy_set_header Host $host;proxy_set_header X-Real-IP $remot…

Qt網絡編程

前言 Qt為了支持跨平臺,對系統網絡編程的API(socket API)也進行了重新分裝。 實際Qt中進行網絡編程也不一定使用Qt封裝的網絡API,也有可能使用的是系統原生API或者其他第三方框架的API。 若要使用Qt中的網絡編程的API&#xff…

矩陣短劇系統:如何用1個后臺管理100+小程序?技術解析與實戰應用

引言:短劇行業的效率革命 2025年,短劇市場規模已突破千億,但傳統多平臺運營模式面臨重復開發成本高、用戶數據分散、內容同步效率低等痛點。行業亟需一種既能降本增效又能聚合流量的解決方案——“矩陣短劇系統”。通過“1個后臺管理100小程…

嵌入式STM32學習——ESP8266 01S的基礎介紹

簡介 ESP8266 系列模組是深圳市安信可科技有限公司開發的一系列基于樂鑫ESP8266EX的低功耗UART-WiFi芯片模組,可以方便地進行二次開發,接入云端服務,實現手機3/4G全球隨時隨地的控制,加速產品原型設計。 模塊核心處理器 ESP8266 在…

form-create-designer中$inject參數的數據結構及各項屬性說明

FcDesigner 是一款基于Vue的開源低代碼可視化表單設計器工具,通過數據驅動表單渲染。可以通過拖拽的方式快速創建表單,提高開發者對表單的開發效率,節省開發者的時間。并廣泛應用于在政務系統、OA系統、ERP系統、電商系統、流程管理等領域。 …

Jasypt概述及整合SpringBoot實現敏感數據加密

前言 在實際開發中,Spring Boot應用的配置文件中經常包含數據庫密碼、API密鑰等敏感信息。如果這些信息以明文形式存儲,會帶來嚴重的安全隱患。本文將詳細介紹如何使用Jasypt(Java Simplified Encryption)對Spring Boot配置文件中…

Better Faster Large Language Models via Multi-token Prediction 原理

目錄 模型結構: Memory-efficient implementation: 實驗: 1. 在大規模模型上效果顯著: 2. 在不同類型任務上的效果: 為什么MLP對效果有提升的幾點猜測: 1. 并非所有token對生成質量的影響相同 2. 關…

git merge解沖突后,add、continue提交

git merge解沖突后,add、continue提交 git merge操作沖突后,需要手動解沖突,解完沖突后,需要: git add . 然后,進入一般的正常git代碼提交流程。 git合并‘merge’其他分支的個別文件到當前branch_gitbash 合并branc…

3.8.1 利用RDD實現詞頻統計

在本次實戰中,我們通過Spark的RDD實現了詞頻統計功能。首先,準備了包含單詞的文件并上傳至HDFS。接著,采用交互式方式逐步完成詞頻統計,包括創建RDD、單詞拆分、映射為二元組、按鍵歸約以及排序等操作。此外,還通過創建…

應對進行性核上性麻痹,健康護理鑄就溫暖防線

進行性核上性麻痹(PSP)是一種罕見的神經退行性疾病,主要影響患者的運動、平衡及吞咽等功能。針對這類患者,有效的健康護理對提升其生活質量、延緩病情發展至關重要。 在日常生活護理方面,由于患者存在平衡障礙和肌肉僵…

融合蛋白質語言模型和圖像修復模型,麻省理工與哈佛聯手提出PUPS ,實現單細胞級蛋白質定位

蛋白質亞細胞定位(subcellular localization of a protein)是指蛋白質在細胞結構中具體的定位情況, 這對蛋白質行使其生物學功能至關重要。舉個簡單例子,如果把細胞想象成一個龐大的企業,其中細胞核、線粒體、細胞膜等…

lanqiaoOJ 4330:歐拉函數模板

【題目來源】 https://www.lanqiao.cn/problems/4330/learning/ 【問題描述】 這是一道模板題。 首先給出歐拉函數的定義:即 φ(n) 表示的是小于等于 n 的數中和 n 互質的數的個數。 比如說 φ(6)2,當 n 是質數的時候,顯然有φ(n)n-1。 【題…

無人機電子防抖技術要點概述!

一、技術要點 1. 傳感器數據融合 電子防抖需結合陀螺儀、加速度計、視覺傳感器等多源數據,實時檢測無人機的姿態變化和振動頻率。例如,IMU(慣性測量單元)通過加速度計和陀螺儀測量飛行器的姿態和運動狀態,結合視覺感…

Win10 安裝單機版ES(elasticsearch),整合IK分詞器和安裝Kibana

一. 先查看本機windows是否安裝了ES(elasticsearch),檢查方法如下: 檢查進程 按 Ctrl Shift Esc 組合鍵打開 “任務管理器”。在 “進程” 選項卡中,查看是否有 elasticsearch 相關進程。如果有,說明系統安裝了 ES。 檢查端口…

BIO、NIO、AIO 的區別與實戰應用解析

導語: BIO、NIO 和 AIO 是后端面試中的經典話題,尤其在高并發、高性能場景下更是重中之重。本文將從面試官視角出發,深入剖析三者的區別、典型題目和實戰解答,助你掌握答題技巧,輕松拿下這一高頻考點! 一、…

電腦風扇轉速不正常的原因

一、硬件故障或接觸問題 1. 風扇本身損壞 扇葉卡頓或軸承磨損:灰塵堆積、異物纏繞(如頭發、線纜)會導致扇葉轉動阻力增大,發出異響并轉速下降;軸承潤滑脂干涸或老化會引起風扇噪音大、轉速不穩定。電機故障&#xff…

運維打鐵:生產服務器用戶權限管理方案全解析

文章目錄 一、引言二、方案設計2.1 權限模型選擇2.2 角色定義2.3 權限分配2.4 用戶與角色關聯 三、相關代碼注釋(以 Linux 系統為例)3.1 用戶創建與角色分配腳本3.2 權限設置腳本 四、常見問題解決4.1 用戶無法登錄4.2 用戶權限不足4.3 權限文件修改后不…

在tp6模版中加減法

實際項目中,我們經常需要標簽變量加減運算的操作。但是,在ThinkPHP中,并不支持模板變量直接運算的操作。幸運的是,它提供了自定義函數的方法,我們可以利用自定義函數解決:ThinkPHP模板自定義函數語法如下&a…

Fastjson利用鏈JdbcRowSetImpl分析

首先創建客戶端 package com.yq1ng.vul;import com.alibaba.fastjson.JSON;/*** FastJsonTest** author yq1ng* date 2021/12/29 19:45* since 1.0.0*/ public class FastJsonTest {public static void main(String[] args) {String ser "{\"type\":\"co…

基于OAuth2-proxy和Keycloak為comfyui實現SSO

背景 comfyui無認證被漏掃后易被rce挖礦 攻擊過程 https://www.oschina.net/news/340226 https://github.com/comfyanonymous/ComfyUI/discussions/5165 阿里云漏洞庫關于comfyui的漏洞 https://avd.aliyun.com/search?qcomfyui&timestamp__1384n4%2BxBD0GitGQ0QD8ID%2F…