You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
9.7 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 39 | 从SQL到Streaming SQL突破静态数据查询的次元
你好,我是蔡元楠。
今天我要与你分享的主题是“从SQL到Streaming SQL突破静态数据查询的次元”。
在前面的章节中我们介绍了一些流数据处理相关的知识和技术比如Apache Spark的流处理模块——Spark Streaming和Structured Streaming以及Apache Beam中的窗口处理。相信你对流处理的重要性和一些基本手段都有所了解了。
流处理之所以重要,是因为现在是个数据爆炸的时代,大部分数据源是每时每刻都在更新的,数据处理系统对时效性的要求都很高。作为当代和未来的数据处理架构师,我们势必要深刻掌握流数据处理的技能。
“批”“流”两手抓,两手都要硬。
你还记得,我在[第15讲](https://time.geekbang.org/column/article/96256)中介绍过的Spark SQL吗它最大的优点就是DataFrame/DataSet是高级API提供类似于SQL的query接口方便熟悉关系型数据库的开发人员使用。
当说到批处理的时候我们第一个想到的工具就是SQL因为基本上每个数据从业者都懂而且它的语法简单易懂方便使用。那么你也能很自然地联想到如果在流处理的世界中也可以用SQL或者相似的语言那真是太棒了。
这样的思想在[第17讲](https://time.geekbang.org/column/article/97121)中我们曾经提到过。
Spark的Structured Streaming就是用支持类SQL的DataFrame API去做流处理的。支持用类似于SQL处理流数据的平台还有很多比如Flink、Storm等但它们是把SQL做成API和其他的处理逻辑结合在一起并没有把它单独分离成一种语言为它定义语法。
那么到底有没有类似SQL语法来对流数据进行查询的语言呢答案是肯定的。我们把这种语言统称为Streaming SQL。Siddhi Streaming SQL和Kafka KSQL就是两个典型的Streaming SQL语言下文的例子我们主要用这两种语言来描述。
不同于SQLStreaming SQL并没有统一的语法规范不同平台提供的Streaming SQL语法都有所不同。而且Streaming SQL作用的数据对象也不是有界的数据表而是无边界的数据流你可以把它设想为一个底部一直在增加新数据的表。
SQL是一个强大的、对有结构数据进行查询的语言它提供几个独立的操作如数据映射SELECT、数据过滤WHERE、数据聚合GROUP BY和数据联结JOIN。将这些基本操作组合起来可以实现很多复杂的查询。
在Streaming SQL中数据映射和数据过滤显然都是必备而且很容易理解的。数据映射就是从流中取出数据的一部分属性并作为一个新的流输出它定义了输出流的格式。数据过滤就是根据数据的某些属性挑选出符合条件的。
让我们来看一个简单的例子吧。假设有一个锅炉温度的数据流BoilerStream它包含的每个数据都有一个ID和一个摄氏温度t我们要拿出所有高于350摄氏度的数据并且把温度转换为华氏度。
```
Select id, t*7/5 + 32 as tF from BoilerStream[t > 350]; //Siddhi Streaming SQL
Select id, t*7/5 + 32 as tF from BoilerStream Where t > 350; //Kafka KSQL
```
你可以看出这两种语言与SQL都极为类似相信你都可以直接看懂它的意思。
Streaming SQL允许我们用类似于SQL的命令形式去处理无边界的流数据它有如下几个优点
* 简单易学使用方便SQL可以说是流传最广泛的数据处理语言对大部分人来说Streaming SQL的学习成本很低。
* 效率高速度快SQL问世这么久它的执行引擎已经被优化过很多次很多SQL的优化准则被直接借鉴到Streaming SQL的执行引擎上。
* 代码简洁,而且涵盖了大部分常用的数据操作。
除了上面提到过的数据映射和数据过滤Streaming SQL的GROUP BY也和SQL中的用法类似。接下来让我们一起了解Streaming SQL的其他重要操作窗口Window、联结Join和模式Pattern
## 窗口
在之前Spark和Beam的流处理章节中我们都学习过窗口的概念。所谓窗口就是把流中的数据按照时间戳划分成一个个有限的集合。在此之上我们可以统计各种聚合属性如平均值等。
在现实世界中,大多数场景下我们只需要关心特定窗口,而不需要研究全局窗口内的所有数据,这是由数据的时效性决定的。
应用最广的窗口类型是以当前时间为结束的滑动窗口比如“最近5小时内的车流量“或“最近50个成交的商品”。
所有的Streaming SQL语法都支持声明窗口让我们看下面的例子
```
Select bid, avg(t) as T From BoilerStream#window.length(10) insert into BoilerStreamMovingAveage; // Siddhi Streaming SQL
Select bid, avg(t) as T From BoilerStream WINDOW HOPPING (SIZE 10, ADVANCE BY 1); // Kafka KSQL
```
这个例子中我们每接收到一个数据就生成最近10个温度的平均值插入到一个新的流中。
在Beam Window中我们介绍过固定窗口和滑动窗口的区别而每种窗口都可以是基于时间或数量的所以就有4种组合
* 滑动时间窗口统计最近时间段T内的所有数据每当经过某个时间段都会被触发一次。
* 固定时间窗口统计最近时间段T内的所有数据每当经过T都会被触发一次
* 滑动长度窗口统计最近N个数据每当接收到一个或多个数据都会被触发一次。
* 固定长度窗口统计最近N个数据每当接收到N个数据都会被触发一次。
再度细化基于时间的窗口都可以选择不同的时间特性例如处理时间和事件时间等。此外还有会话Session窗口等针对其他场景的窗口。
## 联结
当我们要把两个不同流中的数据通过某个属性连接起来时就要用到Join。
由于在任一个时刻流数据都不是完整的第一个流中后面还没到的数据有可能要和第二个流中已经有的数据Join起来再输出。所以对流的Join一般要对至少一个流附加窗口这也和[第20讲](https://time.geekbang.org/column/article/98537)中提到的数据水印类似。
让我们来看一个例子流TempStream里的数据代表传感器测量的每个房间的温度每分钟更新一次流RegulatorStream里的数据代表每个房间空调的开关状态。我们想要得到所有温度高于30度但是空调没打开的的房间从而把它们的空调打开降温
```
from TempStream[temp > 30.0]#window.time(1 min) as T
join RegulatorStream[isOn == false]#window.length(1) as R
on T.roomNo == R.roomNo
select T.roomNo, R.deviceID, 'start' as action
insert into RegulatorActionStream; // Siddhi Streaming SQL
```
在上面的代码中我们首先对TempStream流施加了一个长度为1分钟的时间窗口这是因为温度每分钟会更新一次上一分钟的数据已然失效然后把它和流RegulatorStream中的数据根据房间ID连接起来并且只选出了大于30度的房间和关闭的空调插入新的流RegulatorActionStream中告诉你这些空调需要被打开。
## 模式
通过上面的介绍我们可以看出Streaming SQL的数据模型继承自SQL的关系数据模型唯一的不同就是每个数据都有一个时间戳并且每个数据都是假设在这个特定的时间戳才被接收。
那么我们很自然地就会想研究这些数据的顺序比如事件A是不是发生在事件B之后
这类先后顺序的问题在日常生活中很普遍。比如炒股时我们会计算某只股票有没有在过去20分钟内涨/跌超过20%规划路线时我们会看过去1小时内某段路的车流量有没有在下降。
这里你不难看出,我们其实是在检测某个**模式**有没有在特定的时间段内发生。
股票价格涨20%是一个模式,车流量下降也是一个模式。在流数据处理中,检测模式是一类重要的问题,我们会经常需要通过对最近数据的研究去总结发展的趋势,从而“预测”未来。
在Siddhi Streaming SQL中“->”这个操作符用于声明发生的先后关系。一起来看下面这个简单例子:
```
from every( e1=TempStream ) -> e2=TempStream[ e1.roomNo == roomNo and (e1.temp + 5) <= temp ]
within 10 min
select e1.roomNo, e1.temp as initialTemp, e2.temp as finalTemp
insert into AlertStream;
```
这个query检测的模式是10分钟内房间温度上升超过5度。对于每一个接收到的温度信号把它和之前10分钟内收到的温度信号进行匹配。如果房间号码相同并且温度上升超过5度就插入到输出流。
很多流处理平台同样支持模式匹配比如Apache Flink就有专门的Pattern API我建议你去了解一下。
## 小结
今天我们初步了解了Streaming SQL语言的基本功能。
虽然没有统一的语法规范但是各个Streaming SQL语言都支持相似的操作符如数据映射、数据过滤、联结、窗口和模式等大部分操作符都是继承自SQL只有模式是独有的这是由于流数据天生具有的时间性所导致。
Streaming SQL大大降低了开发人员实现流处理的难度让流处理变得就像写SQL查询语句一样简单。它现在还在高速发展相信未来会变得越来越普遍。
## 思考题
你觉得Streaming SQL的发展前景如何欢迎留言与我一起讨论。
欢迎你把自己的学习体会写在留言区,与我和其他同学一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。