[erlang]高并发下的日志输出技巧

前言

之前, 公司引进了压力测试的概念, 会使用 tsung 测试高并发下服务的性能. 这一测试, 原始的 lager:info 方法的弊端便显示出来了. 测试服务在打印了一次日志的情况下, 性能降到了空跑的1/6.

探究

日志的本质, 其实是躺在 /opt/app/log 目录下的文件. 尽管我们用多线程的方式避开了入口的瓶颈, 但是当我们需要访问相同的资源的时候, 瓶颈又出现了. 尽管我们的实现中没有出现锁, 但是实际上锁还是存在的. 那么, 相信有点基础的读者该明白问题的解决方案了: 用给节点发消息, 信箱接收的方式来排序, 将并发变为串行, 解决锁的问题.

实验

在服务(cowboy) 启动的时候开启一个新节点, 将节点注册为 pid_lager

true = register(pid_lager, spawn(tools, log, []))

需要打日志的时候, 将日志的信息发送到 lager_pid 节点

tools:lager_log(info, <<"hello">>)

节点收到信息后进行打印处理

log() ->
  receive
    {info, Msg} ->
      lager:info(Msg),
      log();
    {info, Format, Data} ->
      lager:info(Format, Data),
      log();
    {warning, Msg} ->
      lager:warning(Msg),
      log();
    {warning, Format, Data} ->
      lager:warning(Format, Data),
      log();
    {error, Msg} ->
      lager:error(Msg),
      log();
    {error, Format, Data} ->
      lager:error(Format, Data),
      log();
    _ ->
      log()
  end.
lager_log(Level, Msg) when Level =:= info orelse Level =:= warning orelse Level =:= error ->
  pid_lager ! {Level, Msg}.
lager_log(Level, Format, Data) when Level =:= info orelse Level =:= warning orelse Level =:= error ->
  pid_lager ! {Level, Format, Data}.

结果

在消除竞争的情况下, 日志带来的损失大约是几个百分点的性能损失. 但是有个缺陷是单位时间的输出日志有上限, 在每秒1w压力下, 只能打6000多条日志. 剩余日志会在压力测试结束后继续运行并输出. 这个我就没有很好的方法了, 只能考虑说精简日志, 将服务备份并部署多个的方法来缓解压力了.

你可能感兴趣的:([erlang]高并发下的日志输出技巧)