Java性能调优实战
刘超
金山软件西山居技术经理
立即订阅
7535 人已学习
课程目录
已完结 48 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 怎样才能做好性能调优?
免费
模块一 · 概述 (2讲)
01 | 如何制定性能调优标准?
02 | 如何制定性能调优策略?
模块二 · Java编程性能调优 (10讲)
03 | 字符串性能优化不容小觑,百M内存轻松存储几十G数据
04 | 慎重使用正则表达式
05 | ArrayList还是LinkedList?使用不当性能差千倍
加餐 | 推荐几款常用的性能测试工具
06 | Stream如何提高遍历集合效率?
07 | 深入浅出HashMap的设计与优化
08 | 网络通信优化之I/O模型:如何解决高并发下I/O瓶颈?
09 | 网络通信优化之序列化:避免使用Java序列化
10 | 网络通信优化之通信协议:如何优化RPC网络通信?
11 | 答疑课堂:深入了解NIO的优化实现原理
模块三 · 多线程性能调优 (10讲)
12 | 多线程之锁优化(上):深入了解Synchronized同步锁的优化方法
13 | 多线程之锁优化(中):深入了解Lock同步锁的优化方法
14 | 多线程之锁优化(下):使用乐观锁优化并行操作
15 | 多线程调优(上):哪些操作导致了上下文切换?
16 | 多线程调优(下):如何优化多线程上下文切换?
17 | 并发容器的使用:识别不同场景下最优容器
18 | 如何设置线程池大小?
19 | 如何用协程来优化多线程业务?
20 | 答疑课堂:模块三热点问题解答
加餐 | 什么是数据的强、弱一致性?
模块四 · JVM性能监测及调优 (6讲)
21 | 磨刀不误砍柴工:欲知JVM调优先了解JVM内存模型
22 | 深入JVM即时编译器JIT,优化Java编译
23 | 如何优化垃圾回收机制?
24 | 如何优化JVM内存分配?
25 | 内存持续上升,我该如何排查问题?
26 | 答疑课堂:模块四热点问题解答
模块五 · 设计模式调优 (6讲)
27 | 单例模式:如何创建单一对象优化系统性能?
28 | 原型模式与享元模式:提升系统性能的利器
29 | 如何使用设计模式优化并发编程?
30 | 生产者消费者模式:电商库存设计优化
31 | 装饰器模式:如何优化电商系统中复杂的商品价格策略?
32 | 答疑课堂:模块五思考题集锦
模块六 · 数据库性能调优 (8讲)
33 | MySQL调优之SQL语句:如何写出高性能SQL语句?
34 | MySQL调优之事务:高并发场景下的数据库事务调优
35 | MySQL调优之索引:索引的失效与优化
36 | 记一次线上SQL死锁事故:如何避免死锁?
37 | 什么时候需要分表分库?
38 | 电商系统表设计优化案例分析
39 | 数据库参数设置优化,失之毫厘差之千里
40 | 答疑课堂:MySQL中InnoDB的知识点串讲
模块七 · 实战演练场 (4讲)
41 | 如何设计更优的分布式锁?
42 | 电商系统的分布式事务调优
43 | 如何使用缓存优化系统性能?
44 | 记一次双十一抢购性能瓶颈调优
结束语 (1讲)
结束语 | 栉风沐雨,砥砺前行!
Java性能调优实战
登录|注册

43 | 如何使用缓存优化系统性能?

刘超 2019-08-29
你好,我是刘超。
缓存是我们提高系统性能的一项必不可少的技术,无论是前端、还是后端,都应用到了缓存技术。前端使用缓存,可以降低多次请求服务的压力;后端使用缓存,可以降低数据库操作的压力,提升读取数据的性能。
今天我们将从前端到服务端,系统了解下各个层级的缓存实现,并分别了解下各类缓存的优缺点以及应用场景。

前端缓存技术

如果你是一位 Java 开发工程师,你可能会想,我们有必要去了解前端的技术吗?
不想当将军的士兵不是好士兵,作为一个技术人员,不想做架构师的开发不是好开发。作为架构工程师的话,我们就很有必要去了解前端的知识点了,这样有助于我们设计和优化系统。前端做缓存,可以缓解服务端的压力,减少带宽的占用,同时也可以提升前端的查询性能。

1. 本地缓存

平时使用拦截器(例如 Fiddler)或浏览器 Debug 时,我们经常会发现一些接口返回 304 状态码 + Not Modified 字符串,如下图中的极客时间 Web 首页。
如果我们对前端缓存技术不了解,就很容易对此感到困惑。浏览器常用的一种缓存就是这种基于 304 响应状态实现的本地缓存了,通常这种缓存被称为协商缓存。
协商缓存,顾名思义就是与服务端协商之后,通过协商结果来判断是否使用本地缓存。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java性能调优实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(19)

  • QQ怪
    学到了很多,挺收益的,思考题:更新效率太低,代价很大,且不一定被访问的频率高,不高则没必要缓存,还不如直接删掉,而且还容易出现数据不一致问题

    作者回复: 👍🏻 对的,两个并发写去更新还存在一致性的问题。不过,在删除缓存后,记得读取数据需要加锁或延时等待,防止读取脏数据。

    2019-08-29
    3
  • AiSmart4J
    还有就是更新缓存代价大。如果缓存里的数据不是把数据库里的数据直接存下来,而是需要经过某种复杂的运算,那么这种不必要的更新会带来更大的浪费。

    作者回复: 对的,这也是一种情况

    2019-08-29
    2
  • AiSmart4J
    如果是更新数据库再操作缓存的话,此时更新缓存的操作不是必须的。可能缓存里的数据并没有被读到,就会被下一次更新MySQL操作带来Redis更新操作覆盖,那么本次更新操作就是无意义的。
    2019-08-29
    1
    2
  • yungoo
    基于redis集中缓存更新数据采用删除而不是直接更新缓存的原因之一:避免二类更新丢失问题。

    分布式系统中当存在并发数据更新时,因无法保证更新操作顺序的时间一致性,从而导致旧值覆盖新值。

    如:
    t1时间点,A进程发起更新key1为1的P1操作。
    t1+x时间点,B进程发起更新key1为2的P2操作。
    其中P1 -> P2,数据库中值为2。

    而redis收到的指令,可能因网络抖动或者STW,实际为P2 -> P1,缓存的值为1,造成数据不一致。

    作者回复: 👍🏻 存在并发更新时数据不一致问题

    2019-08-29
    1
    2
  • godtrue
    我觉得看场景,我们是电商的核心系统,计算全部依赖缓存,我们的缓存是经过复杂计算的结构数据,每天定时任务刷新,更新是全部是先添加有效数据后删除无效数据。添加有效数据时,如果数据存在就是更新操作了啦!我觉得挺OK的
    2019-09-12
    1
  • Better me
    布隆过滤器为什么要经过n个hash函数散列,有什么特别的考虑吗

    作者回复: 这是为了计算不同的位置,通过不同位置置1,得出一个数值。

    2019-08-29
    1
  • Maxwell
    老师您说的:通常我们会在查询数据库时,使用排斥锁来实现有序地请求数据库,减少数据库的并发压力。这个通常哪些方案?

    作者回复: 最常用的就是使用同步锁或Lock锁实现。

    2019-08-29
    1
    1
  • ty_young
    老师您好,请问协商缓存和强制缓存没有关联么,不会先走强制缓存,然后在强制缓存的基础上走协商缓存
    2019-10-31
  • 绿里奇迹
    “当黑客利用大量没有缓存的 key 攻击系统时,缓存的内存会被占满溢出”。但是即使使用bloom filter,这些不存在的key也会被判断为不存在,于是继续在缓存中创建该key,直到缓存被占满请问使用bloom filter为什么能解决这类故意攻击的问题?
    2019-10-20
    1
  • 💢 星星💢
    老师,我有个问题,分布式更新或者删除缓存的时候,为啥不对这个操作加锁呢,例如a线程更新或者删除缓存,并更新数据库,然后解锁。此时b线程在争夺锁。并且持有锁。是不是性能问题,所以不这样,还是我理解错了?

    作者回复: 没有理解错,锁和我文中提到的队列都是解决redis缓存数据一致性问题的方案,这种解决方案会带来一定的性能损耗

    2019-09-29
    2
  • Liam
    把数据库的数据全部加载到bitmap?

    作者回复: 是的

    2019-09-05
  • Liam
    bloom filter怎么初始化呢?刚开始bit array都是0吧,不可能直接拒绝掉呀?难道是把数据库的

    作者回复: 初始化时将数据加载到bit array中

    2019-09-05
  • Maxwell
    老师高并发时会不会卡?影响吞吐量,涉及到要更改公用数据如消费积分总量、每天的消费积分额度,现在没加锁,靠数据库的事务更新,担心以后qps上来了数据库扛不住

    作者回复: 使用队列来异步更新数据,没有压力

    2019-08-30
  • victoriest
    只看 模块七 值回票价
    2019-08-30
  • 疯狂咸鱼
    浏览器缓存就是常说的http缓存么?

    作者回复: 对的

    2019-08-29
  • 许童童
    直接更新缓存中的数据,因为请求到达的顺序无法保证,有可能后请求的数据覆盖前请求的数据。直接将数据删除,就是一种幂等的操作,删除后,再去数据库拉数据,就不会有覆写的问题。

    作者回复: 对的,如果两个并发写去更新还存在一致性的问题,还不如直接删除,等下次读取的时候再次写入缓存中。不过,在删除缓存后,记得读取数据需要加锁或延时等待,防止读取脏数据。

    2019-08-29
  • Loubobooo
    课后题:原因很简单
    1. 很多时候,在复杂点的缓存场景,缓存不单单是数据库中直接取出来的值。比如可能更新了某个表的一个字段,然后其对应的缓存,是需要查询另外两个表的数据并进行运算,才能计算出缓存最新的值的。
    另外更新缓存的代价有时候是很高的。每次修改数据库的时候,都一定要将其对应的缓存更新一份,这样做的代价较高。如果遇到复杂的缓存数据计算的场景,缓存频繁更新,但这个缓存到底会不会被频繁访问到?如果没有,这个缓存的效率就很低了

    作者回复: 👍🏻 回答很全面

    2019-08-29
  • 撒旦的堕落
    老师说 缓存数据库一致性问题时 当一个线程缓存删除 而数据库中没有来得及删除时 另一个线程来请求数据 发现缓存中数据不存在去队列中判断 如果数据在更新中 则等待 然后唤醒 不过如果是不同进程中的线程呢 怎么唤醒?感觉这种方式要维护的数据更多了 要把删除的缓存取出来放到队列中 然后更新完成后 还要删除队列中的数据 为了应对分布式的情况 还要使用的是分布式队列 效率变低了 有木有更好的办法呢

    作者回复: 暂时没有想到更好的

    2019-08-29
  • -W.LI-
    老师真棒,全能。
    CDN的缓存策略是copy服务端的,协商缓存和强缓存?如果有些静态资源,服务端开发没做缓存策略,CDN还会缓存么?实际开发中用过一次CDN。是在资源路径前,拼接一段CDN路径。具体不知
    课后习题,如果并发操作时,虽然redis是单线程的但是没法保证网络延时下,先更新数据库。也先更新缓存。个人感觉失效一个key比写一个key开销小。网络传输上看,update还得传一个value的值,redis更新还得写缓存感觉也是失效慢。并发情况写两次(除开正确性)有一次的写完全浪费。

    作者回复: 通常我们是会指定一些静态资源文件上传到CDN上去,并且通过版本号来更新。例如,我们的js资源文件是 xxx001.js,如果我们更新了该资源文件,则将xxx002.js推送到CDN上,同时前端的访问路径也更新访问资源路径。

    2019-08-29
收起评论
19
返回
顶部