PrestoとかAnsibleとかその辺の話を軽く書いてみる

今日はPrestoとかAnsibleとかその辺の話を軽く書いてみようと思います。突っ込んだ話が出来るわけではないのであしからず。

僕のところの環境ではPrestoを使っていて、PrestoはDataNodeやNodeManagerと同居してます。主なユースケースアドホッククエリの実行です。とあるレポートを作りたいってなったときにデータの中身をチェックするのに使います。従来だとこれがHiveだったのですが、HiveだとMapReduceになって遅いので(ローカルモードで済む場合もあるけど)、その点Prestoは早くていいです。ただこれは僕の環境がスモールデータだからっていうのもあって、圧縮済み数百GBのデータに対してselectかけるとかだとPrestoといえども遅くなると思います。あとなにげに良いのがPresto CLI経由だとカラム名が表示されるのでどのデータがどのカラムなのかすぐ分かって便利です。カラム数が多くなると見づらくなりますけど。

今のところPrestoは参照専用にしか使ってなくてETL処理には使ってません。ETL処理はHive使ってます。主にinsert系はHive CLIでselect系はHiveServer2使ってますね。HiveServer2だと結果をfetchしたときにカラム単位で取得出来るので自分でsplitする必要が無いのが大きいですね。HiveServer2を使う最大の理由がこれです。僕のユースケースだとHiveからMySQLにselect insertするからこれって大きいんですよね。Hive CLIやHiveServer1だと自分でsplitする必要があります。

アドホッククエリ以外では最近Prestogresを使ってBIツールからHiveのデータを直で参照するようなレポートを作成しました。データ量が少ないこともあってか性能面に問題はありません。これ以外は全部MySQLに集計データをためてそこにBIツールがアクセスするような構成になってます。

以前は集計用RDBMSは必要かなあと思ってたんですけど、集計データを単純にselectするようなケースだったらPrestoでも十分速いので集計用RDBMSは無くてもいいかもって思い始めてます。

さらにPrestoはウィンドウ関数があるのでランキング処理とかも簡単に出来るんですよね。MySQLだとウィンドウ関数無いので同じことをやろうとすると相関サブクエリー使うことになって性能的に厳しい。

集計データにウィンドウ関数使うようなケースってあるの?っていう話でいうとちょっとあったんですよね。
Hiveからselect insertして集計用MySQLに集計データを作って、それに対してMySQLのviewを作っていろんな観点からレポーティングするようなケースです。viewを作るときにウィンドウ関数的なものが必要だったんです。日付ごとの〜ランキングとかね。
最終的には仕様調整してもらってウィンドウ関数的なもの使わなくて済むようにしてもらいましたけど、Prestoだとウィンドウ関数があるのでそれ使ってPresto viewを作ってPrestogres経由でアクセスすれば解決出来るのかなあって思いました。試して無いけど。

今後Presto使う機会が増えると思うので、なんかモニタリングしたほうがいいかなあと思って、/v1/jmx/mbeanをたたいたらJMXの項目が多過ぎて何見ていいかわからん状態です。とりあえずQueryManager, TaskManager, QueryExecution, RequestStatsの中の項目を適当に取得してGrowthforecastに投げてます。
そのpythonスクリプトはこんな感じ。

import requests
 
def post_gf(presto_url, show_attributes, gf_url, service, section):
    r = requests.get(presto_url, timeout=10)
    jc = r.json()
    attributes = jc["attributes"]
    for attribute in attributes:
        if attribute["name"] in show_attributes:
            #print attribute["name"], attribute["value"]
            data = {}
            data["number"] = int(attribute["value"])
            requests.post(gf_url + "/" + service + "/" + section + "/" + attribute["name"], data)
 
gf_url = "http://localhost:5125/api"
service = "service_name"
 
#QueryManager
objectName = "com.facebook.presto.execution:name=QueryManager"
section = "presto-QueryManager"
 
show_attributes = set(["Executor.ActiveCount", "Executor.CompletedTaskCount", "Executor.QueuedTaskCount", "Executor.TaskCount",
"ManagementExecutor.ActiveCount", "ManagementExecutor.CompletedTaskCount", "ManagementExecutor.QueuedTaskCount", "ManagementExecutor.TaskCount",
"AbandonedQueries.TotalCount", "CanceledQueries.TotalCount", "CompletedQueries.TotalCount", "ExecutionTime.AllTime.Count",
"ExternalFailures.TotalCount", "FailedQueries.TotalCount", "InsufficientResourcesFailures.TotalCount", "InternalFailures.TotalCount",
"StartedQueries.TotalCount", "UserErrorFailures.TotalCount"])
presto_url = "http://localhost:8080/v1/jmx/mbean/%s" % (objectName)
 
post_gf(presto_url, show_attributes, gf_url, service, section)
 
#TaskManager
objectName = "com.facebook.presto.execution:name=TaskManager"
section = "presto-TaskManager"
 
show_attributes = set(["InputDataSize.TotalCount", "InputPositions.TotalCount", "OutputDataSize.TotalCount", "OutputPositions.TotalCount",
"TaskManagementExecutor.ActiveCount", "TaskManagementExecutor.CompletedTaskCount", "TaskManagementExecutor.QueuedTaskCount", "TaskManagementExecutor.TaskCount",
"TaskNotificationExecutor.ActiveCount", "TaskNotificationExecutor.CompletedTaskCount", "TaskNotificationExecutor.QueuedTaskCount", "TaskNotificationExecutor.TaskCount"])
 
presto_url = "http://localhost:8080/v1/jmx/mbean/%s" % (objectName)
 
post_gf(presto_url, show_attributes, gf_url, service, section)
 
#QueryExecution
objectName = "com.facebook.presto.execution:name=QueryExecution"
section = "presto-QueryExecution"
 
show_attributes = set(["Executor.ActiveCount", "Executor.CompletedTaskCount", "Executor.QueuedTaskCount", "Executor.TaskCount"])
 
presto_url = "http://localhost:8080/v1/jmx/mbean/%s" % (objectName)
 
post_gf(presto_url, show_attributes, gf_url, service, section)
 
#RequestStats
objectName = "io.airlift.http.server:name=RequestStats"
section = "presto-RequestStats"
 
show_attributes = set(["ReadBytes.AllTime.Count", "TotalCount", "RequestTime.AllTime.Count", "WrittenBytes.AllTime.Count"])
 
presto_url = "http://localhost:8080/v1/jmx/mbean/%s" % (objectName)
 
post_gf(presto_url, show_attributes, gf_url, service, section)

これを見た方がいいよ〜とかあれば教えてくれるとうれしいです。

Prestoはバージョンアップが頻繁なのでその辺の手順をどうしようかなあと思ってて、今まではFabric的な内製のデプロイツール使ってたんですが、イマドキのツール使った方が良いよなってことでAnsible使ってます。

Ansibleは最近本が出ましたね。

入門Ansible

入門Ansible

Hadoopの設定ファイル管理はAmbariに任せているんでPrestoもAmbariに任せられればいいかなあとか思ってたんですが、無理そうだったのでAnsible化しました。まあ身近にすでにPresto用Ansible Playbookがあったのでそれを使えば良いやって思ったのが一番の理由です。

ちなみにCloudera Mangerだと独自にサービス追加出来るみたいですね。Cloudera Managerで手軽にNorikraを試す | nagaseyasuhito Daily works.を見るとNorikraをCloudera Manager管理にしているようです。

軽く触った限りだとAnsibleはChefに比べると学習コストが低くていいですね。Fabricも良いんですけど冪等性欲しいなあってなったらAnsibleかなと。ただFabric的なものが不要になるかというとまだ微妙な気がします。アドホックに実行したいときにもAnsible使うんですかね。特定のtaskのみ実行するのにtag使わなきゃいけないようですし、そういう場合はplaybookは書かないのかな。

あとAnsible Towerは有償ですが、ちょっと気になってます。この手のWebフロントエンドって必要だと思うんですよね。ログが残るのも大きい。

まあ、そんな感じです。