网络科技

    今日:768| 主题:244859
收藏本版
互联网、科技极客的综合动态。

[其他] 日邮件发送量千万级,谈京东的EDM平台优化之路

[复制链接]
兜兜转转 发表于 2016-10-12 06:04:37
123 8

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
EDM 是 Email Direct Marketing 的缩写,即邮件营销。它是利用电子邮件(Email)与受众客户进行商业交流的一种直销方式,邮件营销的对于企业的价值主要体现在三个方面:开拓新客户、维护老客户,以及品牌建设。
  京东的EDM平台每日发送量千万级别,峰值数据2T(每日),如何能在峰值到来时保证系统的稳定,以及从大量的邮件发送任务中筛选出高优先级发送任务并及时发送是构建这个平台的难点之一。
  老平台日益突出的问题

  原有的老平台已经是5年前的产物了,受限于当时研发人员对EDM的研发经验和当时的技术栈,老平台的几个问题在日后的发展中越来越突出,慢慢的让新架构变成了一件不可不做的事情。
  老平台存在的问题如下:
  1、技术栈、实现思路混乱

  受限于业务,老平台分成了生产邮件和促销邮件两个子平台。对于邮件任务的发送,老促销邮件平台引入了Thrift框架,而老生产邮件平台则通过抢占式更新数据库的方式实现。
  渲染邮件模板时,老生产使用的是velocity,而老促销已经改为由上层(邮件模板装修系统)用handlebars提前渲染好后直接发送。
  2、SQL Server的改造需求。

  老平台的数据库使用的是SQL Server,从降低公司成本的角度出发,有尽快迁移到MySQL的需求。
  3、历史需求包袱很重。

  很多业务已经下线,但是代码还留在线上(包括各种关联系统)。
  新平台:业务架构的确定

  在这样的情况下,我们决定抛弃老的平台,构建新一代的EDM平台。那其中第一步就是确认业务架构。
  新平台将由生产平台、发送平台和统一管理平台组成。生产平台负责生产邮件发送任务,发送平台则部署在主流运营商的网络上,冗余部署一定量的发送节点,保证发送成功率。因为邮箱服务提供商通常会对邮件的发送方按IP做流控限制,并且对各种网络运营商投递的邮件的接受程度也不一样。
  同时,为了保证在主流的网络运营商渠道上都有发送节点,避免因某个网段或某个运营商网络故障引起邮件发送成功率的波动。所以将发送和生产的逻辑区分开,有利于应用区分部署和扩容,平台间的职责也更加清晰。
  老平台也是生产和发送分成两个平台,只不过职责没有划分得非常清晰,比如各自的平台上都集成了管理功能,发送节点只能调节自己的发送策略,不利于发送策略的批量调整。
  生产平台和发送平台间使用Redis队列传递邮件任务。设计期间考虑过MQ,Kafka类组件,没有使用的原因是以上组件对于传递邮件的任务都“过重”,引入新的组件意味着新的风险,新组件的稳定性也会影响平台的稳定性。同时Redis对队列有原生的支持,作为当前最常使用的组件,起简单易用的特点正好符合新架构对这个组件的要求。再加上公司已经对Redis实现了集群及自动伸缩方案,可用率大大提高,学习零成本,都是Redis的优势,也是这次架构升级选用Redis的理由。
  建立统一管理平台,实现对生成和发送情况的统一调度。要求是实现对整个生产和发送平台的调度管理,包含指定高优节点,屏蔽成功率较低节点,降级开关等一系列措施。
  经过多次梳理和方案推导后,整个EDM平台的业务架构如下:
   
日邮件发送量千万级,谈京东的EDM平台优化之路-1 (品牌建设,邮件营销,数据库,优先级,Email)

  生产平台对接用户组,订单组,会员等系统的MQ消息或远程调用生成邮件发送任务,并按类型划分1-10个优先级,数字越大,优先级越高。
  Redis按优先级和目标邮箱两个维度拆分成多个Redis队列,负责将邮件任务传递到发送平台。
  发送平台聚焦在发送业务的处理上,包括优先级队列、发送降频、邮件模板渲染等事务。
  管理平台主要负责配置数据的维护、降级开关的推送和必要时人工对生产、发送平台的调度。
  方案细节

  1、Redis优先级队列

  首先,业务上决定了邮件任务的紧急程度是不一样的,例如用户对账户密码找回的邮件就比优惠券到账的及时性敏感度更高,显然密码找回的邮件需要以最快速度投递到用户邮箱中。这和某些在极端场景才出现的“优先级”不一样,是一直持续存在的高优任务,最简单的办法就是区别对待,按优先级设置队列,从生产平台开始到Redis队列再到发送平台都一直是一个或多个特殊的队列,方便系统对这些高优发送任务做处理。
  同样,高优先级队列长度的报警阀值比较小,一旦积压研发同学会第一时间收到报警,必要时可以人工接入。而发送平台总是最先拉取高优先级发送任务,保证其第一时间被处理。值得注意的是,从客观规律上看高优的邮件往往量是比较小,这使得发送平台总是优先处理高优的邮件并不会让优先级低的发送任务没有机会被拉取。
  当业务量较大,发送较为频繁时触发邮件服务商的流控,或网络不稳定,出口IP异常时都会引起部分发送平台的邮件投递成功率的下降,这时需要让成功率将低的节点暂时甚至永久的不再向邮件服务商投递邮件,解决方案之一是在队列的拆分维度除了优先级以外再增加一个目标邮箱,一旦出现上述问题后,可以直接让发送节点不再拉取该邮箱的所有队列来实现故障隔离。
  同时,用优先级和目标邮箱拆分Redis队列还有一个好处是,如果使用的是分布式的Redis,队列的元素总是在一个分片中的,如果队列过少,会导致有可能大量元素都集中在同一个分片中形成热点分片。将Redis队列拆分后可以让分个分片的读写相对更均衡,分片的利用率更高。实际上,Redis队列还设置了一个最大长度,防止队列无限制的增长。
  2、投递降频

  投递邮件时如果投递被拒绝邮件服务提供商一般都会返回一个错误码,发送平台上有一个错误映射表,发送错误后将错误码和错误映射表比较,如果触发了流控则降低邮件发送任务的拉取频率,直到投递成功率恢复后再逐步提升发送能力。
  3、Checker

  Checker是生产平台扫描邮件发送任务的定时任务的总称,按职责不同,Checker被具体分为UnsuccessChcker、InQueueChecker、ExpireChecker等等。职责是将各个状态的邮件发送任务更新为下一个流程需要的状态,比如将入库成功的状态更新为Redis队列中,Redis队列中更新为发送平台发送中,发送错误的任务更新为重新投递等等。
  重新投递是非常重要的一个功能,因为某个出口IP因为各种原因可能会常常被邮件服务商拒收,重试相当于有较大几率更换出口IP再做发送尝试,有利于投递成功率的提高。因为邮件发送任务常常被各种Checker更新,为了保证数据的一致性和状态按正确流程流转,邮件发送任务被加上了版本号,每次更新后自增,更新时使用乐观锁更新。
  性能优化

  初期平台上线时的第一版架构如下:

日邮件发送量千万级,谈京东的EDM平台优化之路-2 (品牌建设,邮件营销,数据库,优先级,Email)

  上线后出现了一系列的性能问题,总结起来主要为两类。
  第一类问题:写库CPU 100%,影响远程调用接口的性能,引发上游团队关注。

  引发写库CPU 100%的原因最主要的还是数据库同一时间读写请求太多和索引利用率不高导致的。因此第一步想将数据库的读写压力分开,对数据库做了读写分离,所有的读请求全部调整到了从库上去,以此降低主库压力。这里有一个前提是经过评估,从库读取脏数据并不会对业务产生困扰,因为邮件发送任务本身有版本号,即使数据库主从同步有延迟引起从库读到“脏数据”使用乐观锁更新时也会失败,不会引起业务错误。
  第二步将查询条件归一再后建立索引,索引不是越多越好,归一时可以现将查询任务列出来,观察哪些查询条件是相似的,有没有特殊的业务导致了不一样的查询条件,这些业务有没有办法从其他角度去支持,逐步归纳后再建索引。上述步骤多次使用后,通常情况必须要建立的索引就不会太多了。目前邮件发送任务表(分表后单表千万级)只有一个主键索引和一个组合索引(三个字段),所有查询条件全部先利用索引查询数据。
  调整完索引后发现Checker的扫描还是过于频繁,读库CPU利用率还是不够理想(过高),梳理业务后发现整个平台的发送能力取决于邮件服务商的接受量和一定程度的发送平台量(出口IP量)。两者不变的情况下,整个发送平台的发送量不会提升,Redis队列的吞吐能力也不变,Checker大部分时候运行的结果只是Push了个别元素,甚至没有Push。Checker完全可以改成Redis队列小于一定阀值,例如最大长度的1/2再做一次扫描,一次扫描尽量将队列填满。调整Checker策略和索引后数据库的QPS大约降了2/3,load也稳定在5以下。
  还有一个让数据库CPU较高的原因是Checker引起数据库死锁。
  例如有Transaction1需要对ABC记录加锁,已经对A,B记录加了X锁,此刻正尝试对C记录加锁。同时此前Transaction2已经对C记录加了独占锁,此刻需要对B记录加X锁,就会产生数据库的死锁。
123下一页
友荐云推荐




上一篇:丁香园前CTO冯大辉开启创业路 称将“干架”百度医疗
下一篇:20 women Silicon Valley tech companies should be adding to their boards
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

依恋ヽ那段情 发表于 2016-10-12 06:56:55
有钱的捧个钱场,没钱的回家拿钱捧个钱场。
回复 支持 反对

使用道具 举报

旧时光她是个美人 发表于 2016-10-12 07:33:26
呵呵。。。
回复 支持 反对

使用道具 举报

Allelujah 发表于 2016-10-12 07:33:29
我们走得太快,灵魂都跟不上了……
回复 支持 反对

使用道具 举报

a2502018869 发表于 2016-10-12 07:38:38
很好很强大。。
回复 支持 反对

使用道具 举报

1107752474 发表于 2016-10-13 04:45:36
打酱油的人拉,回复下赚取积分
回复 支持 反对

使用道具 举报

雲煙、雨巷 发表于 2016-10-13 04:50:58
路过...
回复 支持 反对

使用道具 举报

梁佳伟 发表于 2016-10-18 05:18:44
前排,哇咔咔
回复 支持 反对

使用道具 举报

xiaoqibest 发表于 2016-10-19 15:47:21
大人,此事必有蹊跷!
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表