site logo

Keep doing what you want, never give up.

招聘会
文章配图

基于 MySQL 和 Redis 的缓存穿透、缓存击穿、缓存雪崩及最佳解决方案

为什么缓存优化至关重要? 在高并发系统中,缓存(Redis)能极大地减少数据库(MySQL)查询压力,提升网站性能。然而,如果缓存策略不合理,可能导致 缓存穿透、缓存击穿、缓存雪崩 等经典问题,进而引发数据库崩溃、系统可用性下降、响应变慢。 这些问题不仅影响SEO页面加载速度,还可能导致业务宕机。因此,深入理解Redis缓存的优化策略是架构设计中的关键。本文将详细介绍这些缓存问题的原理、影响,并提供对应的解决方案。 1. 什么是缓存穿透(Cache Penetration)? 缓存穿透: 缓存穿透是指查询的数据在缓存和数据库中都不存在,每次请求都会直接查询数据库还一无所获,导致数据库压力过大,甚至被击穿。通常发生在 恶意攻击、异常数据,导致 Redis 和 MySQL 都查不到数据。 解决方案 ✅ 方法 1:缓存不存在的空值(推荐) 当数据库返回空结果时,将 null 或 empty 值也存入 Redis,防止后续同样的查询持续打穿透到 MySQL 数据库。比如可用如下代码逻辑有效防止缓存穿透: key := "uid:9999999" result := redis.Get(key) if result == nil { user := db.Query("SELECT * FROM users WHERE uid=9999999") if user == nil { redis.Set(key, "empty", 60) // 缓存空值 60 秒 } else { redis.Set(key, user, 600) // 缓存正常数据 10 分钟 } } ✅ 方法 2:布隆过滤器(Bloom Filter)(高效拦截非法请求) 使用布隆过滤器存储所有合法的 uid,请求时先查询布隆过滤器,避免无效查询。 if !bloomFilter.Exists("uid:9999999") { return nil // 直接返回,不查询数据库 } ✅ 方法 3:参数校验 在 API 层面限制非法请求,避免 uid < 0 或超出正常范围的数据进入查询逻辑。
文章配图

理解 MySQL B+ 树索引:磁盘 IO、范围查询与性能优化

MySQL (InnoDB)主要使用 B+ 树索引,而不是哈希、二叉树或B树。 使用B+树的主要原因是B+树对磁盘IO友好,减少了磁盘IO操作,从而提高了查询的速度。 想象你在一本1000页的书中查找某个知识点,如果没有目录(索引),你只能一页一页的翻,这其实就是全书查找(对比到数据库就是全表扫描),这样的查找方式非常慢(效率低下)。但如果这本书有详细的目录那查找起来是不是快了很多?而B+树不仅是有目录,还是多层级目录(根目录只存大概分类、第2层目录存细化分类、。。。、最终数据-叶子节点),这样查询效率自然就高了。 B+树的非叶子节点只存储键值,不存储数据,叶子节点存数据;另外B+树是多叉树(相对二叉树),通常一个节点包含多个子节点,这就减少了树的高度。 举个栗子🌰:如果一个B+树索引有1000个分叉,那差不多只需要3层即可存储10亿条数据,这意味着查询时最多只需要3次磁盘IO。 注意:实际应用中索引键的类型和行数据的大小将直接影响数据的存储量 // InnoDB存储引擎每个节点(页)的大小通常为16KB // 每个索引项由索引键值和指向子节点的指针组成 // 假设键值以 bigint 类型为例,需占用 8 字节,指向子节点的指针占用固定的 6 字节 // 每个索引项的大小 = 8 + 6 = 14字节 每个节点可以存储的索引项数量 = 16KB / (8B + 6B) = 1170 个 // 三层 B+ 树的存储容量计算方法如下: 第一层(根节点):存储 1170 个指向第二层的指针; 第二层(中间节点):每个节点再存储 1170 个指针 = 1170 x 1170 = 1368900 个叶子节点; 第三层(叶子节点):存储实际的数据行指针。 假设每行数据大小为1KB,则每个叶子节点(16KB)可以存储16行数据,那么三层 B+ 树的 总存储容量 = 1368900(叶子节点数)x 16(每个叶子节点存储的数据行数)= 21902400 行, 也就是大约两千一百万行数据。 所以优化MySQL性能的一个可行方案就是控制索引键和要存储数据的大小,如下表,索引键占用的空间越大每个索引页能存储的索引项就越少,从而可能导致B+树的层级增加,以至查询性能下降(磁盘IO次数变多)。 数据类型 占用大小 是否适合索引? 备注 TINYINT 1字节 ✅ SMALLINT 2字节 ✅ INT 4字节 ✅ BIGINT 8字节 ✅ CHAR(10) 10字节 ⚠️ 定长字符串,存储开销比INT大 VARCHAR(255) 变长(最长767字节) ❌ 变长字符串会导致索引存储空间大,影响性能 TEXT/BLOB 不定长(存储在外部页) ❌ MySQL不能直接索引TEXT/BLOB类型 另外也可以通过启动MySQL时指定 –innodb-page-size=32K 或 通过my.cnf修改MySQL默认节点的大小的方式来降低树的高度:
文章配图

大厂面试 - 贝壳:JWT是什么?

JWT(JSON Web Token)是一种用于在网络环境中进行安全信息传递的开放标准 完整的JWT由三部分组成,其结构可以表示为xxxxxx.yyyyyy.zzzzzz格式。 头部(Header): 通常包含令牌的类型和加密算法; 载荷(Papload): 包含自定义的数据如用户信息,权限等; 签名(Signature): 作用是用来验证消息的完整性和真实性,防止消息被篡改; JWT是无状态的,服务器不需要为其保存会话信息,从而减轻了服务器的存储压力,但同时也意味着一旦泄露任何请求都会被允许,而常用的解决方法是给JWT设置不固定的过期时间,强制客户端过期重新获取。 JWT另一个特点是,一旦生成后在其过期前都不可再修改其有效期。 它的主要应用场景包括用户身份验证和授权,用户在登录成功后获取JWT后,后续的所有请求都需要携带该JWT向服务器请求资源,服务器则可以根据这个JWT来验证用户的有效性。
文章配图

大厂面试 - 贝壳:MySQL索引的最左前缀原则

1、MySQL索引的最左前缀原则是什么意思?如果有查询条件为 a > 1 and b = 1 and c = 1,请问这个查询能命中MySQL索引吗? 索引的最左前缀原则是指查询语句要使用索引的条件需要满足从关联索引的最左侧开始且需要连续匹配。 比如,如果创建联合索引的顺序是(a, b, c)则上面的查询条件就可以命中索引,但如果创建y索引的顺序是(b,a, c)或者其他顺序,则上面的查询语句则无法使用索引。 2、使用explain工具分析慢查询的时候需要关注哪些信息? 首先关注“type”项,如改项显示为“ALL”则意味着查询使用了全标扫描,这是最差的情况,必须进行优化。如果改项的值为“index”或“range”等则相对较好。 还要注意“row”这项,它代表预计扫描的行数,如果改值较大,即使查询使用到了索引也需要进行优化。 此外,“possible_keys”和“key”这两项也非常重要,前者表示可能使用到的索引,后者表示查询实际使用的索引。如果改项值为空则意味着未使用索引,需要立即优化。
文章配图

MongoDB聚合查询aggregate之group分组

MongoDB中并没有类似MySQL关系型数据库中Left Join这种连表查询,但是它提供了一个称为aggregate的聚合管道查询语法来让我们实现类似MySQL那样的关联查询。其大致思路就是将多个查询语句按顺序逐一执行,然后汇总结果。 假设我们有两个集合,一个用户集合用来存放用户信息名字叫user,另外一个集合名叫photo用来存放用户的照片信息。 用户集合user ------------------------- | uid | name | |-----------|-----------| | 100000 | A | | 100001 | B | | 100002 | C | ------------------------- 照片集合photo ----------------------------- | uid | photo | |-----------|---------------| | 100000 | A的照片一 | | 100001 | B的照片一 | | 100000 | A的照片二 | | 100002 | C的照片一 | ----------------------------- 现在的需求是查出user表中所有用户的照片集合,相同用户的照片需要合并在一个数组中: 查询结果 ------------------------------------------------- | uid | name | photo | |-----------|---------------|-------------------| | 100000 | A | A的照片一,A的照片二 | | 100001 | B | B的照片一 | | 100002 | C | C的照片一 | ------------------------------------------------- 这时我们就可以联合aggregate语句的$lookup、$unwind、 $project以及$group语法得出想要的结果,查询语句如下: