高并发系统设计40问
唐扬
美图公司技术专家
立即订阅
9202 人已学习
课程目录
已更新 38 讲 / 共 40 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 为什么你要学习高并发系统设计?
免费
基础篇 (6讲)
01 | 高并发系统:它的通用设计方法是什么?
02 | 架构分层:我们为什么一定要这么做?
免费
03 | 系统设计目标(一):如何提升系统性能?
04 | 系统设计目标(二):系统怎样做到高可用?
05 | 系统设计目标(三):如何让系统易于扩展?
06 | 面试现场第一期:当问到组件实现原理时,面试官是在刁难你吗?
演进篇 · 数据库篇 (5讲)
07 | 池化技术:如何减少频繁创建数据库连接的性能损耗?
08 | 数据库优化方案(一):查询请求增加时,如何做主从分离?
09 | 数据库优化方案(二):写入数据量增加时,如何实现分库分表?
10 | 发号器:如何保证分库分表后ID的全局唯一性?
11 | NoSQL:在高并发场景下,数据库和NoSQL如何做到互补?
演进篇 · 缓存篇 (6讲)
12 | 缓存:数据库成为瓶颈后,动态数据的查询要如何加速?
13 | 缓存的使用姿势(一):如何选择缓存的读写策略?
14 | 缓存的使用姿势(二):缓存如何做到高可用?
15 | 缓存的使用姿势(三):缓存穿透了怎么办?
16 | CDN:静态资源如何加速?
加餐 | 数据的迁移应该如何做?
演进篇 · 消息队列篇 (6讲)
17 | 消息队列:秒杀时如何处理每秒上万次的下单请求?
18 | 消息投递:如何保证消息仅仅被消费一次?
19 | 消息队列:如何降低消息队列系统中消息的延迟?
20 | 面试现场第二期:当问到项目经历时,面试官究竟想要了解什么?
用户故事 | 从“心”出发,我还有无数个可能
期中测试 | 10道高并发系统设计题目自测
演进篇 · 分布式服务篇 (9讲)
21 | 系统架构:每秒1万次请求的系统要做服务化拆分吗?
22 | 微服务架构:微服务化后,系统架构要如何改造?
23 | RPC框架:10万QPS下如何实现毫秒级的服务调用?
24 | 注册中心:分布式系统如何寻址?
25 | 分布式Trace:横跨几十个分布式组件的慢请求要如何排查?
26 | 负载均衡:怎样提升系统的横向扩展能力?
27 | API网关:系统的门面要如何做呢?
28 | 多机房部署:跨地域的分布式系统如何做?
29 | Service Mesh:如何屏蔽服务化系统的服务治理细节?
演进篇 · 维护篇 (5讲)
30 | 给系统加上眼睛:服务端监控要怎么做?
31 | 应用性能管理:用户的使用体验应该如何监控?
32 | 压力测试:怎样设计全链路压力测试平台?
33 | 配置管理:成千上万的配置项要如何管理?
34 | 降级熔断:如何屏蔽非核心系统故障的影响?
高并发系统设计40问
登录|注册

07 | 池化技术:如何减少频繁创建数据库连接的性能损耗?

唐扬 2019-10-02
在前面几节课程中,我从宏观的角度带你了解了高并发系统设计的基础知识,你已经知晓了,我们系统设计的目的是为了获得更好的性能、更高的可用性,以及更强的系统扩展能力。
那么从这一讲开始,我们正式进入演进篇,我会再从局部出发,带你逐一了解完成这些目标会使用到的一些方法,这些方法会针对性地解决高并发系统设计中出现的问题。比如,在 15 讲中我会提及布隆过滤器,这个组件就是为了解决存在大量缓存穿透的情况下,如何尽量提升缓存命中率的问题。
当然,单纯地讲解理论,讲解方案会比较枯燥,所以我将用一个虚拟的系统作为贯穿整个课程的主线,说明当这个系统到达某一个阶段时,我们会遇到什么问题,然后要采用什么样的方案应对,应对的过程中又涉及哪些技术点。通过这样的讲述方式,力求以案例引出问题,能够让你了解遇到不同问题时,解决思路是怎样的,当然,在这个过程中,我希望你能多加思考,然后将学到的知识活学活用到实际的项目中。
接下来,让我们正式进入课程。
来想象这样一个场景,一天,公司 CEO 把你叫到会议室,告诉你公司看到了一个新的商业机会,希望你能带领一名兄弟,迅速研发出一套面向某个垂直领域的电商系统。
在人手紧张,时间不足的情况下,为了能够完成任务,你毫不犹豫地采用了最简单的架构:前端一台 Web 服务器运行业务代码,后端一台数据库服务器存储业务数据。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《高并发系统设计40问》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(45)

  • 每天晒白牙
    1.老师我想请教下文中说的线程池预热,既初始化核心线程数的线程,我看jdk的源码没看到预热过程。
    而且请求过来,如果线程数小于核心线程数,就创建线程处理,如果线程数大于核心线程数,就往队列中添加,如果是有界队列,则判断队列是否满了,如果满了,且线程数没有达到最大线程数就继续创建线程,是这样的流程,没有在初始化时就创建核心线程数这个数量的线程
    2.如果线程池采用无界队列,确实会存在内存撑爆的问题,且最大线程数这个参数就没用了,这种队列存在有意义吗?
    3.我们工作中也用到了池化技术,线程池,各种连接池
    4.我工作中遇到一个关于vertx-redis-clent的频繁fgc的问题,这个就是把请求放队列里,而队列是无界的,导致内存满了,频繁fgc,下面是我的排查过程,希望能对大家有帮助
    https://mp.weixin.qq.com/s/fWsy26VeUvb8yPKON3OTmA

    作者回复: 1. ThreadpoolExecutor提供了prestartAllCoreThreads方法可以预先启动核心线程
    2. 如果使用无界队列的话,最大线程数就没有意义了,因为永远不会用到,所以尽量不要使用无界队列

    2019-10-02
    7
    14
  • tyul
    重要线程池的队列任务堆积量,请问下老师,这个指标怎么监控。

    作者回复: jdk的ThreadPoolExecutor可以调用executor.getQueue().size()

    2019-10-02
    2
    14
  • helloworld
    老师在网上查了很多的资料对于TPS和QPS两个性能指标的区分,但是也没有搞清楚到底两者有什么区别,以及两者的计算公式,老师能不能详细解释下呢?感谢。打卡06.

    作者回复: 我理解的QPS是每秒查询数,是针对读请求的
    TPS是每秒执行事务数,倾向于写请求

    2019-10-08
    3
    10
  • 大卫
    我在设计一个产品要求的专辑详情页中使用到了自定义的线程池。

    专辑详情页中包含多个板块,部分几个板块要求动态请求搜索或者推荐接口获取数据,板块与板块之间要求内容去重,搜索推荐对于本系统来说属于第三方接口。

    经过考量,使用了CompletableFuture来实现并行请求,同时自定义线程池,使用有界队列,设置合理的线程池大小。根据压测结果,调整出一个合适的线程池大小,使该接口性能达到预期。

    作者回复: 👍

    2019-10-04
    4
  • 613
    phper太难了

    作者回复: 怎么会,是最好的语言呀:)

    2019-10-09
    3
  • Jxin
    1.先回答课后题,池化的应用。池化就是空间换时间。万物皆对象,而java里面的对象是有生命周期的。对象的生死对应着有生时资源申请和死时资源释放这两步操作,而这些操作是有时间开销的。这个时候如果想降低这些开销,那么就要少生对象少死对象,而要少生少死就得复用,即干完继续干不准死,即延长对象生命周期并重用之。那么就可以采用池化,用的时候往里面拿,用完放回去。所以就出现了对象池,而对象即万物。也就是说,只要你是想降低对象生死开销的,那么就可以采用池化。但于我个人,我不喜欢池化。
    2.我个人认为,池化仅用在线程池好点。其他都不咋地。因为线程是执行体本身,所以挺合适。其他池化操作,都属于资源,那么复用就要无状态,即拿出来和放回去要一个样,不然就会影响下一个人使用(下一个线程),那么在操作池化对象时要么得设计无状态要么得在归还或拿取做init操作,太麻烦,不直观,不喜。而且池化资源还是个竞量,这就是个提高复杂度的大坑,太糟糕了,弃了弃了。
    3.说归说,其实用还是用的,毕竟也不全是jvm内部的“干净”对象池,有些对象池跟jvm外部资源有关系“不干净”。这种不干净的对象池,采用池化按需配置也是比较恰当的操作,毕竟外部关系这种开销大小不好确定,比如各种连接池。
    4.但我个人做的工具,碰到这种空间换时间,随手就是线程空间绑定,虽然还有复用无状态的问题,但至少不担心竞量问题了。而各种数据链接池,如果开启了事务也是往线程空间内放该链接的(为了拿到同一条链接)。

    5.请教环节,系统的线程池我自己埋点压过,确如老师所说,cpu密集线程池看核数就够了,io密集可以多些并行,因为数据传输不需要cpu。但是,从我自己压,捣鼓出来的结果看。io操作的线程确实可以在不处于cpu操作的时间片内时,继续做数据传输,但是,它不让渡时间片,也就是当一个cpu调度到一个执行io操作的线程,这条线程不会快速让渡出时间片给其他cpu操作的线程,就像sleep似的。我想问下老师,为什么这样设计,出于什么考量,更或者是我自己捣鼓错了?

    作者回复: 线程在等待io操作的时候确实会让出CPU时间片,可以说说你是如何测试的吗~

    2019-10-03
    3
    3
  • 高源
    老师理论听的挺明白,还是需要动手实战啊,有些东西理解起来很模糊,但实践上有可能一下子就明白了😊

    作者回复: 😄

    2019-10-02
    3
  • longslee
    哈哈,老师我之前一直用Executor的FixedPool,它是无界的队列,所以也 core == max,但是我拿它来处理数据库相关的了,看来以后我得改过来~ 还有,max满了不一定是丢弃呀,可以实现接口自定义满空间的操作,可以丢弃,也可以重试,也可以记录什么的,但是重试一定要给它一定的时间,否则过快提交会StackOverFlow嗷~

    作者回复: 嗯那 可以自定义策略

    2019-10-10
    1
  • xu晓晨
    学完这节课我发现php不是最好的语言了。
    另外想问一下phper想学另外一名语言 是选择java还是go呢?

    作者回复: go,😂

    2019-10-08
    1
    1
  • 约书亚
    还有一种是内存池,用的地方相对较少,基本都是重型武器才有,比如netty这种。
    这门课总会提到实际工作中遇到的坑,还挺不错

    作者回复: 是的,内存池也是一种常见的池化技术的常见实现

    2019-10-03
    1
    1
  • jc9090kkk
    国庆打卡,感谢老师的分享,对于这篇文章存有个疑问,希望老师能解答一下:
    1.文中说的最小连接数是10和最大连接数是20-30,这个数是如何计算出来的?有没有参考标准或者计算公式?根据具体的业务场景或者规模,有什么可以套用的配置经验吗?
    2.这个最大连接数跟mysql配置参数中的max_connections有什么联系吗?如果连接池的最大连接数设置成100,最后的连接请求还是会打到mysql上,如果max_connections这个值太小,还是会报错的啊?这两个值应该一起配合使用吧?我的理解有问题吗?

    作者回复: 1. 其实这些是经验所得,这个数值需要在实际运行中来调整,初期可以按照这个来设置
    2. 连接池的最大连接数肯定要小于max_connections的,你的理解没错~

    2019-10-02
    1
  • 大鸡腿🍗
    唐老师,你说的监控队列的个数,他的作用是?根据监控调整队列个数,还是说我加任务的时候,过多需要把抛弃的任务记录下来。
    其次,有点不解的地方:有一次,我用线程池创建线程处理io密集任务,后面改成CompletableFuture更加快,这是为什么?CompletableFuture也是使用了线程池

    作者回复: 1. 需要监控队列里面堆积的任务数
    2. 这个要看线程池的使用方式

    2019-12-01
  • 被过去推开
    线程池任务堆积量在提交任务时打印日志来监控吗?或者在其他事件触发后查看队列任务堆积量?

    作者回复: 线程池的组件中可以获取堆积量的,ThreadPoolExecutor.getQueue().size(),可以启动一个线程定期打印到日志中

    2019-11-27
  • 布小丫学编程
    老师,我看Dubbo默认线程池实现是使用核心线程数=最大线程数=200个,还有默认使用同步队列SynchronousQueue。这样的设计有什么好处?一般这样的线程数同时能处理多少的并发请求?
    2019-11-19
  • 港岛妹夫
    给合作公司需要同步一些数据, 每天定时同步. 不能走文件,只能HTTP.
    起了一个线程池, 最大最小都是5. 用的无界队列. 一直都没有问题.
    去年有一天, 这个线程池突然不工作了. 同事跟我反馈, 任务不处理, 系统也没有崩. 只有这个线程池不工作了. 没找到问题, 重启好了. 至今不知道为什么.
    2019-11-12
    1
  • 逍遥
    老师,我还是没理解,那我们自己写代码创建的线程池,如果是按jdk原生线程池的流程先放入队列,那不就只适合cpu密集型的场景?这个是怎么解决?还是说tomcat帮我们处理了?

    作者回复: 是tomcat中使用的线程池与原生的线程池不同,tomcat使用的线程池是先增加线程,后放入队列

    2019-11-11
  • 逍遥
    老师请问一下,那我平时代码里面创建的线程池是属于jdk的原生线程池,还是tomcat的线程池呢,第一次知道两者的区别,为什么我在一些并发书籍里面看到的都是老师你说的类似tomcat线程池的执行过程😂

    作者回复: 默认的ThreadPoolExecutor是JDK原生的线程池

    2019-11-11
    1
  • 小喵喵
    请问下如何监控连接池的使用情况,还有有界对列使用情况?自己用代码实现还是有现成的工具???

    作者回复: 要用代码实现,比如线程池可以获取队列的堆积数量

    2019-11-10
  • lanco
    我认为中的检测连接池中的连接活性还是每次使用前去select 1会比较好,虽然依旧不会是原子性操作,但是相比于定期让线程去检测,检测完其实说不准因为其他原因挂了,我们去使用就gg了

    作者回复: 这样是对DB的查询量增加了一倍,高并发下可能性能会有影响

    2019-11-08
  • 雷霹雳的爸爸
    坑啊,jedis的连接池,旧版的jedis有个奇怪的玩意儿,.returnBrokenResource,得写段套路得代码避免把一个坏掉的连接又在之后被使用,结果我们那东西没按套路来,自己一通乱封装,还是个多租户的系统,写到别人家去了,然后就是如文章所说,maxThreadCount设小了,自己给自己把吞吐量给限制住了,怎么压也压不上去...

    作者回复: 😂😂

    2019-11-05
收起评论
45
返回
顶部