如何创建一条可靠的实时数据流

原创 2016年05月30日 20:45:13



数据的生命周期一般包含“生成、传输、消费”三个阶段。在有些场景下,我们需要将数据的变化快速地反馈到在线服务中,因此出现了实时数据流的概念。如何衡量数据流是否“可靠”,不同的业务之间关注的指标差别很大。根据对大量业务场景的观察,我们发现对数据流要求最严格的业务场景往往和钱有关


在广告平台业务中,广告的预算和消费数据

  1. 广告主修改广告预算,投放系统首先将新的预算更新到数据库,然后需要将其同步到检索端。检索端将广告的预算和已消费金额作对比,重新决定广告是否有效。如果没有及时更新,会导致广告超预算消费或者没有及时上线,无论哪种情况,损失都将由广告平台承担。
  2. 广告的消费数据一般在广告发生特定事件的时候产生(展现,点击,转化等)。当产生消费数据时,需要将其同步到检索端,检索端更新广告的已消费金额,并和广告的预算做对比,重新决定广告是否有效。如果没有及时更新,会导致广告超预算消费,损失将由广告平台承担。

在电商业务中,商品的库存和价格当商品库存变少时,如果没有及时同步到服务端,会使用户在结算时才发现商品已无货,伤害用户体验,甚至导致用户流失。一个极端的业务场景是秒杀。同样,如果商品的价格变高时没有及时同步到服务端,会导致用户在付款的时候发现价格变高,伤害用户体验,甚至导致用户流失。另外,如果库存增加或者价格降低时,没有及时同步到服务端,会流失可能带来的交易,带来的损失也只能是电商平台承担。


在电商业务中,用户的消费数据有些电商业务中允许用户预充值,用户的账户可能会有余额。如果用户产生了消费,但订单和余额并没有及时更新,可想而知会导致用户产生很大的疑惑。


因此,本文重点讨论一下这些业务场景下对实时数据流的要求。相信在这些场景下都可以认为是可靠的实时数据流,可以很容易适应其他业务。在这些场景下的实时数据流中,往往最关心三个指标:可用性,准确性,实时性。


  • 可用性

最基本的要求,可靠的实时数据流必须要高可用的。


  • 准确性

准确性表示数据流的消费端接收的数据,和数据流发送端发送的数据保持严格一致。也就是常说的“不重不漏”。在有些场景下,如果消费端的操作满足“幂等性”,那么对“不重”的要求可以放宽。但是对“不漏”的要求往往一般是不能妥协的。


  • 实时性

实时性表示数据的传输要满足低延时。延时一般定义为,一条数据从被发送端发送到被消费端接收之间的时间。不同的场景对实时性的要求不同,一般分为秒级和分钟级。




为了方便讨论,我们以一个最简单的实时数据流系统为例,其包含三个模块:生产者,传输模块,消费者。复杂的实时数据流系统可以认为是这三个模块的多次组合。一般来说,我们会使用 Message Queue 作为数据的传输模块,因此在下文中使用MQ来代替传输模块。接下来我们从三个方面讨论如何保证实时数据流的可靠。


  • 可用性

成熟的 MQ 系统(例如kafka)都用保障高可用性的方案。生产者和消费者我们一般是使用集群来提高可用性。


在生产者端,对可用性的定义包含两重含义:

  1. 数据总是能被生成的。
  2. 数据总是能被发送到 MQ 的。

具体分两种情况。一种情况是数据量非常大,但是能容忍在极端情况,有很小一部分的丢失(例如广告的消费数据)。另一种情况是数据量不是特别大,但对准确性要求非常高,数据是严格不能丢失的(例如用户充值数据)。两种情况的处理方案有所不同。


第一种情况,在消息生成的时候,生产者一般都会先落地到本地磁盘,再由一个单独的程序从磁盘读取数据并发送到 MQ。这样有几个好处:

  1. 当生产者发生宕机的时候,并不影响数据的继续发送。生产者重启或者迁移到备用机器后,数据可以继续生成并发送。
  2. 避免因为网络抖动或者 MQ 性能出现问题时,影响生产者的对外服务质量。一般来说,数据是生产者在对外提供服务的过程中产生的。如果由生产者直接将数据写入 MQ,为了保证数据和对外响应结果的一致性,不能使用异步写的方式,需要同步写。因此在出现网络抖动或者 MQ 写延迟过长的时候,会导致生产者无法对外提供服务。
  3. 降低生产者代码复杂性。
  4. 这个将磁盘数据发送到 MQ 的程序一般仅仅是调用 MQ 的library,可以非常简单,减少了出错导致崩溃的可能性,其开源方案是 Flume。实战中,Flume + Kafka 已经有非常成熟的方案,而且非常稳定。

第二种情况,生产者一般是将数据直接写入一个可靠的存储系统中(例如数据库),再由一个单独的程序将数据从存储系统中读出并写入到 MQ。


同样,在消费者端,也是先使用 Flume 将数据落地到本地磁盘。如果消费者发生了宕机,也并不影响 Flume 继续从 MQ 读取数据。在消费者重启或者迁移到备用机器以后,可以继续之前的工作。


这样,生产者和消费者都可以认为是在使用磁盘作为介质和 MQ 在通信,而不是网络,而磁盘的可靠性往往比网络更高。另一方面,生产者和消费者可以更专注于其本职工作,使用 Flume -> Kafka -> Flume 的开源方案,也避免重复开发。


虽然 Flume 在使用过程中非常稳定,但如果是对可用性要求非常高的系统,我们仍然要考虑在 Flume 程序崩溃甚至磁盘损坏时的恢复方案。尤其在磁盘发生损坏时,我们往往无法准确定位生产者哪些已经生产的数据没有被发送到 MQ。一个典型的方案是重做,即将我们无法确定是否已经发送到 MQ 的数据全部重发一次。因此,在消费者端,保证操作的幂等性是非常重要的。


  • 准确性

准确性可以简单表述为“不重不漏”。“不重”的保证比较困难,在上文已经讨论,在数据流发生异常的某些情况下,我们是无法或者相当麻烦才能定位哪些数据已经发送到 MQ 中,因此需要批量重做,这就会导致 MQ 中有重复的数据。因此,一般的方案往往都是将消费者设计成操作幂等性的,这样就能够容忍数据重复的情况。


“不漏”在设计到财务的系统中往往不能妥协,可以延迟,但不能遗漏。

基于防御性编程的思想,我们做好任何上下游交互的模块都可能出错的准备,并提供更高层次的协议保证业务的正确性。例如,在向 MQ 写入数据时,我们要假定及时 MQ API 返回成功状态,数据在 MQ 中仍然是可能被丢失的,message id 机制也不是100%可靠的。那么,我们如何验证生产者发送的数据,经过 MQ 之后一定能够到达消费者?我们需要在生产者和消费者之间建立新的协议。


协议的第一步是为每条数据做一个唯一的标示,即 GUID。更进一步,我们希望 GUID 能够可读,并且能表示数据的先后顺序。为了满足这个需求,我们需要一个高可用的能够产生严格递增的 ID 的服务。这是另一个很大的话题,在这里不展开。有了这个服务,在生产者发送数据前,先向这个服务请求一个 ID,附加到一条数据上,然后再传输。


在消费者端,有两个方案进行验证。一个方案是生产者要保证发送到数据 ID 是严格递增的消费者验证前后两条数据的 ID 是否连续。如果不连续,即认为是数据有丢失,停止继续消费,通知生产者进行到错误恢复流程。待生产者恢复后,通知消费者继续消费。


另一个方案生产者在发送数据时,除了给每条数据附加上自己的 ID,还要附加上其前一条数据的 ID。这样消费者通过两个 ID 可以验证数据是否有丢失。这个方案的好处是,不需要生产者保证数据的 ID 是连续的。

在实战中,生产者往往将数据写入到一个 Topic 的多个 Partition,每个消费者只消费指定 Partition 的数据,因此同一个 Partition 内的数据 ID 往往是不连续的。因此,这种方案更多的被采纳。


  • 实时性

实时性对系统带来的影响往往弱于准确性。从文章开头的案例讨论可以看出,实时性不好往往也导致业务上的经济损失,尤其在一些流水很大的系统中,可能导致非常可观的经济损失。


为了提高实时性,我们一般通过几个手段:

  • 减少网络通信

  • 上下游服务尽量同机房甚至同机架部署

  • 如果一定出现跨机房(尤其是异地机房)的通信,在机房间使用专线

尽可能少地拆分服务是最有效的方法。这需要在系统的扩展性、伸缩性和成本之间做好权衡,根据业务需要设计方案,避免过度优化。


实时性的另一个问题是我们如何监控数据的延迟,并在延迟过高的能及时发现并处理。一个常见的方案是使用“哨兵数据”。生产者定期(例如每5分钟)向 MQ 写入一条固定格式的数据,这条数据必须包含的字段是数据生成的时间,这条数据成为哨兵数据。消费者需要监控,是否在经过一个指定的时间间隔能接收到“哨兵数据”。如果接收不到,说明生产者或者 MQ 出现了问题。如果接收到了,将数据的生成时间和接收时间做对比,如果时间间隔超出阈值,说明延迟过大。无论哪种情况,都应该触发报警,甚至有些依赖于数据流实时性的服务都要同时停止服务。




对绝大多数实时数据流系统来说,可用性、准确性、实时性,三个指标考虑的是优先级依次降低,实现的代价也是依次增长。在不同的业务场景中,对“可靠”的定义也有所不同。可能有些系统数据丢失1%对业务的影响不大,如果要保证100%准确带来的成本会大幅增加;也可能有些系统分钟级实时和秒级实时对业务的影响不大,但如果从分钟级提高到秒级成本会大幅增加。因此,在架构设计中,一定要结合具体业务场景,综合考虑和权衡服务质量、用户体验、系统成本等多方面因素。

版权声明:本文为博主原创文章,未经博主允许不得转载。

流式传输的实现途径

首先,多媒体数据必须进行预处理才能适合流式传输,这是因为目前的网络带宽对多媒体巨大的数据流量来说还显得远远不够。预处理主要包括两方面:一是降低质量;二是采用先进高效的压缩算法。    其次,流式...

中国移动SDTP协议中鉴权请求的加密算法

SDTP鉴权请求使用于鉴别源用户的一个消息。它使用加密算法(MD5和SHA256哈希)计算鉴权信息生成摘要(Digest)放在鉴权请求消息中传输。 在移动的大部分接口规范中都会使用到SDTP协议,但...

微服务——简单应用钱包服务的设计

写在前面: 现在基本上每个APP或者其他网页都会加入用户钱包这一功能,钱包是 一个常见的产品需求,那么本博阐述非金融的钱包或者称为简单钱包的 设计思路和具体实现。 设计目标: 业务目标: 1....

2017年的双十一又一次刷新了记录,交易创建峰值32.5万笔/秒、支付峰值25.6万笔/秒。而这样的交易和支付等记录,都会形成实时订单Feed数据流,汇入数据运营平台的主动服务系统中去。数据运营平台的

2017年的双十一又一次刷新了记录,交易创建峰值32.5万笔/秒、支付峰值25.6万笔/秒。而这样的交易和支付等记录,都会形成实时订单Feed数据流,汇入数据运营平台的主动服务系统中去。数据运营平台的...

如何选择可靠的实时操作系统

转发一篇关于 RTOS 的可靠性和认证问题的文章。大型的 RTOS 比较重视这个问题,比如 VxWorks、 Greenhill , 而小型的 RTOS 讨论的比较少,随着汽车、医疗电子等关键应用越来...

iOS使用ffmpeg播放rstp实时监控视频数据流

一、编译针对iOS平台的ffmpeg库(kxmovie) 近期有一个项目,需要播放各种格式的音频、视频以及网络摄像头实时监控的视频流数据,经过多种折腾之后,最后选择了kxmovie,kxmovi...

IGS实时数据流列表

  • 2016年03月01日 14:52
  • 191KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:如何创建一条可靠的实时数据流
举报原因:
原因补充:

(最多只允许输入30个字)