| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 大数据 -> 缓存管理经验分享 -> 正文阅读 |
|
[大数据]缓存管理经验分享 |
缓存穿透/击穿/缓存雪崩概述目前主流的数据库无法承载高并发的读取,因此后端应用大量使用分布式缓存来应对高并发的读流量,如果因为缓存穿透/击穿/雪崩原因导致大量流量打到数据库上,可能导致数据库挂掉。 缓存穿透访问一个缓存和数据库都不存在的 key,此时会直接打到数据库上,并且因为查不到数据,也不会写入缓存,所以下次同样会打到数据库,请求每次都会走到数据库,流量大时可能会击垮数据库。 解决方案【1】空值缓存:查询数据库发现没有数据,给对应的 key存入一个空值缓存,代码数据库中没有数据,应用查询到空值就直接返回,避免了穿透到DB。 缓存击穿存在一个高并发的热点 key,在缓存过期的一瞬间,有大量的读请求,由于此时缓存过期了,所以请求最终都会走到数据库,造成瞬间数据库请求量大,压力骤增,可能导致数据库挂掉。 解决方案【1】锁:①、当大量数据读取缓存并失败时,其实只需要一个线程/机器去访问数据库并填充数据,其他线程/机器只需要等待缓存填充完成后读取缓存就行。 缓存雪崩大量的 key设置了相同的过期时间,或者因为 Redis实例宕机,在同一时刻缓存全部失效,造成请求全部穿透到DB,瞬间DB请求量大,压力骤增,可能导致DB被打卦。 解决方案【1】过期时间打散:避免大量 key 同时过期,可以在设置过期时间时,在基础过期时间上加一个随机值来打散过期时间,通过打散过期时间,避免同一时间大量缓存过期。 缓存预热概述目前我们所使用的缓存大致可以分为两种,一种是分布式缓存例如 redis,另外一种就是本地緩存,有很多组件。 填充緩存的必要性1、采用被动填充,就会使得机器拉入集群以后,生产流量大量涌入,线程阻塞等待缓存数据返回,线程池打满,另外存在大量的反序列化,CPU打满的情况。导致服务不可用。 填充缓存时会遇到的问题问题1:采用主动填充在系统启动时会造成大批量的机器(几百台机器*N 个Key)同时请求数据库填充数据,导致数据库被打爆。 Redis Key大 Key,多Key的场景1、简单的 key存储的 value很大。 大 Key的危害1、内存占用大,空间不均匀。 解决方案分拆1、单个 key存储的 value很大:需要整体存取:分拆成多个 key mget。 部分存取:使用 hash值分拆,或者存入 redis hash中的 field。 删除大 key 线上删除要使用 unlink,del 会阻塞(自然过期也会出现阻塞) 其他1、redis hash 不能 expire field, redis 只能过期顶级 key。 大 Key改造大 JSON1、业务需求需要保存查询 sql 对应的结果集 k: sql hashcode → v: 查询结果 result 存入 redis,以及 k: sql hashcode → v:(时间、sql 语句、查询引擎),在本地存进 Map 序列化成 Json,由一个固定 key(SQL_CACHE)放入 redis,过期时间 7 天。 redis hash1、第一次改造就针对这个大 key 把原本的 map 直接存成 redis hash,避免反复序列化以及大 key 网络传输成本。
解决 bug后,由于我们只需要 valueList,直接使用 hvals
3、某一次请求调用了 7000 次 redis 操作导致了 timeout 发现了该异常。
细分前缀 k/v,set 管理 keys1、由于我们的 sql 自带时间属性,我们将 sql 和引擎一起做了 md5 or SHA1,java hashcode 碰撞概率大所以不采用,减少 key 的长度这里截取了前 8 位,TTL 一天,sql→ result 的缓存。这样每天或者切换引擎将自动生成新的 key,避免需要去删除或者更新缓存。 避免数据膨胀前言内存作为一种总量有限的资源,一旦耗尽,立马会造成非常严重的后果,例如持续性 fullgc、oom 导致进程被杀死等问题。结果基本上是服务不可用。 对于绝大部分系统,我们会在内存中存放各种数据在加速系统的响应。 对于内存中存放的数据,我们一定要有一种感知:它们随时可能变大而撑爆了内存。 因此,我们一定要小心谨慎,确保数据量在受控范围内。 内存占用的计算估计内存的占用是非常有必要的,如果我们能估计出单个对象的大小以及对象的大致数目,也就能够大致估计出整体的内存占用情况,从而做到心里有数。 下面介绍一下 java 中各类数据类型的内存布局。通过分析布局,我们可以精确的计算出单个类型的对象的大小。 基础数据类型1、java 中一共有 8 种基础数据类型,每种各自占用的字节数如下: 对象类型对象类型是复合类型,它有基础数据类型组成。 对象类型的内存占用分为 4 块:mark word、klass pointer、数据字段、padding。 数组数组实际上也是一种特殊的对象,此外,它还有个特有的字段:数组长度。 数组占用的内存分为 5 块:mark word、klass pointer、数组长度字段、数组元素、padding。 内存占用分析工具1、如果要精准的计算内存占用情况,还是需要借助工具的分析,这类工具目前并不太多。 防止内存爆炸使用原生类型替换 string根据前面的分析,能轻易计算出一个 String 的内存占用是 50+个字节(根据 String 的长度而变化,但至少是 50)。 在机票的业务场景中,会大量出现短长度 string(长度只有 2/3 个字符,例如航司 2 字码,机场/城市三字码等),这样的数据使用内存占用高达 50 的 String 来表示存在巨大的浪费。 使用 CodeUtil,可以把 String 编码成原生的数据类型,从而节约大量的内存占用(通常也能提升性能)。 目前这种技术在国际机票大系统引擎、agg 等比较消耗内存的系统中大量使用。 使用对象池一些业务场景中,往往存在大量数据完全相同的对象,如果能保证相同的对象在内存中只有一份,那么也能节省大量的内存占用。 例如,在引擎中,每一个 Fare 对象都有个字段,一共占用了 14 个字节,如下: 限制容器最大容量1、单个对象占用的内存通常不会太多,内存爆炸的情况几乎都表现为极大数量(上百万甚至上千万)的对象总和占据了大量的内存。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 13:22:37- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |