AWS EventBridge实战:事件驱动架构设计、路由规则与踩坑指南 事件驱动这个话题近几年被聊得很多但真正落到工程实施上能讲清楚“为什么用它、怎么配、踩了哪些坑”的实战内容其实不多。我最近帮一个团队重构了一套订单通知链路顺手深浅不一地把 AWS EventBridge 摸了个遍从最初的点对点调用改造到现在的事件总线架构中间经历了反复调整规则、排查事件丢失、补可观测性等一系列折腾。这篇文章就把整个过程拆开写出来包含选型思路、事件总线如何设计、路由规则怎么写、可观测性怎么搭以及一堆花钱买来的坑和教训。无论你是刚开始接触事件驱动架构的新手还是已经用过 SNS、SQS 想搞清楚 EventBridge 到底替代了什么这篇都值得你花十分钟读完。我被问得最多的问题是SNS 也能广播SQS 也能解耦为什么还要引入 EventBridge说实话早期我也是这么想的直到我自己动手搭了一套完整的事件流才理解 EventBridge 真正的价值不在“收发消息”而在“面向事件的路由能力”。下面我会从底层概念开始一步步带你建立起一条可用的生产级事件链路。1. 为什么最终选了 EventBridge从点对点耦合到事件总线1.1 点对点集成的问题到底出在哪很多团队的现状是服务 A 要通知服务 B直接封装一个 HTTP 客户端调用 B 的接口过了一阵服务 C 也需要这份数据于是在 A 里再加一个 C 的调用再后来D、E 都来了A 的代码里密密麻麻全是外部依赖任何一个下游抖一下A 就要跟着重试、熔断、改配置。我接手那个订单项目时最典型的一个场景是订单服务创建订单后要调用库存服务的接口扣减库存调用通知服务发短信调用数据分析服务同步订单明细。每次上线都有一个小节叫“改订单服务的代码加一个新的下游调用”。这就是典型的发布者与消费者强耦合生产者要知道“谁在关心我的事件”还要关心“对方接口长什么样、返回什么结构、出错了怎么处理”。一旦消费者列表变化生产者必须跟着发版。这种架构的另一个隐患是故障扩散。下游接口超时上游线程池被打满下游发布新版本改了响应字段上游解析直接报错。本来下游自己的问题结果上游跟着遭殃。事件驱动架构要解决的核心问题就是把这些点对点依赖改成“生产者只负责描述发生了什么消费者各自决定要不要响应”。1.2 EventBridge、SNS、SQS 到底怎么选很多人在选型时会拿这三者做对比我先说结论它们解决的问题有重叠但侧重点完全不同。SQS 是队列核心是“点对点消费、任务可靠传递”。一条消息只会被一个消费者取走处理完后删除。它适合任务分发比如上传文件后触发一个后台处理任务十台机器抢消息谁抢到谁处理。它不适合做一对多的广播路由因为每条消息默认只有一个消费者。SNS 是主题核心是“发布订阅、一对多广播”。一条消息推给所有订阅者但过滤能力很弱只能按消息属性做简单筛选无法基于消息体里的业务字段做精细化路由。而且 SNS 的订阅目标类型有限要接到 Lambda、SQS、HTTP 端点配置起来不算复杂但想基于内容做“如果订单金额大于 100 才路由到某个服务”这种规则SNS 基本做不到。EventBridge 做的事情更像“事件路由器 规则引擎”。它同样基于发布订阅模型但把“如何匹配事件、匹配后做什么转换、投递失败怎么办”这些能力都内置了。它支持用 JSON 格式的事件模式精确匹配匹配范围可以细化到 source、detail-type甚至是业务数据中的某个字段。目标是 Lambda、SQS、SNS、Step Functions、Kinesis、API Destination 等覆盖了大多数集成场景。我自己选型的判断标准可以总结成三句话需要任务队列、谁抢到谁处理就选 SQS只做无脑广播、不需要内容过滤SNS 够用有明确的“按业务字段路由到不同目标”需求或者想把各服务的集成规则集中管理EventBridge 是更合适的选择。2. 搭好事件驱动地基EventBridge 核心概念一次讲清2.1 事件总线和事件结构是两件不能混淆的事EventBridge 里有两个基础概念事件总线Event Bus和事件Event。事件总线是事件的入口通道所有发到 EventBridge 的事件都必须指定总线。每一条事件总线都对应一组规则规则决定哪些事件会被匹配、匹配后投递到哪个目标。每个账号默认有一条名为default的总线AWS 服务产生的事件默认进 default但自定义业务事件我更建议单独建一条总线这样规则、指标、权限都隔离得更干净。事件本身其实是一个 JSON 对象AWS 对事件的格式有约定基本结构长这样{ version: 0, id: 唯一标识EventBridge自动生成, detail-type: OrderCreated, source: order.service, account: 123456789012, time: 2025-01-20T10:00:00Z, region: ap-northeast-1, resources: [], detail: { orderId: ORDER-2025-001, customerId: CUST-1001, amount: 299.00 } }几个关键字段必须理解到位source是事件来源标识通常写成服务名比如order.service或inventory.service它决定了规则的第一个匹配维度detail-type是事件类型比如OrderCreated、OrderCancelled用来说明“发生了什么”detail是业务数据体携带订单编号、金额、客户 ID 这类实际内容。version、id、time、region这些字段由系统填充你发送事件时只要填 Source、DetailType、Detail、EventBusName 四个字段即可。一开始很容易把“发布者”和“事件类型”混在一起。比如同一个订单服务它可能发出OrderCreated、OrderCancelled、OrderShipped三种事件source 都是order.servicedetail-type 不同。规则匹配时source 和 detail-type 常常组合使用这样既不会因为 source 太宽把所有事件都收进来也不会因为 detail-type 太泛误伤其他服务的同类事件。2.2 规则、事件模式与目标路由的核心三板斧EventBridge 的路由能力核心就集中在“规则Rule 事件模式Event Pattern 目标Target”这个组合上。规则是绑定在某条事件总线上的它定义了两件事什么事件会被匹配匹配后投给谁。事件模式就是“什么事件会被匹配”的过滤器。它用 JSON 结构来描述比如我想匹配所有 source 为order.service且detail-type为OrderCreated的事件可以写成这样{ source: [order.service], detail-type: [OrderCreated] }注意这里的值都是一个数组意味着你可以写多个值每个值之间是“或”关系。如果还需要对 detail 中的业务字段做过滤可以在事件模式里继续嵌套{ source: [order.service], detail-type: [OrderCreated], detail: { amount: [{numeric: [, 100]}] } }这段模式的含义是只会匹配订单金额大于 100 的创建事件。这就是 EventBridge 比 SNS 强大的地方——过滤可以直接作用在 body 的业务字段上而不是依靠松散的消息属性。目标要说清楚的是“事件匹配成功后去哪里”。可以是一个 Lambda 函数也可以是一个 SQS 队列、SNS 主题、Step Functions 状态机甚至是外部 HTTP APIAPI Destination。一条规则可以挂多个目标每个目标可以独立配置。多个目标适合什么场景比如订单创建后库存服务要扣库存、通知服务要发消息两者关心的事件相同但处理逻辑完全不同于是可以建一条规则挂两个目标或者建两条各自独立规则分别挂目标。还值得提一下输入转换器Input Transformer。目标接收的默认负载就是完整事件但下游往往只关心detail里的几个字段这时可以用输入转换器裁剪事件结构只把orderId、amount这些业务字段传给 Lambda减少目标侧的解析成本和敏感数据暴露面。2.3 输入转换、DLQ 与 Schema Registry容易被忽略却影响巨大的三个组件输入转换器刚开始用容易忽略但它在生产环境真的很有用。比如目标是一个外部 Webhook你不想把完整 AWS 事件结构暴露给对方只想传给对方一个自定义 JSON用输入转换器可以做到。它有两种用法InputPath按路径提取原始事件里的部分内容InputTemplate在提取的基础上拼装新的 JSON。我习惯把它们组合成这样一个流程先用 InputPath 取$.detail再用模板包一层业务字段并加上固定头信息。DLQ死信队列是事件投递失败后的兜底。规则匹配成功但目标执行失败时EventBridge 会按目标的重试策略重试通常最多重试 24 小时或者一定次数。如果重试仍失败事件就会被丢弃。打开 DLQ 配置后失败事件会转投到一个指定 SQS 队列方便后续人工排查或者自动补偿处理。这里的教训后面单独说但建议任何面向上游生产事件的规则都必须配 DLQ。Schema Registry 其实是一个被严重低估的组件。它扫描经过总线的事件自动推断事件的 JSON 结构生成 Schema 并可以下载代码绑定Java、Python、TypeScript 等。这意味着生产者和消费者可以基于同一份 Schema 生成模型类字段变更时能更早发现问题解决“两边手写 DTO字段对不上”的问题。3. 一步步搭建生产可用的 EventBridge 事件流3.1 创建事件总线和第一条路由规则聊理论容易动手才是关键。我们从一个最小可用场景开始订单服务发送OrderCreated事件规则匹配后触发一个库存处理函数。这里是实际操作步骤。先在控制台或者用 CLI 创建一个自定义事件总线。CLI 命令如下aws events create-event-bus --name order-bus如果使用控制台在 Amazon EventBridge 左侧菜单选择“事件总线”点击“创建事件总线”名称填order-bus。建议在实际业务事件上用自定义总线不要全部堆在 default 里否则规则管理和指标查看都会变得混乱。然后创建规则。规则必须指定所属总线、事件模式以及目标。先建一个不带目标的规则模式匹配 source 和 detail-typeaws events put-rule \ --name order-create-rule \ --event-bus-name order-bus \ --event-pattern {source:[order.service],detail-type:[OrderCreated]}如果这里 command 返回一个RuleArn说明规则已创建成功。需要提醒的是--event-pattern的 JSON 在 shell 里转义很容易出错建议先用单引号包住整个 JSON。如果你在 Windows 环境做测试注意引号规则不同我会建议先写到文件里再通过file://方式传输能省下很多转义烦恼。3.2 编写生产者与消费者代码规则建好以后重点就是“事件怎么发进去”和“事件怎么被接住”。生产者端代码用 boto3 发送事件下面是 Python 的落地示例import boto3 import json client boto3.client(events, region_nameap-northeast-1) event { Source: order.service, DetailType: OrderCreated, Detail: json.dumps({ orderId: ORDER-2025-001, customerId: CUST-1001, amount: 299.00, itemCount: 3 }), EventBusName: order-bus } response client.put_events(Entries[event]) if response[FailedEntryCount] 0: print(发送失败:, response[Entries]) else: print(发送成功)put_events支持一次传入多个 Entries单次最多 10 条每条事件大小限制是 256KB。发送时如果FailedEntryCount大于 0说明部分事件被拒绝通常是因为事件大小超限、总线不存在或者权限不足。消费者端是一个普通 Lambda 函数。事件被投递进来后Lambda 收到的 payload 是完整事件结构哪怕你只想用 detail 里的数据也先别急着只取 detail。生产环境建议打印完整入参用于排障再做业务处理import json def handler(event, context): print(json.dumps(event)) detail event.get(detail, {}) order_id detail.get(orderId) amount detail.get(amount) # 这里是库存扣减逻辑 return {statusCode: 200, orderId: order_id}从代码角度看消费者并不关心事件是谁发的只关心 detail 字段是否有它需要的业务信息。这个特性就是解耦的核心体现生产者不需要依赖消费者的 SDK消费者也不需要探测生产者的接口。如果你想用 SQS 作为缓冲目标让处理能力削峰填谷建规则时目标指向一个 SQS 队列即可。EventBridge 会自动把事件投递进队列消费者按自己的节奏拉取消息。如果规则挂的是 Lambda事件是同步触发还是异步触发取决于 Lambda 的调用方式EventBridge 目标默认为异步调用。3.3 打通 IAM 与目标权限链路很多新手在把规则关联 Lambda 时遇到“事件没有触发 Lambda”的问题大部分原因不是规则写得不对而是权限链路没有打通。EventBridge 投递事件到目标时需要两个层面的权限一是目标资源必须允许 EventBridge 写入二是规则配置的目标角色必须有调用目标资源的权限。对于 Lambda 目标需要在目标函数策略resource-based policy中允许events.amazonaws.com主账号调用。控制台操作时它会自动帮你在创建目标时添加这种权限但如果用 CLI 或基础设施即代码Infrastructure as Code你必须自己处理。有时候你会见到一个“目标角色”的概念它的意思是为本次投递创建一个专门的 IAM Role并让 EventBridge 使用这个角色调用目标。拆开讲是这样的EventBridge 服务本身要扮演service-role去调用目标资源比如调用 Lambda 的lambda:InvokeFunction权限。如果你不给它这个角色投递就会静默失败。控制台上选择 Lambda 目标时默认可以不填角色是因为控制台偷偷在 Lambda 上添加了资源策略。但规则目标如果指向 Step Functions 或 API Destination最好还是建一个显式角色责任边界更清晰。有一个简单的自查路径规则触发了但目标没执行先看 CloudWatch 里 EventBridge 规则执行的FailedInvocations指标是否有增长如果增长去目标资源的 CloudTrail 里查日志看是否有 AccessDenied。这两种日志配合起来基本能定位 80% 的权限问题。4. 订单系统实战解耦、按规则路由与幂等处理4.1 业务场景和事件拓扑设计理论讲完我们落一个具体场景。某订单业务改造前订单服务创建订单后要串行调用库存、通知、分析三个服务改造后的目标是通过 EventBridge 把一次创建行为的后续处理全部拆成异步独立的消费者。改造后的链路大致是这样的订单服务创建订单持久化成功后只向order-bus发一条OrderCreated事件。库存在订单总线上的规则匹配到有新订单减库存通知服务订阅同一个事件类型发短信分析服务通过规则只接收金额大于 100 的订单事件做实时统计。库存、通知、分析三个服务之间不发生任何互相调用订单服务也不感知它们的存在。这个设计的核心收益有两点第一新增消费者时订单服务零改动只需要在 EventBridge 上加规则第二任何一个消费者故障只会影响自己的链路订单服务完全不感知因为事件已经发出去了后续处理是否成功那是消费者自己的事。这正是事件驱动架构的价值把“一个操作完成后的所有副作用”从同步阻塞调用中解放出来。4.2 精确路由的三种事件模式写法同一个事件发出后不同消费者需要不同粒度的数据EventBridge 通过不同的事件模式来实现。第一种是全量匹配适合通知服务。只要是订单创建事件不管金额大小都要发消息通知用户。{ source: [order.service], detail-type: [OrderCreated] }第二种是条件过滤适合分析服务。分析服务只关心金额大于 100 的订单避免对低价值订单也做无谓计算。{ source: [order.service], detail-type: [OrderCreated], detail: { amount: [{numeric: [, 100]}] } }第三种是组合排除比如取消事件中排除某些特定渠道的订单。模式可以针对多个业务字段做 AND 或 OR 的组合注意最外层是 AND 关系同一字段多个值才是 OR 关系{ source: [order.service], detail-type: [OrderCancelled], detail: { channel: [app, web], reason: [user_cancel, timeout_cancel] } }这个规则会匹配渠道为 app 或 web、取消原因为用户取消或超时取消的所有取消订单。实际项目里这类组合经常出现在运营策略、灰度策略中EventBridge 的事件模式天然支持这些写法不用消费者各自再写过滤逻辑。把过滤放在总线层消费者的代码就变得很干净接到的都是自己需要的事件处理函数不需要再做 if-else 判断是否该处理。4.3 消费者幂等与事件重试的正确心态事件驱动架构引入了一个新问题消息可能不止一次地被投递。EventBridge 对目标投递会做重试重试机制延时时长从几秒到几十分钟不等加上消费者自己的失败重试同一事件最终可能被处理两次。订单场景里最典型的后果就是扣库存被扣两次、短信被发两条、统计被算两遍。这是初学者最容易忽略的边界。我在这个项目里给每个消费者都设计了幂等键通常直接使用事件里的orderId eventTime或者 EventBridge 自动生成的id字段在数据库里建唯一索引处理前先尝试插入插入冲突则说明已经处理过直接跳过。另一个需要想清楚的问题是关于重试的态度。消费者处理失败时你是希望事件被星际重新投递还是先转 DLQ 人工处理我的实践是能重试的比如下游 API 暂时不可用就依赖 EventBridge 的重试不能靠重试解决的比如事件里数据本身残缺就快速失败转到 DLQ人工补偿比反复重试高效得多。如果所以规则都配置重试 24 小时很可能一个小错误被无限放大下游日志里全是同一批重试事件排障时反而被噪音干扰。5. 可观测性体验让每条事件都有迹可循5.1 CloudWatch 指标和告警要看哪些数事件驱动架构的难点之一就是一条请求从源头到消费者之间是异步链路出了问题很难定位。EventBridge 自身的可观测性做得很完善关键是把该看的指标和日志配好。EventBridge 默认向 CloudWatch 暴露三个核心指标Invocations规则尝试调用目标的次数、FailedInvocations调用失败的次数、ThrottledRules被限流的规则数。这三个指标按规则维度和总线维度都可以查建议最基础的两条告警就这样设置FailedInvocations在 5 分钟内持续大于 0发告警ThrottledRules大于 0发告警。第一条代表事件投递失败通常意味着目标权限或者目标资源出问题第二条代表下游处理不过来EventBridge 对该规则做了限流需要关注目标资源的并发或队列积压。除了指标事件轨迹Event Trace也是排障利器。CloudTrail 默认记录 EventBridge 的 API 调用比如PutEvents、PutRule、PutTargets你可以按事件 ID 或时间范围追踪一条事件从生产到写入总线的全过程。我排查丢失事件时经常先从 CloudTrail 确认生产者确实调用过PutEvents再查规则指标最后看目标日志三步下来基本能定位事件丢在哪个环节。5.2 事件归档和回放把后悔药提前备好EventBridge 有个被不少团队忽略的功能事件归档Archive和回放Replay。归档就是把经过总线的事件存下指定时间回放则是重新发送归档事件到同一条总线。这个能力在容灾和事故恢复里太有用了。假设分析服务的消费者上线一个新版本处理逻辑有 bug把最近三天的统计数据全部算错了修复逻辑后你希望重新处理旧事件但又不想让业务重新产生一遍订单。如果之前开启过归档你可以一键回放过去三天的数据让消费者用新逻辑重新处理。这个场景直接决定了恢复时间是从小时级降到分钟级。配置方式很简单在事件总线详情里点击“创建归档”选择要归档的事件模式或者直接归档全部事件设置保留天数。注意归档会产生额外费用按存储的 GB 计费所以我建议只对核心业务总线开归档并且把保留天数控制在业务可接受的回放窗口比如 7 天。回放时还能设置“开始时间”和“结束时间”精确圈定出问题的时间段避免全量重试导致下游流量激增。我实际用过一次某批凌晨数据被错误消费者清掉凌晨四点在控制台发起回放早上七点数据全部补回来了这个功能帮我省下了一天的手工修复时间。5.3 把链路追踪延伸到消费者侧EventBridge 本身只管“事件从总线到目标”至于消费者处理得怎么样它管不着。链路追踪要靠 X-Ray 或者服务自身的 Trace ID 来贯穿。我习惯的生产者代码里会生成一个correlationId放到事件的 detail 里消费者接到事件后把这个 ID 作为日志的 trace 前缀。这样一条订单事件从订单服务发出、到总线、到消费者、再到消费者调用外部 API全链路的日志都能通过 correlationId 串起来。X-Ray 在 Lambda 目标场景下会自动处理调用追踪但如果你是自建服务通过 API Destination 接收事件就需要自己在 HTTP 头里传递 X-Ray 追踪头。还有一个辅助工具是 EventBridge Schema Registry 的代码绑定。当总线上的事件结构变化后Schema Registry 会更新消费者如果用了自动生成的数据类重新生成一次代码就能发现字段差异。把这个能力接入 CI 流程后生产者和消费者的模型会自然同步起来避免“用字符串解析一切、全靠人肉对齐字段”的混乱状态。6. 踩坑实录与 EventBridge 使用避坑清单6.1 事件模式“看起来对但不对”的几类问题第一个坑是忘记事件模式里字段值的数组形式。很多人第一次写{source: order.service}然后发现规则怎么都不触发。正确写法是{source: [order.service]}。数组里的值是 OR 关系这个细节虽小但确实是我见过最多的低级错误。第二个坑是 detail 字段的层级匹配。detail 是一个嵌套 JSON事件模式里同样要按嵌套层级写。如果你的事件里 detail 结构是{order: {amount: 299}}事件模式必须写成detail: {order: {amount: [...]}}不能把 order 这一层省略掉。模式匹配是严格按照字段位置匹配的少一层就匹配失败。第三个坑是事件模式中值类型的精准匹配。比如detail.amount在事件里是字符串299事件模式里却想用numeric匹配大于 100这种永远不会生效因为numeric要求字段值是数字类型。排查这种问题最直接的办法是开启那条规则的自测功能控制台里打开规则点击“测试事件模式”粘贴一条真实事件进去看匹配结果比自己干猜快得多。6.2 DLQ 配置和 IAM 权限的隐形坑DLQ 配置有一个反直觉的点不是规则执行失败就会进 DLQ。EventBridge 的语义是当目标重试达到上限后事件被丢弃配置了 DLQ 才会转投到队列。但 Lambda 目标异步调用时Lambda 自身也有重试逻辑EventBridge 投递成功后 Lambda 内部执行失败这件事 EventBridge 是感知不到的只有 Lambda 自己的 DLQ 配置才会生效。这一点非常容易混淆我在实际项目里就遇到“EventBridge 指标显示成功、但消费者函数执行抛错、事件既不重试也不进 DLQ”的情况。所以对于 Lambda 目标我建议在 Lambda 的“异步调用”配置里也设置 DLQ两个层级的失败都要兜住。IAM 权限的隐形坑出现在跨账户投递场景。假设订单事件总线在账号 A分析服务在账号 B目标资源在账号 B规则里填了账号 B 的函数 ARN。即使账号 B 的 Lambda 资源策略允许调用如果 EventBridge 目标配置里没有指定正确的执行角色调用依然失败。跨账户事件路由的正确做法是在账号 A 建一个角色信任关系里允许events.amazonaws.com代入同时具备调用账号 B 目标的权限账号 B 的 Lambda 资源策略里Principal 要写清楚允许哪个角色调用而不仅是允许 account A。这个链条少一环都不通使用基础设施即代码工具部署时更容易踩到。6.3 EventBridge 常见问题速查表我把这段时间遇到的高频问题整理成了速查表供你们排查时参考。问题现象可能原因排查思路规则不触发事件模式字段值没写数组、层级错误、类型不匹配使用控制台“测试事件模式”功能一条条验证目标不执行目标资源策略未放行、接入角色权限不足查看规则FailedInvocations指标和 CloudTrail事件偶尔丢失DLQ 未配置、目标重试次数不够查看规则重试策略为规则配上 DLQLambda 收到事件但处理失败消费者自身逻辑错误、无幂等设计打开 Lambda 日志确认 DLQ 是否兜住失败事件事件被重复处理重试机制导致重复投递消费者使用事件 ID 或业务唯一键做幂等跨账户调用失败目标资源策略 Principal 配置错误、角色信任链断裂检查目标资源策略和 EventBridge 执行角色信任关系发送事件时 FailedEntryCount 不为 0事件超过 256KB、总线不存在、权限不足看返回条目里的错误码逐个字段排查这七类基本上覆盖了我遇到过的九成问题。如果现场还出现怪异行为比如规则删除后仍然有调用大概率是 CloudTrail 里的历史投递或者事件总线被误配置去控制台检查是否有多个规则指向同一目标就知道。还有一个资深玩家才知道的细节EventBridge 规则是最终一致性生效的你刚创建一条规则理论上要等几秒钟才能生效测试时不要创建完立刻狂发事件然后怀疑规则没生效。给它一点生效时间这是很多自动化测试踩过的坑一个脚本里 create rule 之后马上 put event结果偶发匹配不上其实就是事件模式更新还没到达服务端。最后聊一下成本。EventBridge 计费方式是“按发布到总线的事件数量”计费规则数量不收费目标是 Lambda 这类资源时按目标服务计费。实际做订单系统时一次订单创建只发一条事件即便有几个消费者同时消费成本也只是几条规则和几次 Lambda 调用的费用。相比 SNS 加 SQS 加 Lambda 的组合EventBridge 在中小规模场景下并不会带来明显成本压力反而能把架构简化不少。我现在个人做业务系统只要谈到“一个动作之后有多方关注结果”第一反应就是用事件总线把链路搭起来而不是再加一个 HTTP 接口。大致流程是先画事件拓扑、再定事件模式、然后配规则和消费者、最后补指标和 DLQ。这套流程走顺之后你会发现加新消费者变成了一件很自然的事情再也不会有打开订单服务代码改一通的恐惧了。如果你也在改造过程中遇到奇怪的路由或者投递问题可以把自己的场景写下来我们可以一起对着规则参数和事件日志慢慢磨。