从数据的角度审视物联网
第一步:数据源数据采集
数据源数据采集,就是通过各种物联网设备,实现各种数据数字化的任务,同时也可能需要将数据临时存储起来,准备好数据的上传工作。
因为数据类型多种多样,比如我们常说的温度、湿度、甲醛含量,另外还有图像、声音、震动等等,所以采集这些数据的设备也具有明显的多样性。
除了传统的嵌入式系统涉及的软件和硬件开发外,传感器是这一部分需要重点关注的关键元器件。随着物联网的发展,新的应用在不断涌现,比如监测人体心率和血氧饱和度的可穿戴设备,以及在智慧农业中用来测量土壤反射率和植物颜色的光学传感器等等。
采集完数据后,你就要利用网络将数据传输到云服务器。
第二步:数据传输
数据传输,就是把采集的数据快速地、可靠地上报到云平台。这里的技术难点是实现高并发。因为物联网设备的数量巨大,而且它们在时刻不断地产生数据,所以海量的数据对云平台的性能构成了挑战。云平台只有具备高并发的能力,才能有效地、可靠地实现数据的传输。高并发的实现,需要借助分布式的架构设计,同时使用负载均衡、消息队列和缓存等相关技术。
第三步:数据存储
数据传输完成之后,你要面对问题是海量数据的存储。
比如,一辆共享单车一天会产生 1MB 的数据,如果按照 2000 万辆的保有量计算,每天就会产生 20TB 的新增数据。而在智慧城市的系统中,一个 800 万像素的摄像头,一个小时就能产生 3.6GB 的数据。那么一座城市,光是摄像头,一个月的数据量就可以达到数百 PB。
除了数据量大,数据的种类也很丰富,它们大体上可以分为 3 类,分别需要有不同的存储手段:
- 结构化数据(Structured data)
- 半结构化数据(Semi-structured data)
- 非结构化数据(Unstructured data)
结构化数据(Structured data)
比如用户和设备的关系,用户信息、设备参数等。这类数据还是适合关系型数据库,基于关系型数据库,我们可以很容易地实现数据的“增删改查”,而且可以方便地实现事务操作,保证数据操作满足 ACID 特性(也就是原子性 Atomic,一致性 Consistency,隔离性 Isolation 和持久性 Durability)。
为了应对大数据对计算和读写性能的挑战,数据库系统需要借助分布式架构的威力(横向扩展),你可以采用分布式数据库。
分布式关系型数据库
行业内一开始的实践是对数据库进行分库分表,然后借助数据库中间件实现关联查询、主键避免重复、分页查询和事务一致性等功能。但是这种方式有很多弊端,比如分库分表需要根据业务数据的特点仔细设计,而且这种分库分表操作一定会涉及非常麻烦的数据迁移工作;通过中间件执行 SQL 的效率不高;事务一致性很难保证,往往需要在应用中实现“最终的一致性”。
为了解决这些问题,分布式关系型数据库出现了。它也经常被称为 NewSQL 数据库。它的优势主要体现以下 3 个方面。
- 高扩展性。NewSQL 天生支持数据分片,支持动态增加节点,不需要进行麻烦的数据迁移工作,所以能够轻松地满足数据不断增大时的存储需求。
- 高并发性。相比于单机关系型数据库基于磁盘的设计,NewSQL 在设计上更好地利用了内存,所以 SQL 执行效率很高。在事务的支持上,NewSQL 有着高效的分布式事务特性。所以它可以实现海量数据的读取和写入,以及大量用户的查询和更新等操作。
- 高可用性。NewSQL 采用 Paxos 或者 Raft 协议来实现多副本的存储,而且还支持自动选择主节点,保证了数据库的故障切换时间很短。
所以,对于需要强一致性事务的场景(比如共享单车物联网系统中的支付交易),以及需要基于关系模型进行复杂查询的场景(比如共享单车中涉及用户信息表、单车信息表和骑行记录表的丢失单车查询),当单机关系型数据库已经无法满足大数据需求时,可以考虑分布式关系型数据库。尤其是当之前的业务已经基于关系型数据库开发完成,并且在实际服务环境中运行的时候,分布式关系型数据库简直是业务开发人员的福音。因为这种情况下想改用其他类型的数据库,如果数据库不支持 SQL 语言,业务代码就需要进行大量的修改和调整。
在实践中,分布式数据库的开源选择有 TiDB、CockroachDB 等,也有商业化的产品,比如阿里巴巴的 OceanBase 等。
另外,物联网中的传感器设备,随时间不断产生新数据。要存储这类数据,你可以选择时序数据库,来获得更高的读写和查询性能。
时序数据库
分布式关系型数据库这个方案,是从增加能力的角度得到的。那么,我们能不能从简化问题的角度出发,找到其他解决方案呢?
物联网中传感器的应用系统就是这样的场景,比如监控冷库中温度和湿度条件的传感器。这些传感器会按照一定的周期不断地上报数据(比如每 1 分钟上报 1 次)。这样的数据按照时间顺序排列,形成了一系列的数据点,所以被称为时间序列数据(Time Series Data),简称时序数据。
时序数据在读写、存储和分析处理方面有下面这些特点:
- 时序数据是持续地写入,一般是采用固定的频率,没有写入量忽大忽小的明显变化。数量非常大,而且并发写入的需求也很高。但是数据很少做更新,旧数据除了特殊情况下的修改,基本是不需要更新的写入操作。
- 时序数据的读取很少,相比写入的高并发和高频率,读取的需求主要是进行数据分析的应用,而分析应用的并发访问量是比较少的。
- 时序数据时效性很强,一般是越新的数据价值就越大,旧数据会迅速失去价值。
- 时序数据的数据分析主要关心的是新数据,旧数据被查询和分析的概率不高。旧数据一般是粗颗粒度的读取分析。而且在被分析时,一般是基于时间范围读取分析,读取某一条记录的几率很小。
基于时序数据结构和应用上的特点,人们开发出了时序数据库,它在近些年随着物联网的应用变得非常流行。时序数据库简化了关系型数据库很多不必要的功能,比如采用读取性能不高的 LSM 树代替 B+ 树的存储结构。它专注于支持高并发的数据写入,采用更高压缩比的压缩算法来支持海量数据的存储,降低存储的成本,同时,通过预处理等方法来支持海量数据的高效分组聚合计算。
序数据库的具体产品有哪些呢?
首先是开源软件,你可以选择 InfluxDB,KairosDB 和 OpenTSDB 等产品。
另外,云服务企业一般都开发了自己的时序数据库,比如阿里巴巴的 TSDB 和亚马逊的 AWS Timestream 等。其中,TSDB 还扩展支持了空间信息,以便处理地理围栏和空间轨迹等需求。
半结构化数据(Semi-structured data)
比如 JSON 结构的数据,日志记录等。这些数据的存储一般采用 NoSQL 数据库产品。
半结构化数据包含相关标记,用来分隔语义元素,以及对记录和字段进行分层。比如,JSON 格式的数据JSON 中大括号“{}”,中括号”[]”,冒号”:”,逗号”,”就是分隔语义元素,每个冒号前面的内容是字段,后面的是记录。
半结构化数据的特点是,它的结构并不固定,属于同一类实体可以有不同的属性,这表明它有很好的可扩展性。另外,即使它们被组合在一起,这些属性的顺序并不重要。这些特点决定了我们很难按照关系型数据库的数据模型来建立半结构数据的结构和相互之间的关联。除了 JSON,常见的半结构数据还有 XML 等。在应用系统中呢,日志文件就是典型的半结构化数据。
为了更有效地存储半结构化数据,我们可以选择 NoSQL 数据库。它以键值对存储,且结构不固定,每一个元组可以有不一样的字段。每个元组可以根据需要增加一些自己的键值对,这样数据库就不会局限于固定的结构,可以减少一些时间和空间的开销。
其实,我们知道 SQL 只是一种操作数据库数据的接口,所以 NoSQL 中的“No”真正表达的意思是 No Relational,专业的叫法应该是非关系型数据库。
非关系型数据库由于不再强调数据的一致性,不支持事务操作,也不再关注复杂的关联表查询,所以它对海量数据的处理性能更好,而且存储的数据格式比较丰富,易于扩展。有些非关系型数据库会使用内存来存储数据,以便支持更快的查询速度。
非关系型数据库也有很多的开源产品,比如 CouchDB、Redis、HBase、Cassandra 等,你可以根据熟悉程度和生态支持选择。商业化的选择也有 MongoDB 和 Oracle NoSQL 等产品。
非结构化数据(Unstructured data)
非结构化数据没有预定义的数据模型,无法简单地用数据库二维表结构来表现。它的格式非常多样,标准也不是统一的。对于这一类数据的大规模存储,我们只能使用分布式文件系统。
比如视频、音频等数据。它们一般采用文件的形式存储,Hadoop 体系中应用广泛的分布式文件系统 HDFS 是常用的选项。其他的分布式文件系统还有 FastDFS 和 Ceph 等。
只有当实现了海量数据的存储,我们也才能为数据的处理打好基础。
数据迁移工具
数据的迁移工作比较麻烦,需要在设计阶段就尽量避免。但是,有些数据迁移的需求可能是你避免不了的。比如你要把已运行系统中 MySQL 数据库里的数据,导入到 NoSQL 数据库 HBase 中,以便使用大数据技术进行分析处理。
对于这样的需求,我们就得借助工具来完成,比较有名的工具就是 Sqoop 项目。它在 Hadoop 大数据存储系统和关系型数据库等系统之间架起了桥梁,借助 Sqoop,你就可以很方便地把 MySQL 数据导入到 HBase 中。另外,Sqoop 采用了被称为 Connector 的插件架构,不同的 Connector 还可以对接不同的数据源,而且你也可以根据自己的需求定制专属的 Connector 来完成一些特殊的迁移工作。所以,Sqoop 也可以完成 NoSQL 数据库(比如 CouchDB)和文件存储系统(比如 FTP)之间的迁移任务。
当然,Sqoop 也有一个缺点,那就是不太适合增量的数据更新,又叫 CDC(Change Data Capture)。如果基于 Sqoop 采用定时扫描整张表的方法,那么执行会比较低效,延时也比较严重。这时,你可以考虑 LinkedIn 开源的 Databus 项目,或者阿里巴巴的 Canal,它们都是基于分析数据库日志文件来高效地实现数据的增量更新。
第四步:数据处理
数据处理阶段,非常考验你对海量数据的处理能力,你需要用到大数据计算引擎。大数据的处理,从应用场景划分的话,可以分成两个大类:
- 批处理,顾名思义,它是对批量的数据进行统一处理的方法。批处理适合海量静态数据的非实时处理,延迟比较高,也叫离线计算,主要用于离线报表、历史数据汇总等场景。比如我们需要知道一个月里,共享单车的总骑行时长和距离,骑行距离最远的单车等信息,就需要对所有单车的数据做汇总的计算,得出想要的结果。批处理的计算过程可能耗时较长,几分钟、几个小时,甚至几天都有可能。
- 流处理,它是对数据流做及时的处理计算。相比批处理,它具有低延时的特点,一般可以达到毫秒甚至微秒的级别。这样可以满足海量数据对于大吞吐量的处理能力的需求。主要用于实时监控、趋势预测、实时推荐等场景。比如温度、湿度数据基于高、低阈值的实时判断,就需要采用流处理的方式。
批处理之经典思路:MapReduce 的分而治之
首先,谷歌(Google)基于公司内部的实践,在 2004 年发表了分布式计算框架的论文。这篇论文提出了 MapReduce 计算框架的设计思想,主要用于解决海量网页的索引生成问题。接着,开源搜索引擎项目 Nutch 的开发人员,基于这个设计思想开发出了开源的 Hadoop MapReduce 实现。
具体来说,就是把数据分成相同大小的多份,然后相应地创建多个任务,并行地处理这些数据分片,这个的过程被定义为 Map 过程;接着,再将 Map 过程中生成的计算结果进行最终的汇总,生成输出结果,这个过程被定义为 Reduce 过程。这两个过程合起来就是 MapReduce 了。
批处理之高效率开源框架:以“快如闪电”为目标的 Spark
Spark 是如何打造高效率框架的呢?
首先,在计算模型上,Spark 抛弃了 MapReduce 的两个过程模型,采用了 DAG(Directed Acyclic Graph,有向无环图)模型。采用 DAG 来描述数据处理的过程,应该说是反映了数据处理过程的本质。这样一方面开发人员可以更容易地描述复杂的计算逻辑,另一方面计算框架也能更方便地自动优化整个数据流,比如避免重复计算。
其次,Spark 的数据存取充分地利用了内存。
它的数据分片被称为 Partition。然后它基于 Partition,提出了 RDD(Resilient Distributed Datasets,弹性分布式数据集)的概念。所谓的“弹性”就是指,数据既可以存储在磁盘中,也可以存储在内存中,而且可以根据内存的使用情况动态调整存储位置。这就提高了计算的效率。
流处理开源框架:Storm、Spark Streaming 和 Flink
这其中最早的代表就是社交网络公司 Twitter 开发的 Storm 框架。Storm 的一个重要概念就是数据流(Stream)。相对于批处理针对数据块的处理方式,所谓的流处理,就是针对数据流的处理方式。Storm 把 Stream 描述成是元组(Tuple)构成的一个无限的序列。Stream 从水龙头(Spout)中产生,也就是说,Spout 把需要处理的数据转换为由 Tuple 构成的 Stream。然后 Stream 经过转接头(Bolt)的处理,输出新的 Stream。其中,Bolt 的处理可以是过滤、函数操作、Join 等任何操作。你可以参见下面的流程图示例:
图片中的 Spout、Bolt 和 Stream 共同构成了 Storm 中另一个重要概念,拓扑(Topology)。你应该可以看出来 Topology 是一个 DAG(有向无环图)。Storm 框架中运行的正是一个个 Topology,而且因为是流处理,它会一直运行直到被手动终止。
基本上和 Storm 同时出现的流处理开源框架是 Spark Streaming。Spark Streaming 正是将数据流转换成一小段一小段的 RDD。这些小段的 RDD 构成一个流式的 RDD 序列,称为 DStream,所以它的流处理被称为“微批处理”。
显然,它的实时性取决于每小段 RDD 的大小,实时性不如 Storm 框架;不过,这种方式也使它的吞吐能力要大于 Storm。整体来看,你可以认为 Spark(包括 Spark Streaming)基于数据块的数据模型,同时提供了批处理和流处理的能力。
Flink 将数据块作为一种特殊的数据流,通过从文件等持久存储系统中按照 Stream(流)的方式读入和处理,来提供批处理的能力。在这个基础之上,Flink 提供了统一的批处理和流处理框架,也就是所谓的“流批一体”的数据处理框架。
Flink 虽然出现的时间不长,但凭借着优秀的设计,性能非常强,延迟可以低到微秒级别,是对实时计算性能要求的高的场景的理想选择。行业内,阿里云和腾讯云对于 Flink 的支持都非常好;很多企业也在实践中逐渐尝试使用 Flink 来替代 Storm 框架。
第五步:数据应用
数据应用处于整个体系的最顶端,是物联网系统的最终目的。我们关注的核心点是通过数据创造价值,而实现的基础是各种算法。
数据如何产生价值呢?
数据产生价值的方法,概况来说,可以分为 4 种:
- 可视化
- 挖掘
- 预测
- 控制决策
最直接的方法是可视化,也可以称为图表分析。可视化可以非常直观地向人们展示数据的含义。比如共享单车的地理位置,如果给用户一个经纬度坐标,那无异于没有给这个信息;而在地图上以光标的方式显示出来,那用户就可以马上知道这个单车相对于自己的方位和距离。类似的还有以曲线、柱状图表示数据变化趋势,以饼状图表示百分比数据,用网络图表示的事物关系等等。它们都可以为原始数据,和分析结果数据提供理想的展示手段。
比图表分析更进一步的方法是挖掘分析。我们可以基于各类算法来分析数据的规律和关联关系等。这种方法基于各种现成的模型,或者自定义的模型,可以从数据中提取出人工分析无法看出来的、隐藏着的规律和联系。
还有一种进阶的方法是预测分析。随着积累的数据和经验越来越多,我们可以用算法来构建预测模型。当新收集的数据输入给模型时,我们就可以预测出未来的状况。
最后一种方法是控制决策。物联网设备可能具备执行器,物联网系统可以基于业务目标控制这些执行器。而控制决策是采集的数据基于算法计算得到的。
数据分析可以使用的算法有哪些?
挖掘分析、预测分析和控制决策要用到统计分析、机器学习,包括人工智能的各种算法。这些算法分为监督学习和非监督学习两类。
- 督学习算法需要我们像尽心尽责的父母,明确告诉它“什么是正确的”,“什么是错误的”。
- 非监督学习算法面对的是“放羊式”父母,需要自己将数据中的“异常值”区分出来。
常见的监督学习算法有决策树和 SVM(支持向量机)算法等。决策树类似我上面描述的专家系统;SVM 算法是一种分类算法,也可以用于线性和非线性回归问题,比如基于骑行习惯构建用户的画像。
非监督学习算法有 K-means 算法等。K-means 算法是聚类算法,比如,基于共享单车的使用次数和时间段,我们可以区分出故障车和正常单车。
总之,使用算法的一个原则是,你先要分析数据的特征,掌握大体的倾向,然后结合你要实现的目标,再选择合适的算法。