Erlang/Elixir 一个稳定高效的连接池

wudixiaotie · 2015年09月16日 · 最后由 pakehu 回复于 2016年02月15日 · 2300 次阅读

连接池很好写,基本架构就是一个 manager,在 manager 启动的时候负责创建链接并把连接存储到一个地方,然后每次请求过来都给出一个有效的连接。 为了保证效率,我采用了 ets 表,而没有用进程字典和 queue 作为存储连接的地方,为什么呢?因为 ets 表可以并发读和并发写,进程字典和 queue 速度是比 ets 快,但是只能有 manager 去访问,这样无形当中就形成了性能瓶颈,ets 则可以 N 多个进程同时去读,没有瓶颈,在并发的情况下比进程字典和 queue 快了不是 1 倍 2 倍。 在 erlang 中大部分数据库 driver 的连接都是一个进程,我们拿到的都是这个进程的 PID,拿 postgresql 的 driver 举例子。他的单个连接可以支持并发访问,所以连接池不需要加锁。 当我们给其他进程连接的时候,由于未知错误导致这个数据库连接进程挂掉了怎么办?所以我们需要一个 supervisor 进程来监督这些连接。每当有个连接死掉的话,就通知 supervisor 让他去重启,所以我们的重启策略就是永久的也就是 permanent,然后由于所有的链接都是一样的所以监控策略就是 simple_one_for_one,每 5 秒中重启 10 次就 dawn 掉整个 supervisor。 当我们一个连接挂掉,我们要求重启的时候也能通知 manager,告诉他替换新的连接,所以我们还需要在每次重启前执行一段代码,这样就需要个 worker,由他负责启动连接替换旧的连接,然后把新链接注册到 supervisor 上。 当 supervisor 挂掉后怎么确保 manager 也重启呢?我的做法是把 manager 注册到最顶层的 supervisor 上,然后 supervisor link 到 manager 上,这样保证了 manager 和 supervisor 任何一个挂掉,整个连接池都会重启。 真个架构最终形态应该是: 架构图片 具体的代码在这里:postgresql pool

ETS 虽然是并发的,但是有 1 个坑,如果多个进程同时写入 1 条数据,会无法保证这条数据的正确性。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号