高级架构师必会——Redis(缓存)

本文深入解析Redis缓存原理及其在解决数据库与Web服务器间瓶颈中的作用,详述Redis基础与进阶知识,包括五种核心数据结构:String、Hash、List、Set和SortedSet的特性和应用场景,对比Redis与memcached区别,探讨数据淘汰策略及缓存穿透预防。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、在讲解Redis相关知识之前,先给大家介绍下什么是缓存。

缓存概念

缓存是为了解决数据库服务器和web服务器之间的瓶颈。如果一个网站的流量很大,这个瓶颈将会非常明显,每次数据库查询耗费的时间将会非常可观。对于更新速度不是很快的网站,我们可以用静态化来避免过多的数据库查询。对于更新速度以秒计的网站,静态化也不会太理想,可以用缓存系统来构建。如果只是单台服务器用作缓存,问题不会太复杂,如果有多台服务器用作缓存,就要考虑缓存服务器的负载均衡。

二、接下来在给大家介绍下Redis的基础知识

1、什么是Redis?

Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作。Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。 Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能,比方说用他的List来做FIFO双向链表,实现一个轻量级的高性 能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一 个功能加强版的memcached来用。 Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算。

2、redis 常见数据结构以及使用场景分析

String

常用命令: set,get,decr,incr,mget 等。

String数据结构是简单的key-value类型,value其实不仅可以是String,也可以是数字。 常规key-value缓存应用; 常规计数:微博数,粉丝数等。

Hash

常用命令: hget,hset,hgetall 等。

Hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。 比如我们可以Hash数据结构来存储用户信息,商品信息等等。比如下面我就用 hash 类型存放了我本人的一些信息:

key=JavaUser293847

value={

 “id”: 1,

 “name”: “SnailClimb”,

 “age”: 22,

 “location”: “Wuhan, Hubei”

}

List

常用命令: lpush,rpush,lpop,rpop,lrange等

list 就是链表,Redis list 的应用场景非常多,也是Redis最重要的数据结构之一,比如微博的关注列表,粉丝列表,消息列表等功能都可以用Redis的 list 结构来实现。

Redis list 的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。

另外可以通过 lrange 命令,就是从某个元素开始读取多少个元素,可以基于 list 实现分页查询,这个很棒的一个功能,基于 redis 实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西(一页一页的往下走),性能高。

Set

常用命令:sadd,spop,smembers,sunion 等

set 对外提供的功能与list类似是一个列表的功能,特殊之处在于 set 是可以自动排重的。

当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。可以基于 set 轻易实现交集、并集、差集的操作。

比如:在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程,具体命令如下:

sinterstore key1 key2 key3 将交集存在key1内

Sorted Set

常用命令: zadd,zrange,zrem,zcard等

和set相比,sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列。

举例: 在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息,适合使用 Redis 中的 SortedSet 结构进行存储。
redis 和 memcached 的区别

3、 redis 和 memcached 的区别

redis支持更丰富的数据类型(支持更复杂的应用场景):Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。memcache支持简单的数据类型,String。

Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而Memecache把数据全部存在内存之中。

集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 redis 目前是原生支持 cluster 模式的.

Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的多路 IO 复用模型。

来自网络上的一张图
redis和memcached对比

三、Redis的进阶知识

1、Redis有哪几种数据淘汰策略?

noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)

allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。

volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。

allkeys-random: 回收随机的键使得新添加的数据有空间存放。

volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。

volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

2、Redis如何进行缓存穿透预防及优化

缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,但是出于容错的考虑,如果从存储层查不到数据则不写入缓存层,如图 11-3 所示整个过程分为如下 3 步:

缓存层不命中

存储层不命中,所以不将空结果写回缓存

返回空结果

缓存穿透将导致不存在的数据每次请求都要到存储层去查询,失去了缓存保护后端存储的意义。

缓存穿透模型

缓存穿透问题可能会使后端存储负载加大,由于很多后端存储不具备高并发性,甚至可能造成后端存储宕掉。通常可以在程序中分别统计总调用数、缓存层命中数、存储层命中数,如果发现大量存储层空命中,可能就是出现了缓存穿透问题。

造成缓存穿透的基本有两个。第一,业务自身代码或者数据出现问题,第二,一些恶意攻击、爬虫等造成大量空命中,下面我们来看一下如何解决缓存穿透问题。

缓存穿透的解决方法

1)缓存空对象

如下图所示,当第 2 步存储层不命中后,仍然将空对象保留到缓存层中,之后再访问这个数据将会从缓存中获取,保护了后端数据源。

缓存空值应对穿透问题

缓存空对象会有两个问题:

第一,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间 ( 如果是攻击,问题更严重 ),比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。

第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为 5 分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。

<think>好的,我需要帮这位大四的同学制定一个提升Java工程师专业能力的计划。首先,他的背景是双非民办本科,现在在实习,可能基础可能不是特别扎实,但已经有了一定的实践经验。关键是要根据他的现状,给出实际可行的建议,帮助他在实习期间快速提升。 首先,要明确Java工程师需要哪些核心能力。一般来说,包括Java语言基础、框架(比如Spring全家桶)、数据库、系统设计、算法、工具使用(如Git、Maven)、软技能等。同时,实习期间接触到的实际项目经验非常重要,需要结合理论与实践。 他提到现在在公司实习,所以应该利用好公司资源,多参与项目,积累实战经验。同时,可能需要注意基础知识的查漏补缺,因为双非院校可能教学资源有限,可能存在一些基础薄弱的地方。 接下来,分步骤思考: 1. **巩固Java核心基础**:虽然可能学过,但实际开发中常用的集合、多线程、JVM等可能需要更深入的理解。比如,ArrayList和LinkedList的区别,ConcurrentHashMap的实现原理,JVM内存模型等。 2. **掌握Spring全家桶**:Spring Boot、Spring MVC、Spring Cloud等是必备的。实习中可能已经接触到了,但需要系统化学习,理解原理而不仅仅是使用。 3. **数据库优化**:SQL编写、索引优化、事务隔离级别,以及NoSQL如Redis的使用。实际项目中数据库性能往往是瓶颈,需要重点掌握。 4. **参与实际项目**:在实习中主动承担责任,多问问题,理解业务逻辑背后的技术实现,积累调试和解决问题的经验。 5. **代码质量与设计模式**:写出可维护的代码,学习设计模式,理解如何设计模块化的系统,避免重复代码。 6. **工具链熟练使用**:比如Git分支管理,Maven依赖管理,Linux基本命令,以及IDEA的调试技巧。 7. **学习系统设计**:从简单的模块设计到分布式系统,了解微服务、缓存、消息队列等架构设计。 8. **算法与数据结构**:虽然工作中可能不常写复杂算法,但面试时会考,尤其是大厂。LeetCode刷题是必要的。 9. **软技能**:沟通能力,文档编写,团队协作。实习中需要和同事有效沟通,理解需求。 10. **持续学习与社区参与**:关注技术博客、开源项目,参与技术讨论,比如GitHub、Stack Overflow。 可能的误区:不要只停留在框架的使用层面,要深入理解原理。比如Spring的IoC和AOP实现机制,MyBatis的缓存机制等。 需要推荐一些学习资源,比如书籍、在线课程、实战项目等。同时,制定一个学习计划,平衡工作与学习时间。 另外,考虑到他现在实习,时间可能比较紧张,建议优先提升与工作直接相关的技能,比如公司正在使用的技术栈,同时利用业余时间补充基础知识。 最后,鼓励他多做项目,将所学应用到实际中,通过解决问题来提升能力。同时,建议定期复盘,总结遇到的问题和解决方案,形成知识体系。</think>以下是针对 **实习阶段 Java 工程师** 的系统化提升方案,结合 **技术能力突破** 与 **职场生存技巧**,帮你快速从实习生成长为团队核心成员: --- ### **一、优先夯实四大实战基础(短期内见效快)** #### 1. **Java 核心深度补强** - **重点突破**: - 集合源码(`HashMap` 哈希冲突解决、`ConcurrentHashMap` 分段锁设计) - 线程池参数调优(拒绝策略、`ThreadPoolExecutor` 工作原理) - JVM 内存模型(堆栈结构、GC 日志分析工具) - **学习方式**: - 用 **Arthas** 在线诊断公司项目中的线程阻塞问题 - 每天阅读 30 分钟 **《Java 编程思想》** 配合实际代码验证 #### 2. **Spring 全家桶进阶** - **必学场景**: - 用 `@Transactional` 时事务失效的 8 种原因(自查清单) - Spring Boot 自动配置原理(`spring.factories` 文件解析) - Spring Cloud 微服务链路追踪(Sleuth + Zipkin 实战) - **实操建议**: - 在实习项目中主动申请 **封装公司内部 Starter** 组件 #### 3. **数据库与缓存实战** - **高频考点**: - SQL 索引优化(Explain 执行计划解读) - Redis 缓存穿透/雪崩解决方案(布隆过滤器、多级缓存架构) - 分库分表中间件对比(ShardingSphere vs MyCat) - **立刻行动**: - 用 **Jmeter** 压测实习项目接口,找出慢 SQL 并优化 #### 4. **开发工具链精通** - **效率翻倍工具**: - IDEA 插件:`SequenceDiagram`(生成方法调用时序图) - Git 高级操作(`rebase` 合并提交记录、`cherry-pick` 跨分支修复 Bug) - Linux 快速定位日志(`grep` + `awk` 组合命令) --- ### **二、实习生快速获得信任的职场策略** #### 1. **需求沟通技巧** - 接到任务时用 **5W2H 法** 确认细节(Why, What, Who, When, Where, How, How Much) - 每日下班前主动发送 **工作进度日报**(格式:已完成/卡点/明日计划) #### 2. **代码质量管控** - 提交 PR 前必做: - 用 **Alibaba Java 代码规范插件** 扫描 - 在本地跑通 **单元测试**(JUnit + Mockito) - 注释规范: ```java /** * 功能:分布式锁释放 * @param lockKey 锁键(需与加锁时一致) * @param requestId 请求标识(防止误删其他线程锁) * @return 是否释放成功 * @throws IllegalStateException 当锁不属于当前请求时抛出 */ ``` #### 3. **故障处理 SOP** - 生产问题排查流程: 1. 用 `tail -f` 查看实时日志 2. 通过 `jstack` 导出线程堆栈分析死锁 3. 使用 **Prometheus + Grafana** 定位性能瓶颈 - 撰写事故报告模板: ```markdown ## 故障概述 - 时间:2023-10-01 14:00 - 影响:订单支付接口超时率 30% ## 根因分析 - 数据库连接池配置过小(maxActive=20 → 实际并发 50+) ## 改进措施 - [x] 调整连接池参数并增加监控报警 ``` --- ### **三、差异化竞争力构建(3-6个月)** #### 1. **架构设计意识培养** - 学习 **DDD(领域驱动设计)** 划分微服务边界 - 研究公司现有架构痛点,提出改进方案(如引入 **RocketMQ 削峰填谷**) #### 2. **技术影响力建设** - 在团队内部分享: - 《如何用线程池优化公司批处理任务》 - 《Spring AOP 实现统一权限校验的最佳实践》 - 参与开源项目(从修复文档 typo 开始) #### 3. **全链路技术栈拓展** - 前端:学习 **Vue3** 完成一个管理后台(理解前后端协作流程) - 运维:用 **Docker** 封装项目环境(编写 Dockerfile 最佳实践) --- ### **四、学习资源精准推荐** 1. **书籍** - 《凤凰架构》—— 周志明(分布式架构演进) - 《企业级 Java 应用开发实战》—— 倪超(支付宝架构师经验) 2. **视频课程** - B 站 [Java 工程师成神之路](https://www.bilibili.com/video/BV1FV411h7M7)(技术图谱梳理) - 极客时间 [Java 业务开发常见错误 100 例](https://time.geekbang.org/column/intro/100106701)(避坑指南) 3. **实战项目** - GitHub 热门项目: - [miaosha](https://github.com/qiurunze123/miaosha)(高并发秒杀系统) - [spring-cloud-microservice-example](https://github.com/eacdy/spring-cloud-microservice-example)(微服务脚手架) --- ### **五、关键成长里程碑规划** ```mermaid gantt title Java 工程师成长路线 dateFormat YYYY-MM-DD section 基础巩固 Java 并发编程 :done, des1, 2023-10-01, 30d Spring 源码精读 :active, des2, 2023-11-01, 45d section 项目突破 参与核心模块开发 :crit, des3, 2023-11-15, 60d 主导技术方案设计 :des4, 2024-01-01, 30d ``` --- **行动建议**:下周起,每天抽出 1 小时专项攻克一个技术难点(如周一研究线程池参数配置,周二用 Arthas 分析内存泄漏)。遇到复杂问题及时记录,周末统一向 mentor 请教。坚持 3 个月后,你会看到质的飞跃! 💪
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值