ビッグデータの技術的生態について説明してください。Hadoop、Hive、Spark の関係は何ですか

著者:リトルモンスター
リンク:https://www.zhihu.com/question/27974418/answer/1862026844
出典:Zhihu
著作権は著者に属します。商業的転載の場合は著者に連絡して承認を求め、非商業的転載の場合は出典を明記してください。

1

Hadoop は一連のツールの総称であり、HDFS、Yarn、MapReduce の 3 つの部分で構成されており、その機能は分散ファイル ストレージ、リソース スケジューリング、およびコンピューティングです。

論理的にはこれだけでビッグデータ分析は完了します。

しかし、最初の問題は厄介です。このセットは、Yarn を使用してリソースをスケジュールし、MR 計算のために HDFS ファイルのコンテンツを読み取ることと同等です。Java コードを書きたいのですが、データを処理するのに最適なツールは何ですか? SQL!したがって、Hive は、この一連の標準プロセスの SQL 化に相当します。

Hive は、独自の SQL パーサーとオプティマイザーを Hadoop に追加し、SQL を記述し、それを Java コードに解析して、MR を実行するものとして単純に理解できます。基になるデータは依然として HDFS 上にあります。

これは完璧に見えますが、問題は、プログラマーにとって非常に遅いと感じられることです。その理由は、ファイルの書き込みと読み取りを頻繁に行う必要がある MR です。このとき、MR に代わるメモリベースの Spark が登場し、SQL の有向非巡回グラフを生成でき、各種演算子や広狭依存関係の最適化により、計算速度が新たな高みに到達しました。

これが完全に解決されるのは当然です。

しかし、考えてみましょう。これらのデータはどのようにして得られたのでしょうか? これまで静的なデータを扱ってきましたか? オンライン支払い検証など、リアルタイムで結果を返す必要があるものは、Spark がバッチで計算するまで待つことができません。

問題を解決する前に、データの出所を振り返って考えてみましょう。一般的なデータには、ビジネスデータとログデータの 2 種類があります。

ビジネス データは、データベース内の規則的かつ整然とした構造化データです。ビジネス データはどのようにして Hive に届くのでしょうか? オープンソースは通常、テーブルなどの Sqoop を介してインポートされます。データが少ない場合は、毎日すべてのテーブルをインポートします (完全同期と呼ばれます)。データが特に大きい場合は、毎日の変更と新しい追加のみが同期されます (増分同期)。

ただし、この種の同期は遅れており、クラスターのコンピューティング リソースが比較的アイドル状態である真夜中に行われ、対応するオフライン分析も実行されます。

リアルタイムデータを取得するにはどうすればよいですか?

2

リアルタイムで理解するにはどうすればよいですか?バッチを処理してから、もう少し詳細を取得し、1 つ来て 1 つを処理します。

たとえば、何かを購入すると、プラットフォームのデータベースに追加の注文データが存在し、アプリは行動ログ データを生成します。注文データがデータベースに挿入されると、通常、データの挿入、更新、または削除を記録する binlog が作成されます。この binlog をリアルタイムで取得できる限り、それはリアルタイム データを取得することと同等です

ビンログを取得するにはどうすればよいですか? これは、データベースのマスター/スレーブ バックアップ メカニズムを指します。通常、メイン データベースのバイナリ ログはバックアップ データベースに同期されます。メイン データベースのバイナリ ログを取得し、解析し、パッケージ化し、最後に廃棄するためにバックアップ データベースに見せかけることができる canal と呼ばれるツールがあります。これは、リアルタイムでデータを取得するのと同じです。

運河はビンログを取得した後に直接処理できますか? はい、しかし誰もが考えるべきことが 1 つあります。5 月 1 日が近づいているので、多くの人が一度に注文して消費しますが、運河からのニュースを一度に消費できなかったらどうしますか? たとえば、宅配業者は毎日 1 人の宅配業者だけを送り、お金と商品は受け取り後に受け取ります。ところが、ある日突然、宅配業者があなたの階下に何千個もの荷物を送りました。あなたはそれを一つ一つ運ぶために階下に行き、宅配業者はあなたが荷物の移動を終えるのを待ってから戻らなければなりませんでした。あなたは賢くて、すぐにそれを思いつき、速達キャビネットに入れてください。時間があればゆっくりと動かすことができ、宅配便の時間を費やすことはありません。

これはメッセージ キューであり、Kafka は非同期、分離、ピーク除去などの役割を果たします。Canal データは通常、Kafka または RocketMQ にスローされ、一定期間保存できます。次に、ダウンストリーム プログラムがメッセージをリアルタイムで取得して計算します。

3

ダウンストリームについてはこれだけ述べましたが、ダウンストリームでは誰がこれらのリアルタイム データを消費して計算するのでしょうか? Spark を思い出してください。はい、また登場しました。Spark ストリーミングは、リアルタイム ストリーミング データを処理するための優れたプレーヤーです。

Spark は、コンポーネントのセット全体を表す一般的な用語です。たとえば、Java を使用して Spark タスクを記述し、Spark SQL を使用して SQL を記述し、Spark MLib を使用して機械学習モデルのトレーニングを完了するなどできます。Spark Streaming は、ストリーミング データをマイクロバッチで処理するために使用されます。

具体而言,离线数据我们是等半夜数据都抽到 Hive 中再计算,而 Spark Streaming 则是实时数据来一小批,它就处理一小批。所以本质上讲,Spark Streaming 还是批处理,只不过是每一批数据很少,并且处理很及时,从而达到实时计算的目的。

Spark 本身的流行使得 Spark Streaming 也一直大范围使用。

这一套有什么逻辑缺陷吗?

我们可以想一想,实时数据和离线数据最大的差异,是时效性。离线数据像湖水,该多少就多少,就在那里;实时数据像水流,绵绵不绝。时间,便是非常重要的一个特质。当一条数据来的时候,我们需要知道这条数据是什么时候产生的,这便是业务时间。但我们拿到这条数据时往往是业务时间之后的一小会,这边是处理时间。真正世界里的实时数据肯定不是像 Spark Streaming 那样一批一批来的,而是一个一个的事件。对此,Flink 帮助我们解决了这些问题。

4

无论是业务数据还是日志数据,往往都有相应的时间标志字段,代表着这条消息的业务时间。你可以让 Flink 选择这个时间,这样,Flink 就知道当前处理到哪个时间点了。

Flink 不同于 Spark Streaming 的微批次处理,它是一条一条数据处理的。这样的数据一般是先来后到的,但难免会有些数据沿途受阻晚来了几秒钟,这就会导致两个问题:数据延迟和乱序数据。这也是做实时数据的非常关注的问题。

如何防止数据延迟?如果是上游数据迟了,就加大上游资源;如果是数据突然激增,导致 Flink 处理不过来导致任务出现延迟,就加大 Flink 的资源,比如并发。

数据乱序呢?

同样的,我们一般也通过上游和 Flink 本身来分别保证。

我们上面提到了消息的快递柜 Kafka,Kafka 有分区的概念,就像是不同的通道,一条消息来了后,可以走 A,也可以走 B,也可以走 C。那么问题来了,现在面试官问你,业务数据抛入 Kafka,如何保证消息的顺序性呢?

(5月4日 更)

顺序性一般有两方面需要保证。我们举一个小小的例子,一个用户下单的场景,有两个基本共识:

  1. 同一个用户的订单状态会先后变化;
  2. 不同用户的不同订单也有先后之分。

所以我们解决数据的顺序性一般也是从这两方面考虑。如果你还记得大学高数里的多元函数求偏导,对于 x 和 y 两个变量,求 x 的偏导会假设 y 为常量,反之同理。我们考虑这个问题也一样,如果不能同时兼顾这两方面,那就一个一个去优化吧!这种思想也称为贪婪算法,在很多地方都有应用,这里暂时说到这里。

回到问题,那么如何保证同一用户的订单顺序呢?很简单,前面我们提到的链路是,数据库中插入或更新数据时,会实时产生该条数据的 binlog,canal 获取、解析、包装这条 binlog 并抛入 Kafka。

而 Kafka 由于有分区的存在,很可能同一个订单的消息会被发送到不同的分区中,这样的话,如果下游的 Flink 任务消费不同分区速率不同,就可能导致先到的数据反而被后消费,产生顺序误差。解决的办法即保证同一订单的消息进入 Kafka 的同一分区即可。

Kafka 的每一条消息都会有 messageKey 和 message 两个结构,如果没有直接给消息指定分区,那么 messageKey 决定了消息进入哪个分区,在 canal 中,我们便可以设定消息如何进入 Kafka。数据库中的业务数据,会存在一张张的表中,表一般都会有主键,来唯一标识一条数据,我们一般也就是通过设定 canal 选择 binlog 所在表的主键来决定其进入 Kafka 的分区。这样,就基本解决了第一个问题。

(5月9日 更)

但这只保证了同一订单数据的顺序性,并未保证不同订单之间的顺序性。聪明的你可能已经想到,如果 Kafka 只设定一个分区那不就保证了吗?但这其实算是本末倒置,Kafka 本身相当于快递柜,多个分区相当于多个柜子,能存储更多的数据,提高并发,如果为了顺序性而牺牲并发量,那就得不偿失了,而且一般本身数据的乱序无论是在概率和重要性方面都不如并发重要的。就比如我要统计每小时的订单数,即使数据乱序了,只要在窗口区间内计算结果也不怎么受影响。

但这并不是说我们就不考虑数据在全局的顺序性了。

我们如何去认识乱序或延迟数据呢?

既然这种情况是偶发性的,那么一般可以这么做,在实时的流数据中,如果想要拿到 T 时刻的数据,只要等一小会儿比如 1s,就能保证在 T+1s 的时刻拿到 T 时刻的所有数据。

上面这句话其实理解起来也很简单,比如幼儿园老师组织小朋友们春游,约定了早上 8:00 集合发车,即 8:00 触发一个事件。但总有那么几个调皮捣蛋的学生会迟到几分钟,于是老师说好的 8 点发车实际上是8:05,大家觉得也没啥问题,回家就跟家长说,我们今天 8:00 发车春游啦。

在 Flink 中,这种机制就叫做 watermark。

上面我们说过,每一条数据一般都会自带一个时间字段,来标志这条数据的业务时间,即什么时候发生的。然后 Flink 提取这个时间字段,就知道了目前 Flink 任务进行到几点了。

那么既然要考虑乱序或迟到数据,我们一般也会让 Flink 当前的时间稍微迟几秒钟。比如我们认为大部分情况下乱序或迟到的数据都在 1s 以内,那么来一条数据,比如这条数据自带的时间是 08:00:01,那我们就认为 08:00:00 时刻的数据才刚到齐。但回过头来说,在大多数场景下,毕竟乱序或迟到数据算是占比很小了。

5

是不是看到这里有点抽象了?下一节我们聊聊 SQL 吧

おすすめ

転載: blog.csdn.net/haoweng4800/article/details/128564659