Redis 在互联网高并发场景下的应用--个人总结

在现代互联网系统中,高并发已经成为常态。无论是电商的秒杀场景、社交平台的热点推荐,还是支付接口的风控,系统需要同时应对成千上万的请求。这时候,Redis 作为一个高性能的内存数据库,凭借其极快的读写速度和丰富的数据结构,成为解决高并发问题的利器。

1. 缓存热点数据 —— 缓解数据库压力

问题背景:数据库在高并发场景下容易成为瓶颈,特别是热点数据的访问会导致 QPS 瞬间飙升。
Redis 解决方案

  • 使用 StringHash 缓存热点数据。

  • 采用 Cache Aside 模式:先查缓存,缓存未命中再查数据库并回填。

示例代码

import redisr = redis.Redis(host='localhost', port=6379, db=0)def get_data_from_db(key):print("查询数据库")return {"id": key, "value": f"data_{key}"}def get_data(key):cache_key = f"cache:{key}"val = r.get(cache_key)if val:print("命中缓存")return eval(val)data = get_data_from_db(key)r.setex(cache_key, 60, str(data))return dataprint(get_data(1))
print(get_data(1))

在高并发场景下使用 Cache-Aside(旁路缓存) 模式,确实需要特别注意一些坑点和边界情况。主要有以下几个方面:

1. 缓存击穿(Cache Miss Under High Concurrency)

  • 问题:某个热点 key 过期瞬间,大量请求并发打到数据库,造成瞬时压力飙升。

  • 解决

    • 互斥锁(分布式锁) 控制只允许一个请求回源数据库并更新缓存。

    • 或者使用 逻辑过期:缓存里放置过期时间戳,过期时先返回旧值,再异步刷新。

2. 缓存穿透(Cache Penetration)

  • 问题:请求的数据在数据库中不存在,每次都会查询 DB,导致 DB 压力大。

  • 解决

    • 缓存空对象(短 TTL),避免重复访问 DB。

    • 增加 布隆过滤器前置拦截机制,快速判断 key 是否可能存在。

3. 缓存雪崩(Cache Avalanche)

  • 问题:大量缓存 key 在同一时间点同时过期,引发请求全部打到 DB。

  • 解决

    • 给 key 设置 随机过期时间,避免同时失效。

    • 使用 多级缓存(L1/L2) 减轻瞬时压力。

4. 数据一致性(Consistency)

  • 问题:Cache-Aside 是 最终一致性,更新逻辑里 “先写 DB 再删缓存” 会有时间窗口问题。

  • 解决

    • 常见策略是 先更新 DB,再删除缓存(推荐),避免脏读。

    • 或者使用 延时双删(写 DB → 删缓存 → 延迟一小段时间再删一次缓存)。

    • 若业务对一致性要求极高,可能需要 订阅 binlog(如 Canal)异步更新缓存

5. 热点 Key 与大 Value

  • 热点 Key:可能被频繁访问,甚至成为单点瓶颈。可通过 分片/多副本 缓解。

  • 大 Value:更新频率低但体积大时,更新缓存成本高,可以考虑 局部字段缓存拆分存储

6. 并发控制 & 原子性

  • 多线程并发下需要注意 读写竞争:避免多个线程同时回源刷新。

  • 分布式场景下要用 原子操作(如 Redis 的 setnx + expire) 做锁和限流。

7. 监控与降级

  • 监控缓存命中率、请求 QPS、DB 压力。

  • 当缓存大面积失效时,可以考虑:

    • 启动 限流/熔断

    • 提供 降级数据(兜底逻辑)

应用场景:用户信息、商品详情页、首页推荐数据等。

2. 限流 —— 防止接口过载

问题背景:突发流量可能会压垮下游服务,例如秒杀、登录、支付接口。
Redis 解决方案

  • 使用 String 作为计数器:INCR + EXPIRE 实现固定时间窗口限流。

  • 使用 Sorted Set 存储时间戳:实现滑动窗口限流,更加精细化。

  • 可以配合 Lua 脚本保证原子性操作。

应用场景:API 调用限流、防止刷单、短信/验证码接口保护。

示例代码(滑动窗口限流)

import time
import redisr = redis.Redis(host='localhost', port=6379, db=0)def is_allowed_sliding_window(user_id, action, period=60, max_count=5):key = f"rate_limit:{user_id}:{action}"now = time.time()pipeline = r.pipeline()pipeline.zadd(key, {now: now})pipeline.zremrangebyscore(key, 0, now - period)pipeline.zcard(key)pipeline.expire(key, period)_, _, count, _ = pipeline.execute()return count <= max_countfor i in range(10):if is_allowed_sliding_window("u1001", "login"):print(i, "允许")else:print(i, "拒绝")time.sleep(0.5)

或者 使用 String 作为计数器

import redis
import timer = redis.Redis(host='localhost', port=6379, db=0)def is_allowed(user_id, action, period=60, max_count=5):"""在 period 时间内最多允许 max_count 次操作"""key = f"rate_limit:{user_id}:{action}"count = r.incr(key)if count == 1:r.expire(key, period)  # 设置过期时间if count > max_count:return Falsereturn True# 测试
for i in range(10):if is_allowed("u1001", "login"):print(i, "允许")else:print(i, "拒绝")time.sleep(0.5)

3. 分布式队列 —— 异步削峰

问题背景:大量请求直接打到数据库或下游服务,可能会瞬间撑爆系统。
Redis 解决方案

  • 使用 ListLPUSH + BRPOP)作为简单任务队列。

  • 使用 Stream 实现类似 Kafka 的消息队列:支持消费组、消息确认和持久化。

  • 常见用途:削峰填谷,将请求转为异步任务,让系统有更多缓冲时间。

应用场景:订单处理、日志收集、消息通知、秒杀排队。

示例代码(Stream 队列)

import redisr = redis.Redis(host='localhost', port=6379, db=0)
stream_key = "order_stream"# 生产者
def produce():for i in range(5):r.xadd(stream_key, {"order": f"order_{i}"})print("生产订单:", f"order_{i}")# 消费者
def consume():last_id = "0-0"while True:messages = r.xread({stream_key: last_id}, block=2000, count=2)if not messages:breakfor _, msgs in messages:for msg_id, data in msgs:print("消费订单:", msg_id, data)last_id = msg_idproduce()
consume()

4. 分布式锁 —— 保证数据一致性

问题背景:在分布式环境中,多实例同时修改同一资源,可能造成数据冲突。
Redis 解决方案

  • 使用 String 类型:

    • SET key value NX PX timeout 实现加锁,避免重复设置。

    • 校验 value 防止误删锁。

  • 高级方案:使用 RedLock 算法 提升可靠性,避免单点故障。

应用场景:库存扣减、任务调度、并发下的幂等操作。

示例代码

import redis
import uuid
import timer = redis.Redis(host='localhost', port=6379, db=0)def acquire_lock(lock_key, expire=5):lock_id = str(uuid.uuid4())result = r.set(lock_key, lock_id, nx=True, ex=expire)return lock_id if result else Nonedef release_lock(lock_key, lock_id):script = """if redis.call('get', KEYS[1]) == ARGV[1] thenreturn redis.call('del', KEYS[1])elsereturn 0end"""return r.eval(script, 1, lock_key, lock_id)lock_id = acquire_lock("my_lock", expire=3)
if lock_id:print("获得锁,执行业务逻辑...")time.sleep(2)print("释放锁:", release_lock("my_lock", lock_id))
else:print("未获得锁")

5. 实时统计与排行榜

问题背景:高并发下,需要对访问量、点赞数、排名进行实时计算。
Redis 解决方案

  • 使用 INCR / HINCRBY 做计数器。

  • 使用 Sorted Set 实现排行榜,支持按分数排序。

应用场景:网站 PV/UV 统计、热搜榜、积分排名、点赞排行榜。

示例代码

import redisr = redis.Redis(host='localhost', port=6379, db=0)# 统计 PV
r.incr("page_view")
print("页面访问量:", r.get("page_view").decode())# 排行榜
leaderboard = "game_rank"
r.zincrby(leaderboard, 10, "user1")
r.zincrby(leaderboard, 20, "user2")print("排行榜:", r.zrevrange(leaderboard, 0, -1, withscores=True))

总结

在互联网高并发场景下,Redis 可以解决以下核心问题:

  1. 缓存热点数据 → 缓解数据库压力,提升响应速度。

  2. 限流 → 防止突发流量冲击系统。

  3. 分布式队列 → 实现削峰填谷,支撑异步处理。

  4. 分布式锁 → 保证数据一致性,防止并发冲突。

  5. 实时统计与排行榜 → 提供快速的聚合计算能力。

Redis 不仅仅是一个缓存,更是一个 高并发场景下的基础设施。合理利用其数据结构与特性,可以极大提升系统的可扩展性与稳定性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/95682.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/95682.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++笔记之软件设计原则总结

C++笔记之软件设计原则总结 code review 文章目录 C++笔记之软件设计原则总结 1.软件设计的六大原则 2.高内聚与低耦合 2.1.高内聚(High Cohesion) 2.2.低耦合(Low Coupling) 2.3.高内聚与低耦合的关系与重要性 3.DRY(Dont Repeat Yourself)原则 3.1.定义 3.2.好处 3.3.示…

ThreadLocal 深度解析:原理、应用场景与最佳实践

一、ThreadLocal 核心概念与设计哲学​1.1 ThreadLocal 的基本概念​ThreadLocal 是 Java 中提供线程局部变量的类&#xff0c;它允许每个线程创建自己的变量副本&#xff0c;从而实现线程封闭&#xff08;Thread Confinement&#xff09;。简单来说&#xff0c;ThreadLocal 为…

AMD显卡运行GPT-OSS全攻略

AMD显卡运行GPT-OSS全攻略 本文介绍如何在Windows系统上使用AMD显卡&#xff08;以RX 7900XTX为例&#xff09;运行开源GPT-OSS模型。 前置要求 硬件&#xff1a;AMD显卡&#xff08;如RX 7900XTX&#xff0c;具体支持型号参考ROCm文档&#xff09;。软件&#xff1a; Ollam…

【Sharding-JDBC】​Spring/Spring Boot 集成 Sharding-JDBC,分表策略与 API、YAML 配置实践​

文章目录环境准备Spring框架Sharding-JDBC 4.x版本api实现Sharding-JDBC 5.4.x版本yaml实现Springboot框架Sharding-JDBC 5.4.x版本yaml实现分库、加密、读写分离基于yaml的配置示例更多相关内容可查看需求&#xff1a;按月分区&#xff0c;按年分表&#xff0c;找不到对应年份…

单片机和PLC有哪些区别?揭秘单片机MCU的常见应用

单片机&#xff08;MCU&#xff09;和可编程逻辑控制器&#xff08;PLC&#xff09;作为电子控制系统中的两大核心组件&#xff0c;分别在不同的领域发挥着重要作用。然而&#xff0c;尽管它们都属于自动化控制领域的关键设备&#xff0c;但它们的设计理念、应用场景和性能特点…

ElementUI之Upload 上传的使用

文章目录说明SSM使用引入依赖在spring-mvc.xml中加入配置创建上传工具类AliOssUtil响应工具类ResultJSON编写controller自动上传代码编写结果如下演示手动上传前端代码编写后端代码编写结果演示如下说明 为了方便演示&#xff0c;前后端代码一起写了 关于对象存储请看我另一篇博…

Langchain4j 整合MongoDB 实现会话持久化存储详解

目录 一、前言 二、大模型会话记忆介绍 2.1 AI 大模型会话记忆是什么 2.2 大模型会话记忆常用实现方案 2.3 LangChain4j 会话记忆介绍 三、大模型常用会话存储数据库介绍 3.1 常用的会话存储数据库 3.2 MongoDB 简介 3.2.1 MongoDB 是什么 3.3 为什么选择MongoDB 作为…

SQL 常用 OVER() 窗口函数介绍

1. sum() over() 做组内数据累加在 SQL 中想实现不同分组内数据累加&#xff0c;可以通过 sum() over() PARTITION BY ORDER BY 结合实现。这种方式能同时满足多维度分组且组内累加的需求&#xff0c;示例如下&#xff1a;假设我们有一张 sales 表&#xff0c;表中存储着…

OpenRouter:一站式 AI 模型调用平台,免费畅享千问、DeepSeek 等顶级模型

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事&#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 OpenRouter&#xff1a;一站式 AI 模型调用平台&#xff0c;免费畅享千问、DeepSeek 等顶级模型前…

SpringBoot 整合 Kafka 的实战指南

引言&#xff1a; 本文总字数&#xff1a;约 9800 字预计阅读时间&#xff1a;40 分钟 为什么 Kafka 是高吞吐场景的首选&#xff1f; 在当今的分布式系统中&#xff0c;消息队列已成为不可或缺的基础设施。面对不同的业务场景&#xff0c;选择合适的消息队列至关重要。目前…

OpenCV 实战篇——如何测算出任一副图片中的物体的实际尺寸?传感器尺寸与像元尺寸的关系?

文章目录1 如何测算出任一副图片中的物体的实际尺寸2 传感器尺寸与像元尺寸的关系3 Max Frame Rate最大帧率4 为什么要进行相机标定?相机标定有何意义?5 基于相机模型的单目测距--普通相机1 如何测算出任一副图片中的物体的实际尺寸 物体尺寸测量的思路是找一个确定尺寸的物…

Java并发锁相关

锁相关 ​1. 什么是可重入锁&#xff1f;Java 中如何实现&#xff1f;​​ ​答​&#xff1a; 可重入锁允许一个线程多次获取同一把锁&#xff08;即递归调用时无需重新竞争锁&#xff09;。 ​关键点​&#xff1a;防止死锁&#xff0c;避免线程因重复请求已持有的锁而阻塞。…

Pie Menu Editor V1.18.7.exe 怎么安装?详细安装教程(附安装包)​

​​Pie Menu Editor V1.18.7.exe​ 是一款用于创建和编辑 ​饼图菜单&#xff08;Pie Menu&#xff09;​​ 的工具软件&#xff0c;通常用于游戏开发、UI设计、3D建模&#xff08;如 Blender 等&#xff09;、或自定义软件操作界面。 一、准备工作 ​下载文件​ 下载了 ​Pi…

基于Spark的中文文本情感分析系统研究

引言 1.1 研究背景与意义 随着互联网的普及和社交媒体的兴起、特别是自媒体时代的来临&#xff0c;网络文本数据呈现爆炸式增长。这些文本数据蕴含着丰富的用户情感信息&#xff0c;如何有效地挖掘和利用这些信息&#xff0c;对于了解舆情动态、改进客户服务、辅助决策分析具…

Simulink子系统、变体子系统及封装知识

1.引言 文章三相新能源并网系统序阻抗模型——序阻抗分析器IMAnalyzer介绍了一种用于分析和扫描序阻抗的软件。其中&#xff0c;在序阻抗扫频操作过程中&#xff0c;用到了一个扰动注入、测量和运算工具【IMtool】&#xff0c;它外表长这样&#xff1a; 内部长这样&#xff1a…

高阶组件介绍

高阶组件约定俗成以with开头 import React, { useEffect } from react; import { TouchableOpacity, Image, StyleSheet } from react-native;type IReactComponent React.ClassicComponentClass| React.ComponentClass| React.FunctionComponent| React.ForwardRefExoticComp…

C++ STL系列-02.泛型入门

C STL系列-02.泛型入门C中的泛型编程主要通过模板&#xff08;template&#xff09;实现。模板允许我们编写与类型无关的代码&#xff0c;是一种将类型作为参数进行编程的方式。在C中&#xff0c;模板分为函数模板和类模板。 1. 函数模板函数模板允许我们定义一个函数&#xff…

高效管理网络段和端口集合的工具之ipset

目录 1. 核心命令速查 2. 集合类型 3. 实战案例&#xff1a;使用 ipset 封禁 IP 案例 1&#xff1a;基础黑名单封禁&#xff08;手动添加&#xff09; 案例 2&#xff1a;自动过期和解封 案例 3&#xff1a;封禁 IP 和端口组合 案例 4&#xff1a;白名单模式 案例 5&am…

实例和对象的区别

对象&#xff08;Object&#xff09;是一个概念&#xff0c;它表示“某个类的一个成员”&#xff0c;是“逻辑上的个体”。实例&#xff08;Instance&#xff09;是一个现实&#xff0c;指的是在内存中真正分配了空间的对象。实例一定是对象&#xff0c;但对象不一定是实例。例…

Win10 Chrome认不出新Emoji?两个扩展搞定显示与输入

前言 用Win10电脑在Chrome里发消息、刷网页时&#xff0c;你是否遇到过这样的尴尬&#xff1a;别人发的、或者页面显示的 Emoji&#xff0c;在你屏幕上变成了空白方框&#xff0c;像“文字里缺了一块拼图”&#xff1f;其实这不是Chrome的错&#xff0c;也不用换电脑&#xff0…