后端物联网消息队列通信【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址https://gitcode.com/gh_mirrors/em/emqx点击查看免费下载导读在同时配置多个认证器Authenticator或多个授权源Authorization Source的 EMQX 集群中客户端被拒绝时往往难以快速判断到底是哪一个后端作出了拒绝决策。本篇技术指南基于 EMQX 开源仓库中changes/ee/feat-17671.en.md对应的功能变更系统讲解 EMQX 6.x 中新增的认证/授权拒绝日志后端归因能力认证拒绝时在 warning 级别输出authenticator_rejection日志并携带 authenticator id 与 provider 模块授权拒绝时在 warning 级别输出authorization_source_denied日志并携带 source type、模块、topic 与 action同时剖析其背后的逐认证器/逐授权源限流机制帮助读者在真实生产环境中快速定位拒绝来源同时避免日志洪泛。背景多后端场景下的排障痛点EMQX 的认证Authentication与授权Authorization都支持配置多个后端并按照链式chain顺序依次匹配认证链全局或按监听器listener配置若干 authenticator客户端连接时按顺序尝试直到某个 authenticator 返回明确结果授权链全局配置若干 authorization source客户端发布/订阅时按顺序尝试直到某个 source 返回匹配的 allow/deny。在多个后端并存时运维排障最困难的一点是当客户端被拒绝很难从一条笼统的拒绝消息中看出是哪个后端产生了决策。在本次变更之前授权拒绝的结果基本只能在**客户端追踪client trace**中逐条查看操作成本高而认证拒绝也缺少统一的、带后端归属的结构化日志。本次变更feat-17671从两个层面解决了该问题认证器返回错误导致客户端被拒绝时输出warning 级别的结构化日志标识产生拒绝的authenticatorid 与provider授权源拒绝某个操作时输出warning 级别的结构化日志携带 source type、模块、topic 与 action此前仅在 client trace 下可见。同时这两类新日志分别按authenticator和authorization source维度限流避免高频失败客户端造成日志洪泛。认证拒绝日志authenticator_rejection触发条件与日志内容当某个 authenticator 对客户端凭据返回{error, Reason}例如密码错误bad_username_or_password时认证链会停止并拒绝该客户端同时输出一条 warning 日志包含以下关键字段字段含义示例msg日志消息标识authenticator_rejectionauthenticator产生拒绝的认证器 ID由 mechanism 与 backend 构成password_based:mysqlprovider实现该认证器的 provider 模块emqx_authn_mysqlreason认证器返回的错误原因bad_username_or_password也就是说运维人员无需开启 client trace仅凭一条日志就能回答是谁拒绝了这个客户端。源码实现链路认证链的入口与遍历逻辑位于 emqx_authn_chains.erlauthenticate/2约 L178-L212先按 listener 从 ETS 表emqx_authn_chains查找专属认证链未找到时回退到全局链global_chain/1如mqtt:global并通过get_enabled/1只保留enable true的认证器do_authenticate/3约 L821-L906按顺序遍历认证器ignore如 precondition 未满足时继续尝试下一个当authenticate_with_provider/2返回{error, ErrReason}时{error, ErrReason} - ?TRACE_AUTHN_THROTTLE(warning, ID, authenticator_rejection, #{ authenticator ID, provider Module, reason ErrReason }), emqx_metrics_worker:inc(authn_metrics, MetricsID, failed), ...这段代码同时做了两件事输出带后端归因的 warning 日志authenticator为认证器 IDprovider为认证器实现模块递增该认证器的failed指标认证器级别的指标由emqx_metrics_worker按metrics_id(ChainName, ID)维护。从数据结构看#authenticator{}recordL22-L33本身就同时保存id、provider实现模块、enable、precondition与运行时state因此拒绝日志可以天然携带这两个归因字段。测试用例验证仓库测试 emqx_authn_chains_SUITE.erl 中t_authenticate_rejection_log约 L354-L371验证了该行为注册一个{password_based, mysql}认证器后使用错误用户名密码调用emqx_access_control:authenticate/1捕获日志并断言?assertMatch( [ #{ msg : authenticator_rejection, authenticator : password_based:mysql, provider : _, reason : bad_username_or_password } | _ ], [M || #{msg : authenticator_rejection} M - Logs] );可见测试同时覆盖了日志消息标识、认证器 ID 与错误原因字段。授权拒绝日志authorization_source_denied触发条件与日志内容当某个授权源authorization source对发布/订阅操作返回{matched, deny}时授权链停止并拒绝该操作此时输出一条 warning 日志携带如下字段字段含义示例msg日志消息标识authorization_source_deniedauthorize_type授权源类型即配置中的 typefile、http、redis等module实现该授权源的模块emqx_authz_fileusername发起操作的客户端用户名alicetopic被拒绝操作涉及的主题taction操作类型含 QoS 与 retain 信息SUBSCRIBE(Q0)、PUBLISH(Q1,false)源码实现链路授权链的遍历与决策位于 emqx_authz.erlauthorize/5约 L487-L508先判断超级用户superuser 直接放行并记?METRIC_SUPERUSER非超级用户进入authorize_non_superuser/4do_authorize/4约 L532-L554按顺序遍历 source states跳过enable false的源、检查 preconditionnomatch/ignore/{matched, ignore}均继续下一个源do_authorize_with_source/6约 L553-L613调用Module:authorize/4获得结果随后调用log_trace/6记录日志。其中log_trace/6约 L639-L686对{matched, deny}分支的处理如下{matched, deny} - %% Emit at warning level (throttled per source type) so that operators %% get per-source attribution for denials by default, without having to %% enable a client trace first. ?TRACE_THROTTLE( warning, bin(Type), AUTHZ, authorization_source_denied, #{ authorize_type Type, module Module, username Username, topic Topic, action emqx_access_control:format_action(PubSub) } )这里有两个值得注意的实现细节归因字段直接取自授权链运行时状态Type type(SourceState)是配置中的源类型Module authz_module(Type)是将类型映射到实现模块如file→emqx_authz_fileaction 采用可读化格式emqx_access_control:format_action/1见 emqx_access_control.erl会把内部 action 表示格式化为SUBSCRIBE(Q0)/PUBLISH(Q1,true)这样的可读字符串方便直接阅读日志。另外authorize_non_superuser/4L510-L525在{matched, deny}时还会递增对应源类型的deny指标与全局?METRIC_DENY计数因此日志与指标可以相互印证。与authorization_permission_denied的区别在 emqx_access_control.erl 中还维护了另一条相关日志authorization_permission_denied它描述的是最终权限判定结果整个授权链得出的 deny其中 publish 场景因另有cannot_publish_to_topic_due_to_not_authorized而在 info 级别记录其余场景在 warning 级别记录。二者定位不同authorization_source_denied回答哪个授权源拒绝了后端归因逐 source 限流authorization_permission_denied回答客户端权限最终被拒绝最终结论。在实际排障中可先用authorization_source_denied定位到具体源再结合该源的规则排查。测试用例验证仓库测试 emqx_authz_SUITE.erl 中t_source_denied_logged_at_warning约 L589-L607验证了该行为配置一个内容为{deny, all}.的文件源?SOURCE_FILE后捕获emqx_access_control:authorize/3返回deny过程中的日志并断言?assertMatch( [ #{ msg : authorization_source_denied, authorize_type : file, module : emqx_authz_file } | _ ], [M || #{msg : authorization_source_denied} M - Logs] );即日志确实以 warning 级别输出并携带源类型与实现模块。限流机制按 authenticator 与按 source 防日志洪泛拒绝日志如果对每个失败客户端都全量输出在恶意扫描或凭据爆破场景下会瞬间刷爆日志。为此本次变更引入了按后端维度的限流认证拒绝日志按 authenticator 限流授权拒绝日志按 authorization sourcetype限流。限流宏SLOG_THROTTLE与TRACE_THROTTLE日志宏定义位于 logger.hrl?SLOG_THROTTLE(Level, UniqueKey, Data, Meta)约 L43-L59先检查logger:allow(Level, ?MODULE)判断日志级别是否放行再调用emqx_log_throttler:allow(Msg, UniqueKey)判断是否通过限流?TRACE_THROTTLE(Level, UniqueKey, Tag, Msg, Meta)约 L104-L116在SLOG_THROTTLE基础上同时向 trace 系统发送事件?_DO_TRACE保证启用 client trace 时依然能追踪到该事件。其中第二个参数UniqueKey就是限流维度认证拒绝场景传authenticator ID?TRACE_AUTHN_THROTTLE(warning, ID, ...)即每个认证器独立限流授权拒绝场景传source typebin(Type)即每个授权源类型独立限流。限流器实现emqx_log_throttler限流核心实现位于 emqx_log_throttler.erl要点如下数据结构使用persistent_term保存每个受限流消息的序号引用SeqRefSeqRef由atomics:new/2创建对于需要按资源维度限流的消息如按 authenticator、source则保存#{UniqueKey SeqRef}映射放行判定allow/2约 L45-L54在全局日志级别为debug时直接放行便于调试否则调用do_allow/2通过?IS_ALLOWED(SeqRef)atomics:add_get返回 1 表示窗口内第一条决定是否输出窗口刷新与丢弃统计init/1中按log.throttling.time_window默认 60 秒周期触发refresh约 L79-L111统计每个限流消息在窗口内被丢弃的数量若大于 0 则输出一条汇总日志?SLOG(warning, #{ msg log_events_throttled_during_last_period, dropped DroppedStats, period emqx_utils_calendar:human_readable_duration_string(PeriodMs) });即被限流丢弃的日志不会无声消失而是以上一周期内各事件丢弃了多少条的形式汇总报告兼顾了日志完整性不丢统计与洪泛防护不逐条输出。受限流消息清单new_throttler/1约 L178-L208中明确列出了authenticator_rejection与authorization_source_denied两个消息二者均属于按资源维度限流即按 authenticator / source 建立独立计数器。相关配置项log.throttling.msgs的默认值定义在 emqx_conf_schema.erl 中其中包含-define(LOG_THROTTLING_MSGS, [ ... authenticator_rejection, authorization_permission_denied, authorization_source_denied, ... ]).并在 emqx_log_throttler.erl 中读取-define(MSGS_LIST, emqx:get_config([log, throttling, msgs], [])). -define(TIME_WINDOW_MS, timer:seconds(emqx:get_config([log, throttling, time_window], 60))).因此在emqx.conf或 Dashboard 配置页中可调整log.throttling.time_window限流统计窗口默认60slog.throttling.msgs需要限流的消息标识列表默认已包含authenticator_rejection与authorization_source_denied。配置文件示例可参考 emqx.conf 相关段落 及 rel/config 下的示例配置。实战解读如何定位哪个后端拒绝了客户端认证被拒假设某客户端使用错误密码连接EMQX 按认证链尝试到 MySQL 认证器后返回错误此时日志大致为warning: authenticator_rejection authenticator: password_based:mysql provider: emqx_authn_mysql reason: bad_username_or_password据此可以直接得出结论拒绝来自password_based:mysql这个认证器由emqx_authn_mysql模块实现无需开启 client trace。授权被拒假设某客户端订阅主题t时被文件授权源拒绝日志大致为warning: authorization_source_denied authorize_type: file module: emqx_authz_file username: alice topic: t action: SUBSCRIBE(Q0)据此可以定位到file类型的授权源及其实现模块emqx_authz_file再结合 emqx_authz_file 的规则配置排查为何拒绝。日志洪泛时的表现当某个认证器或授权源在窗口内被高频拒绝如扫描攻击时authenticator_rejection/authorization_source_denied每条仅在窗口内输出一次其余在窗口结束时合并为log_events_throttled_during_last_period汇总日志例如warning: log_events_throttled_during_last_period dropped: #{authenticator_rejection 1024} period: 1m这样既保留了哪个后端在拒绝的归因信息又避免了逐条刷屏。总结feat-17671 为 EMQX 的认证与授权子系统补齐了拒绝决策后端归因能力其核心价值可以概括为认证侧authenticator 返回错误时以 warning 级别输出authenticator_rejection携带 authenticator id 与 provider 模块见 emqx_authn_chains.erl授权侧授权源拒绝操作时以 warning 级别输出authorization_source_denied携带 source type、模块、topic、action见 emqx_authz.erl限流保护两类日志分别按 authenticator / authorization source 维度限流窗口内重复事件合并为汇总统计实现机制见 emqx_log_throttler.erl 与 logger.hrl相关配置位于log.throttling.*默认值见 emqx_conf_schema.erl可验证性认证与授权两侧均有对应的测试用例emqx_authn_chains_SUITE.erl、emqx_authz_SUITE.erl对日志内容与级别作出断言。对于运行着多认证器、多授权源的生产集群这组日志显著降低了客户端为何被拒绝的定位成本是认证授权排障路径中值得优先关注的结构化观测点。赞分享后端物联网消息队列通信【免费下载链接】emqxThe most scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles项目地址https://gitcode.com/gh_mirrors/em/emqx点击查看免费下载相关推荐EMQX 消除 MQTT v5 CONNACK 拒绝连接后的 unclean_terminate 误报警告日志PR 15872 修复解析EMQX 消除 MQTT v5 CONNACK 拒绝连接后的 unclean_terminate 误报警告日志PR 15872 修复解析 导读 本文围绕 E后端物联网消息队列通信Friend 后端 WebSocket 认证拒绝分级实践让日志严重级别跟随故障来源净化生产错误告警流Friend 后端 WebSocket 认证拒绝分级实践让日志严重级别跟随故障来源净化生产错误告警流 导读 本文基于 Friend 仓库的运维文档 back人工智能AI 应用语音移动开发后端桌面应用智能硬件MCP 服务ScyllaDB 每分区限流Per-Partition Rate Limit配置、拒绝策略与实现原理详解ScyllaDB 每分区限流Per Partition Rate Limit配置、拒绝策略与实现原理详解 本文围绕 ScyllaDB 的 per part数据库分布式数据库后端大数据创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考