lager_error_logger_h dropped ~p messages in the last second that exceeded the limit of ~p messages/s

Erlang日志打印写入文件&映射tomcat 开发的时候在服务器环境大多数linux,开一个screen监控Erlang服务器后台也不是说不能用,但多人都要看后台日志的时候就不是很方便了,今天利用Erlang的file模块和tomcat配置一个简易的日志,能让大家同时通过端口映射看到实时刷新的后台日志(本篇与上一篇内容一致,换个标题引流) 阅读详情

log 这个事, 说大不大说小又不小. 大点的, 可以用scribe flume 这样的系统去做, 小点的, 也就打印一个调试信息而已. 在Erlang 中, log 这事情确实比较伤, error_logger 是个单点, io:format 容易导致节点崩溃. 在开源社区, lager 算是使用比较广泛的一个, 然而, 同样不能完全避免单点的问题. 因为在lager 中, lager_event 作为 core, 是单个进程存在的.

复制代码
 1 dispatch_log(Severity, Metadata, Format, Args, Size) when is_atom(Severity)->
 2     SeverityAsInt=lager_util:level_to_num(Severity),
 3     case {whereis(lager_event), lager_config:get(loglevel, {?LOG_NONE, []})} of
 4         {undefined, _} ->
 5             {error, lager_not_running};
 6         {Pid, {Level, Traces}} when (Level band SeverityAsInt) /= 0 orelse Traces /= [] ->
 7             do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, Level, Traces, Pid);
 8         _ ->
 9             ok
10     end.
复制代码

也就是在lager 中, 所有的log 都需要经过 lager_event 进程.

 

但是在lager 中, 有过载保护机制.

Prior to lager 2.0, the gen_event at the core of lager operated purely in synchronous mode. Asynchronous mode is faster, but has no protection against message queue overload. In lager 2.0, the gen_event takes a hybrid approach. it polls its own mailbox size and toggles the messaging between synchronous and asynchronous depending on mailbox size.

{async_threshold, 20},
{async_threshold_window, 5}

This will use async messaging until the mailbox exceeds 20 messages, at which point synchronous messaging will be used, and switch back to asynchronous, when size reduces to 20 - 5 = 15.

If you wish to disable this behaviour, simply set it to undefined. It defaults to a low number to prevent the mailbox growing rapidly beyond the limit and causing problems. In general, lager should process messages as fast as they come in, so getting 20 behind should be relatively exceptional anyway.

If you want to limit the number of messages per second allowed from error_logger, which is a good idea if you want to weather a flood of messages when lots of related processes crash, you can set a limit:

{error_logger_hwm, 50}

It is probably best to keep this number small.

简单点说就是, 相比较同步模式, 异步模式很快, 但是容易导致lager_event 单进程 message_queue 过大. 再且, 若设计使用不当, 导致lager_event 进程 large_heap 使整个VM崩溃也是分分钟的事.

现在, lager 采用的是hybrid 的方式, 也就是当lager_event 的message_queue_len 小于某个值时, 采用异步模式; 若message_queue_len 大于某个值, 就是用同步的方式. 很好理解, 继续瞧瞧内部的怎么实现的:

1, lager_backend_throttle 的启动

lager_backend_throttle 进程在lager_app 模块的start/2 启动, 也就是整个lager application 启动的时候.

复制代码
 1         {ok, Threshold} when is_integer(Threshold), Threshold >= 0 ->
 2             DefWindow = erlang:trunc(Threshold * 0.2), % maybe 0?
 3             ThresholdWindow =
 4                 case application:get_env(lager, async_threshold_window) of
 5                     undefined ->
 6                         DefWindow;
 7                     {ok, Window} when is_integer(Window), Window < Threshold, Window >= 0 ->
 8                         Window;
 9                     {ok, BadWindow} ->
10                         error_logger:error_msg(
11                           "Invalid value for 'async_threshold_window': ~p~n", [BadWindow]),
12                         throw({error, bad_config})
13                 end,
14             _ = supervisor:start_child(lager_handler_watcher_sup,
15                                        [lager_event, lager_backend_throttle, [Threshold, ThresholdWindow]]),
16             ok;
复制代码

简单易懂的代码,就不需要过多的解释了.

2, lager_backend_throttle 的作用

lager_backend_throttle 是 lager_event event server 中的一个handler , 会处理 message-tag 为log 的所有event, 但仅仅是全量接受而已, 不做实际的log 处理.

复制代码
 1 handle_event({log, _Message},State) ->
 2     {message_queue_len, Len} = erlang:process_info(self(), message_queue_len),
 3     case {Len > State#state.hwm, Len < State#state.window_min, State#state.async} of
 4         {true, _, true} ->
 5             %% need to flip to sync mode
 6             lager_config:set(async, false),
 7             {ok, State#state{async=false}};
 8         {_, true, false} ->
 9             %% need to flip to async mode
10             lager_config:set(async, true),
11             {ok, State#state{async=true}};
12         _ ->
13             %% nothing needs to change
14             {ok, State}
15     end;
复制代码

在接收到 message-tag 为 log 的 event 后, 通过process_info/2 函数获取当前的message_queue_len, 然后切换 async 模式.

3, async 模式的影响

async sync 模式会在message_queue_len 增大/降低过程中切换, 最终会对log 的notify 方式产生不同的影响.

复制代码
 1 do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, Pid) when is_atom(Severity) ->
 2     Destinations = case TraceFilters of
 3         [] ->
 4             [];
 5         _ ->
 6             lager_util:check_traces(Metadata,SeverityAsInt,TraceFilters,[])
 7     end,
 8     case (LevelThreshold band SeverityAsInt) /= 0 orelse Destinations /= [] of
 9         true ->
10             Msg = case Args of
11                 A when is_list(A) ->
12                     safe_format_chop(Format,Args,Size);
13                 _ ->
14                     Format
15             end,
16             LagerMsg = lager_msg:new(Msg,
17                 Severity, Metadata, Destinations),
18             case lager_config:get(async, false) of
19                 true ->
20                     gen_event:notify(Pid, {log, LagerMsg});
21                 false ->
22                     gen_event:sync_notify(Pid, {log, LagerMsg})
23             end;
24         false ->
25             ok
26     end.
复制代码

在async 为 true 的情况下, 使用 gen_event:notify(异步方式) 将log 交给lager_event 进程, async 为false 的情况下, 则使用gen_event:sync_notify(同步方式)将 log 交给 lager_event 进程.

 

notify/sync_notify

1, notify

notify 是用户进程将Event 组装成 message-tag 为 notify 的消息, 通过erlang:send/2 方式发给 event 进程(在lager 中也就是lager_event), 然后在event 进程中依次执行 handlers 中的handle_event callback 函数. 

复制代码
 1 server_update(Handler1, Func, Event, SName) ->
 2     Mod1 = Handler1#handler.module,
 3     State = Handler1#handler.state,
 4     case catch Mod1:Func(Event, State) of
 5         {ok, State1} -> 
 6             {ok, Handler1#handler{state = State1}};
 7         {ok, State1, hibernate} -> 
 8             {hibernate, Handler1#handler{state = State1}};
 9         {swap_handler, Args1, State1, Handler2, Args2} ->
10             do_swap(Mod1, Handler1, Args1, State1, Handler2, Args2, SName);
11         remove_handler ->
12             do_terminate(Mod1, Handler1, remove_handler, State,
13                  remove, SName, normal),
14             no;
15         Other ->
16             do_terminate(Mod1, Handler1, {error, Other}, State,
17                  Event, SName, crash),
18             no
19     end.
复制代码

2, sync_notify

sync_notify 是用户进程通过gen:call/4 函数调用event 进程, 消息的message-tag 为sync_notify. event 进程同样是依次执行handlers 中的handle_event callback 函数, 不同的是, 还会向用户进程reply 消息(ok).

 

highwatermark

在lager 中, error_logger_lager_h 作为 error_logger 的一个 handler, 主要用来限制每秒 from error_logger 的 message 数量.

同样是在lager application 启动的时候, 在start/2 中调用启动. 

在每次接收到event 时, 就会执行check_hwm/1 函数:

复制代码
 1 check_hwm(State = #state{hwm = Hwm, lasttime = Last, dropped = Drop}) ->
 2     %% are we still in the same second?
 3     {M, S, _} = Now = os:timestamp(),
 4     case Last of
 5         {M, S, _} ->
 6             %% still in same second, but have exceeded the high water mark
 7             NewDrops = discard_messages(Now, 0),
 8             {false, State#state{dropped=Drop+NewDrops}};
 9         _ ->
10             %% different second, reset all counters and allow it
11             case Drop > 0 of
12                 true ->
13                     ?LOGFMT(warning, self(), "lager_error_logger_h dropped ~p messages in the last second that exceeded the limit of ~p messages/sec",
14                         [Drop, Hwm]);
15                 false ->
16                     ok
17             end,
18             {true, State#state{dropped = 0, mps=1, lasttime = Now}}
19     end.
复制代码

 

总结:

1, sync 模式速度慢, async 速度快, 但是不利于稳定系统的负载;

2, log 这事说大不大, 说小真不小; 本地的log 也就是用来调试和debug 来用, 正经的还是应该使用外部的日志系统;

3, 认真了解application 的每一个参数, 对于参数的设定才更有把握.

标签:  Erlang,  lager,  overload protection
0
0
« 上一篇: Erlang ets -- something about cache continue
» 下一篇: Erlang tool -- recon

lager_nif_file_backend:更大的lager_file_backend使用erlang文件模块来操作文件 lager_nif_file_backend lager's lager_file_backend uses erlang file module to operates files. 替换lager_file_backend,qps可以提升50%,瓶颈在gen_event 立即下载

相关推荐

logger:Erlang日志系统 Erlang Logger

Erlang日志系统 启动日志应用:logger_app:start() 可动态控制日志等级: loglevel:set(Level) 获取当前日志等级: loglevel:get/0 每次调用后都会重新编译logger,加载module 添加了buffer缓存,每500ms或连续收到100条日志后才刷日志到文件中,优化后可以处理5000/s以上的并发请求。 参考自 ejabberd_logger

Erlang tool -- lager overload protection

log 这个事, 说大不大说小又不小. 大点的, 可以用scribe flume 这样的系统去做, 小点的, 也就打印一个调试信息而已. 在Erlang 中, log 这事情确实比较伤, error_logger 是个单点, io:format 容易导致节点崩溃. 在开源社区, lager 算是使用比较广泛的一个, 然而, 同样不能完全避免单点的问题. 因为在lager 中, lager_even...

weixin_30919571的博客 360

lager_flume:用于库存的 Flume 后端

啤酒的水槽后端 这个后端是为较大的用户实现的,用于将消息记录到水槽。 该库仅适用于flume 1.6+,因为thrift erlang 库没有紧凑协议支持,而thrift 二进制协议自1.6 以来已添加到flume。 用法 较大的处理程序配置应该是 {lager_flume_backend, ["localhost", 4141, info]} 虽然水槽节俭源可能看起来像 # thrift source a1.sources.r1.type = thrift a1.sources.r1.channels = c1 a1.sources.r1.bind = 0.0.0.0 a1.sources.r1.port = 4141 a1.sources.r1.protocol = binary 笔记 后端将: 发现不正确的配置时不启动,并且 当与flume的连接出现问题时,定期重新连接,例如f

Erlang/OTP中的日志与事件处理

日志功能是构筑在Erlang的事件处理框架之上的,而该框架又以gen_event行为模式为基础。该行为模式为事件处理器封装了简单易用的接口。要想进一步调整Erlang/OTP的日志框架,就得编写新的gen_event行为模式的实现模块。gen_event行为模式接口与gen_server的类似:其中包含你所熟悉的init和terminate回调函数,也包含和回调。不过gen_event接口用取代了,这儿正是你接收错误日志事件的地方。gen_server和gen_event回调模块的使用。

qq_53795917的博客 1498

五子棋小游戏,可联机,单机

五子棋小游戏,可联机,单机

ali140滑块

ali 140滑块采用补环境的方式进行逆向,需要的文件主要为这两个,其中collina.js是最主要的环境校验和参数加密的逻辑,这两个文件放本地进行补环境。然后挂上代理,先保证能够正常运行代码,补了些许后能够正常运行了,我们打印最主要的加密函数看看:n值就是得到:挂上代理看看鼠标事件,不管加密逻辑,关心入参即可:收集一些鼠标事件传进记录的函数。其余就是处理一些环境值,一些resetSA的逻辑就行。截图记录:

bboysteed的博客 1681

Lager使用说明

概述 Lager(开源)是Erlang的日志框架。它的目的是在erlang应用程序中提供一种更传统的方式来执行日志记录,这种方式可以很好地与logrotate和syslog等传统UNIX日志记录工具兼容。 特点 更细粒度的日志级别 (debug, info, notice, warning, error, critical, alert, emergency)(调试、信息、通知、警告、错误、关键、警报、紧急) Logger calls是使用parse transform进行转换,以允许捕获Modul

mt4836的博客 2420

基于Freertos与lwip移植FreeModbusTcp协议

基于FreeRTOS的N32G457VEL7之LWIP网络协议栈移植-优快云博客。

Dd_456456的博客 3239

erlang日志系统

本文章目的是解决产品化环境下,将日志输出到日志文件而不在erlang shell终端中显示,方便在shell中执行调试函数! 1、sasl sasl提供错误日志,系统过载保护等,它有定义了下面三个日志处理器 sasl_report_tty_h : 将日志输出到控制台 sasl_report_file_h :将日志输出到单个文件 error_logge...

room_bb的博客 1786

AI Agent开发大全第一课-AI是什么以及如何使用AI

近年来,人工智能的迅猛发展引发了广泛的关注,尤其是“大模型”这一概念越来越深入人心。大模型,顾名思义,通常指的是那些拥有大量参数、能够处理复杂任务的机器学习模型。与传统小模型相比,大模型在数据处理、信息理解和生成等方面表现更加出色。为了理解为什么现在的AI被称为大模型,我们需要深入探讨几个关键因素。立角色是指在提示词中清晰地界定交互双方的身份。明确用户希望模型扮演的角色,可以帮助模型更准确地理解上下文和用户需求。

打造全国最全的AI Agent开发知识领域的博客 1407

使用LSTM实现自动调制识别(RML2018.01a)

目录一、LSTM的代码实现1.1 导入包1.2 数据读取及数据集划分1.3 数据预处理1.4 构建LSTM模型 本文基于RML2018.01a大型数据集,给出LSTM的信号识别的实现方式(附代码) RML2018.01a数据集信息如下: 模型 传送门 CNN/ResNet 使用CNN/ResNet实现自动调制识别(RML2018.01a) LSTM 使用LSTM实现自动调制识别(RML2018.01a)) 一、LSTM的代码实现 1.1 导入包 import numpy as np

QAQIknow的博客 6124

无涯教程-Erlang - log函数

该方法返回指定值的对数。

无涯教程 545

C# WinForm上位机:从串口调试工具到智能温控系统(Modbus RTU协议实战+完整源码)

做工业上位机开发时,我们常从串口调试工具入手:验证设备通信、查看数据帧,但面对实际场景(比如温控、电机控制),单纯的“收发数据”远远不够——需要解析工业标准协议(如Modbus RTU)、实时监控关键指标、实现自动化控制逻辑,还要有稳定的UI交互和数据记录。串口调试工具能收发数据,但看不懂Modbus RTU帧(地址、功能码、寄存器、CRC校验);想控制温控设备(如加热器、风扇),但不知道如何通过Modbus写入控制指令;手动调节目标温度时,温度波动大,需要PID算法实现精准控温,但不会集成;

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1305

logstash到kafka:生产者发送的消息过大的报错

1.报错提示 KafkaProducer.send() failed: org.apache.kafka.common.errors.RecordBatchTooLargeException: The request included message batch larger than the configured segment size on the server. {:exception=>java.util.concurrent.ExecutionException: org.apache.k

qq_41582883的博客 1718

ARM 之十六 详解 CMSIS 版本变迁、各组件使用示例

目前,CMSIS 已经发展到了第六版,其目录结构也发生了重大的变化。在不断发展中,很多原来 CMSIS 的组件被不断独立出去,并因此成立了很多开源社区,今天就来学习一下!由于 CMSIS 已经包含了相当丰富的文档,因此,本文重点学习版本之间的变化以及一些实际使用示例。

技术干货 1958

用Virtuoso和Abstract完成gds2lef

需要用到的工具有virtuoso和abstract。 数模混合的项目通常需要模拟完成模块设计,把接去数字的pin打上label(text),数字的floorplan才能正式开始。 如果只需要简单的数字PR boundary和pin点位置,那么只使用virtuoso就够了,还想把模拟版图都转成lef就要用到abstract工具。 1.PR boundary+pin 1)在virtuoso中打开layout a) Gui操作: Create->P&R Objects->

m0_61544122的博客 8749

伤别

伤别 你走了,背上厚重的行囊 头也不回 矫健的背影,总是那么坚定 站在人头攒动的站台 满目都是行卷浮动的身影 肩擦肩,包撞包 撞出的都是人生的味道 回乡的愉悦短暂又匆匆 还没饮够家乡的酒 暖够孤单的心 车笛声声 脚步匆匆又把生活的重荷上演 或南下,或北上 颠沛流离的无奈 砰击了你们也曾蔚蓝的理想 游子呵 每座城市的美丽都有你们汗水铸成的辉煌 我读懂,世界读懂

yaav8vyalhba的专栏 316

GEE高阶应用——如何绘制2000-2022年土地利用变化轨迹时序图

土地利用变化是指在一定时间范围内,土地利用类型和结构发生的变化。时序变化是指这种变化随时间的推移而发生的序列变化。土地利用变化轨迹的时序变化具体介绍如下:首先,土地利用变化轨迹的时序变化体现在土地利用类型的演变上。在过去的几十年里,随着人口的增加、经济的发展和城市化的推进,土地利用类型发生了显著的变化。传统的农田逐渐减少,而城市、工业、交通、居住等用地的面积不断扩大。同时,随着环境保护意识的提高,生态保护用地、森林、湿地等绿色用地的面积也在增加。

此星光明博客 1114

解析Erlang日志组件lager的监督树和模块

为什么80%的码农都做不了架构师?>>> ...

weixin_34293911的博客 436

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

【erlang】lager源码剖析

lager是erlang的日志库,源码在:https://github.com/erlang-lager/lager,支持多个日志接收器,能够通过配置控制大量日志输出时节点的处理,以防止节点宕掉,适合生产环境中使用。参照官方文档对于每个配置参数的解释,能够适应大多数使用情况,但是有可能遇到配置了某些参数却不生效的情况,这时候需要结合源码理解每个参数。 一、整体框架 lager主要使用了gen_event,可以有多个回调模块,当调用到gen_event:notify的时候,所...

pointer_y的博客 1140

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

error_logger升级到lager:erlang日志框架

介绍: 由于公司需要将之前的error_logger升级为lager,guo

i450500375的专栏 3877

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Flume

Flume是Cloudera提供的日志收集系统,具有分布式、高可靠、高可用性等特点,对海量日志采集、聚合和传输,Flume支持在日志系统中制定各类数据发送,同时,Flume提供对数据进行简单处理,并写到各种数接受方的能力。其设计的原理也是基于将数据流,如日志数据从各种网站服务器上汇集起来存储到HDFS,HBase等集中存储器中。   Flume的核心是把数据从数据源收集过来,在送到目的地,为了...

心有猛虎细嗅蔷薇 501

flume学习(一)——安装和一个简单的netcat程序

flume学习(一)——安装和一个简单的netcat程序 本文主要参考: http://flume.apache.org/FlumeUserGuide.html#configuring-individual-components 首先介绍一下flume的主要作用 apache flume 是一个分布式,可靠的,可用的系统,主要用于高效的数据收集,从不同源中移动大量日志数

archer的技术故事 4961

Flume整体架构总结

Flume简介: Flume 是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统, Flume支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力。(Flume使用java编写,支持Java1.6及以上。)由原来的Flume OG到现在的Flume NG,进行了架构重构,并且现在NG版本完...

Universe — Higher and farther 2419

Erlang中日志管理三两话

原创文章,转载请注明: 转载自庆亮的博客本文链接地址: Erlang中日志管理三两话日志系统的重要性就不罗嗦了,直接开始吧。 一、基本概念 在Erlang中,通过两个概念管理错误事情:事件管理器(event manager)和事件处理句柄(event handles)。通常各种错误、警告和消息事件都会有Erlang运行时系统发送给事件管理器。在Erlang中,默认的

庆亮的博客 1369
上一篇: Socket 与 WebSocket
下一篇: socket调试
王树民
博客等级 码龄10年 912粉丝 560原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值