たごもりすメモ

コードとかその他の話とか。

HiveServerがZooKeeperに繋ぎまくってHiveServer2もろとも死ぬ話

(訂正あり)

HiveServer2で初めて有用になる hive.support.concurrency というプロパティがあって、こいつを有効にするとHiveクエリでテーブルロックがとれるようになる。まあ、でかい変更とかを他に邪魔されずにやりたい時は欲しいかもね。
で、この機能はzookeeperを使うので、オプションを true にするときは hive.zookeeper.quorum を指定しましょう。

が、こいつを有効にしているとき、HiveServer(訂正)およびHiveServer2はzookeeperへの接続をリークさせます。どうなるかというとズバリ zookeeper の maxClientCnxns から溢れて正常に動作しなくなります。
なお HiveServer では hive.support.concurrency は有効にしても意味がありませんが、このコネクションリークは影響を受けます。で、コネクション溢れると普通のクエリも走らなくなります。またzookeeperは接続元のsource IPごとにコネクション数の制御を行うため、同一ホストでHiveServerとHiveServer2が同時に走っている場合、HiveServer2も影響を受けます。死。

原因はたぶんこれ: https://issues.apache.org/jira/browse/HIVE-5853

2014-01-14 18:13:21,492 WARN  zookeeper.ClientCnxn (ClientCnxn.java:run(1069)) - Session 0x0 for server zk2.server.local/192.168.0.2:2181, unexpected error, closing socket connection and attempting reconnect
java.io.IOException: Connection reset by peer
        at sun.nio.ch.FileDispatcher.read0(Native Method)
        at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:21)
        at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:198)
        at sun.nio.ch.IOUtil.read(IOUtil.java:166)
        at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:245)
        at org.apache.zookeeper.ClientCnxnSocketNIO.doIO(ClientCnxnSocketNIO.java:66)
        at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:291)
        at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1047)

こんなエラーがログに出てたらこれだと思いねえ。なおこのときzookeeper側ではこういうログが出てます。

2014-01-14 17:00:00,062 [myid:1] - WARN  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@198] - Too many connections from /192.168.0.1 - max is 50

これは別に lock とかとらなくても、HiveServer へ接続を繰り返すだけで起きます。まじで気をつけましょう。


https://groups.google.com/a/cloudera.org/forum/#!topic/hue-user/DJFiSYwETtk

(訂正)なおCDH4での話です。Hive 0.11 に上げると直るらしいので、みんなでCDH5を涙を飲んで待つのが良いのではないでしょうか。なんてこった。 HiveServer1 はobsoleteだ!と断言されているので、この問題については直らない可能性があります。HiveServer1とHiveServer2を同じホストで動かすのは諦めるのがいちばん早いでしょうか。あとはHiveServer1などさっさと捨てろ! ということですかね。

とはいえ、Thrift API完全に変わるし、そうそうひょいっと移行できないじゃんねえ。

あるいは

hive.support.concurrency に false を設定しましょう。

HiveServer2 でこの設定をしても(たぶん)テーブルロックが取れなくなるだけです。HiveServer1で問題のあった複数のクエリ結果の並行フェッチなどは手元で試したところ普通に動いたので、HiveServer2にする意味はこれだけでも十分あると思います。*1

にしても、なんつーか、CDH4のドキュメントで hive.support.concurrency=true にしろ、と書いてあって、あとHiveServer1といっしょに動かせるよとも書いてあるのに、これClouderaの人は気付いてなかったのかなあ……。

Table Lock Manager (Required)

You must properly configure and enable Hive's Table Lock Manager. This requires installing ZooKeeper and setting up a ZooKeeper ensemble; see ZooKeeper Installation.

Important:
Failure to do this will prevent HiveServer2 from handling concurrent query requests and may result in data corruption.

Enable the lock manager by setting properties in /etc/hive/conf/hive-site.xml as follows (substitute your actual ZooKeeper node names for those in the example):

http://www.cloudera.com/content/cloudera-content/cloudera-docs/CDH4/4.2.0/CDH4-Installation-Guide/cdh4ig_topic_18_5.html

Both HiveServer2 and HiveServer1 can be run concurrently on the same system, sharing the same data sets. This allows you to run HiveServer1 to support, for example, Perl or Python scripts that use the native HiveServer1 Thrift bindings.

http://www.cloudera.com/content/cloudera-content/cloudera-docs/CDH4/4.2.0/CDH4-Installation-Guide/cdh4ig_topic_18_5.html
また余談ですが

HiveServer2 Thrift APIに SessionHandle と OperationHandle というやつがあるのですが、これもリークするバグがあったようです。CDH4.4あたりでこれらのバグが直ってるらしいです。
当初問題がどこにあるのか自分も混乱していましたが、この問題にも複合的に影響してた可能性が高いです。追試する気にはなれないんですけど。

*1:というかテーブルロックなんかべつに要らないし!