pool模型

探究erlang_mysql_driver对同一时刻大量请求的支持

mysql:fetch 和 mysql_conn

今天看到网络上的一篇文章,说erlang_mysql_driver的连接池实际上是没有意义的。

大概意思是,我们使用mysql:fetch去执行sql语句,mysql:fetch会call一条消息到mysql_dispatcher进程中。所以当我们同一时刻大量调用mysql:fetch的时候,mysql_dispatcher中就会有多条call消息在阻塞在消息队列里,那么后面调用的进程必须等待,每个请求需要等待上一个请求执行结束后才能开始执行,所以虽然mysql_dispatcher背后有多个连接进程(mysql_conn)但是他们并没有起到并发使用的作用。

乍一看,好像挺有道理的。但是我又觉得不对劲,毕竟作者不至于挖个这么大的坑吧,于是测试了一下。

同一时刻,spawn 10万个进程,每个进程都调用mysql:fetch进行数据库查询。

按上面的说法,那么这个时候应该会有大量的消息阻塞在mysql_dispatcher中,测试结果却是mysql_dispatcher的消息队列很快就处理完了。也就是mysql_dispatcher很快就把这些消息分发给了mysql_conn,这里我建立9个mysql_conn进程。然后大部分的消息(10万个请求)被堆积在9个mysql_conn进程的消息队列中,而且每个mysql_conn收到的消息是平均的。

证明我们的mysql_dispatcher还是能够顺利完成任务的,而且可以看出mysql_dispatcher处理这些消息肯定只有简单的分发消息,没有涉及数据io过程的。

gen_server:call gen_server:reply

那么上面讲到mysql:fetch不是调用了gen_server:call吗,而gen_server:call确实是会阻塞的。但是这里阻塞的是调用者的进程,也就是我spawn出来的那些进程。而mysql_dispatcher对于这些消息的处理是非常快的,没有涉及到数据的io过程。

fetch_queries(PoolId, From, State, QueryList) ->

with_next_conn(

PoolId, State,

fun(Conn, State1) ->

Pid = Conn#conn.pid,

mysql_conn:fetch(Pid, QueryList, From),

{noreply, State1}

end).

mysql_dispatcher仅仅将消息转发给合适的mysql_conn,然后返回{noreply, NewState}。看好了,这里是noreply,所以业务进程调用mysql:fetch并不能在这里获得返回,这个时候业务进程还属于继续阻塞状态。

那么mysql:fetch的返回结果是从哪里得到?

mysql:fetch获得的返回结果是通过mysql_conn 使用gen_server:reply返回给调用进程的。

%% GenSrvFrom is either a gen_server:call/3 From term(),

%% or a pid if no gen_server was used to make the query

send_reply(GenSrvFrom, Res) when is_pid(GenSrvFrom) ->

%% The query was not sent using gen_server mechanisms

GenSrvFrom ! {fetch_result, self(), Res};

send_reply(GenSrvFrom, Res) ->

gen_server:reply(GenSrvFrom, Res).

这里可能会有一个疑问就是,mysql_conn如何找到mysql:fetch 的调用进程并且正确地将值返回给他,如果在调用进程等待的返回值期间,先收到其他返回值怎么办?

关于这个问题,要查询官方文档上关于gen_server:call的说法。当使用gen_server:call向某一指定的进程发送call消息的时候,收到消息的一方是这样处理的 :Module:handle_call(Request, From, State)。

让我们再看下文档,From is a tuple {Pid, Tag} where pid is the client and Tag is a unique tag.

如果收到handle_call的一方,使用{reply, Reply, State}返回,那么Reply will be given back to From as the return value of call/2,3。但是问题来了,我们的mysql_dispatcher并没有使用常规手段,他直接返回{noreply, NewState}。那么mysql:fetch的调用不是收不到返回值了,不要急,文档说了 if the function returns {noreply, NewState}, Any reply to From must be given explicitly using gen_server:reply/2。

问题又来了,难道mysql_dispatcher没有使用gen_server:reply?确实没有!但是他把From直接传递给了mysql_conn,最终是mysql_conn查询结束后使用gen_server:reply,把结果最终返回给了阻塞在mysql:fetch中的业务进程

所以,在erlang_mysql_driver的连接池中一开始建立多个连接,在面对大量请求的时候,确实是有帮助的,可以多个连接同时执行,最终的io压力会放在这几个连接进程上,mysql_dispatcher顶多就是要维护的进程池有点大罢了。

大并发执行fetch是否会有大量timeout 报错?

这个是题外话了,在测试的时候遇到的问题。因为毕竟只有10个连接来处理10万个请求,那么后面的几万个请求肯定要排队到好久之后的。这个时间一旦超过了设置的timeout时间,那么就会有timeout报错。 然而测试开始的时候,我没有看到timeout报错,一直很疑惑。后来发现是timeout报错导致业务进程直接挂了,已经没法打印报错出来了。 在上面的测试中,只有9个mysql_conn,同一时刻却要处理10万条sql。那么肯定会有其他大量的调用一直处于阻塞状态的,我们使用mysql:fetch(PoolId, Query)的形式查询,而mysql:fetch其实是封装了gen_server call,这个方法默认的timeout时间是5秒。如果在5秒内没有收到返回值,就会扔出一个timeout的错误。而如果不去catch这个错误,进程就直接挂了,那么错误也打印不出来了。 在测试中,使用mysql:fetch(PoolId, Query)的调用,刚开始的进程能收到返回值,但是5秒后,进程就只能收到timeout报错了。 另外 使用mysql:fetch(PoolId, Query, infinity)的调用,进程会一直等待,测试表明虽然有很多的sql查询请求,每个mysql_conn都收到了1万左右的消息,但是最终都能执行并返回结果。

erlang mysql driver_erlang_mysql_driver 源码分析2相关推荐

  1. java mysql 源码分析_JAVA JDBC(MySQL)驱动源码分析

    JAVA连接数据库是其众多功能中的一部分,主要有两种方式连接DataBase: 一种是采用JDBC-ODBC桥,另一种则是称之为纯驱动连接DataBase,第一种方式在大型项目中基本上不再使用,本系列 ...

  2. mysql bulkupdate_django_bulk_update源码分析

    ## django_bulk_update源码分析 这个第三方插件的体量几乎只相当于工作时两三天的代码量了,是一个比较容易开始进行源代码阅读的模块,阅读完这个代码对自定义的进行django拓展也是一个 ...

  3. java jdbc(mysql)驱动源码分析_JAVA JDBC(MySQL)驱动源码分析(二)

    本文系转载,地址:http://blog.csdn.net/brilliancezhou/article/details/5425687 上一篇中分析了Class.forName("com. ...

  4. java jdbc(mysql)驱动源码分析,JAVA JDBC(MySQL)驱动源码分析(四)

    connect方法是java.sql.Driver接口中定义的方法,如果连接的数据库不同,那么为不同的数据库编写JDBC驱动将变得很灵活,实现Driver接口即可.连接数据库时首先得装载JDBC驱动, ...

  5. 【MySQL】——mysql exporter源码分析

    一.前言 最近在做mysql innodb cluster的监控,发现mysql innodb cluster的集群状态没有对应的指标能采集到,索性看一波源码,魔改一把吧.源码链接奉上: https: ...

  6. mysql select源码分析_MYSQL源码分析(三)--Select语句

    ●MYSQL的查询语句起始于:mysql_execute_command(THD *thd),(sql_http://www.doczj.com/doc/2e2a5f295f0e7cd18425367 ...

  7. pbp 读取 mysql数据_SqlAlchemy 中操作数据库时session和scoped_session的区别(源码分析)...

    原生session: from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine from sqlalch ...

  8. 《MySQL 8.0.22执行器源码分析(3.2)关于HashJoinIterator》

    在本文章之前,应该了解的概念: 连接的一些概念.NLJ.BNL.HashJoin算法. 目录 关于join连接 probe行保存概念 Hashjoin执行流程(十分重要) HashJoinIterat ...

  9. mysql源码分析——InnoDB引擎启动分析

    一.InnoDB启动 在MySql中,InnoDB的启动流程其实是很重要的.一些更细节的问题,就藏在了这其中.在前面分析过整个数据库启动的流程,本篇就具体分析一下InnoDB引擎启动所做的各种动作.在 ...

最新文章

  1. 网络工程师的经典爱情观
  2. JAVA静态方法是否可以被继承 6,JAVA静态方法是否可以被继承?
  3. zz 递归算法转换为非递归算法
  4. TCL with SNPS collection_limitget_lib_pins
  5. android 使用Binder通信
  6. mysql 主从复制结构配置
  7. 好未来:今年12月31日停止内地义务教育阶段学科类培训
  8. js获取jsp上下文地址
  9. CSS魔法堂:hasLayout原来是这样!
  10. 动手学PyTorch知识点汇总
  11. (Win7重装)向官方Win7镜像注入驱动程序
  12. 2007最新反病毒软件工具大集合
  13. UE4 WebBrowser插件清除浏览器缓存
  14. [转载]ubuntu samba Windows共享 你可能没有权限访问网络资源
  15. MyBatisPuls入门案例
  16. 法国内政部选择IDEMIA和Sopra Steria为其开发新标准边境管制系统
  17. 电商五十五、商家申请入驻------------商家入驻审核业务分析
  18. 转帖:励建书:数学有助于大众理性思维的培养
  19. P4 学习笔记(1)-- P4程序的构成、基本组件
  20. 经纬度坐标转换为屏幕坐标

热门文章

  1. CF993E:Nikita and Order Statistics(FFT)
  2. 通过容器编排和服务网格来改进Java微服务的可测性
  3. nginx服务器绑定域名和设置根目录的方法
  4. 大数据发展新契机:中国人工智能产业创新联盟在京成立
  5. Linux面试题集锦
  6. 本年度最成功科技IPO企业之一:Twilio股票一月暴涨167%
  7. 解决SpringMVC中的 Could not find acceptable represent
  8. debian 7上安装svn
  9. 合并多个Word文档
  10. python_wifi