Ruby
Rails
AWS
Elasticsearch

AWS Elasticsearch Serviceが律儀にgzipを返すようになって死んだ [解決済み]

More than 1 year has passed since last update.


エラー内容

今朝起きたら、 Elasticsearch + Rails にこんなエラーが起こっていた。

MultiJson::ParseError: unexpected character at line 1, column 1 [parse.c:664]

なんと、いままで Accept-Encoding を無視していた AWS Elasticsearch Service が、急に仕事をしだして、 gzip 形式で返すようになった模様。

追記: なお、 elasticsearch-rails で利用されている faraday は、 Accept-Encoding: gzip がデフォなようです。


バージョン

追記しました

elasticsearch (5.0.0)

elasticsearch-api (5.0.0)
elasticsearch-transport (5.0.0)
elasticsearch-dsl (0.1.4)
elasticsearch-model (0.1.9)
elasticsearch-rails (0.1.9)
elasticsearch-transport (5.0.0)
faraday (0.9.2)
faraday_middleware (0.12.2)
faraday_middleware-aws-signers-v4 (0.1.5)

最新版からは若干古いです。


解決法

faraday_middleware gemを使って、gzipを受け取れるように変更する。


Gemfile


...
gem 'faraday_middleware'
...



config/initializers/aws.rb

Elasticsearch::Model.client = Elasticsearch::Client.new(
host: ENV.fetch('ELASTICSEARCH_ENDPOINT'),
port: 80
) do |faraday|
faraday.use FaradayMiddleware::Gzip # ここを追加
faraday.request :aws_signers_v4,
credentials: Aws::Credentials.new(ENV.fetch('AWS_KEY_ID'), ENV.fetch('AWS_ACCESS_KEY')),
service_name: 'es',
region: 'ap-northeast-1'
faraday.adapter Faraday.default_adapter
end



被害者の会

他にも被害者はいる模様。

https://forums.aws.amazon.com/thread.jspa?threadID=223784


Posted on: Sep 26, 2017 10:56 AM

Just my personal experience -

Without any client changes, one day the ES responses stopped working. When I inspected the response, it was gzipped. The client library I was using requested gzip. Since I didn't make any changes to my client code, I am guessing that the following things are true, but none of them are really proven:

a) the client library had always been requesting gzipped responses ( evidence: https://github.com/elastic/elasticsearch-ruby/issues/457#issuecomment-326204925 )

b) the client library was not equipped to receive gzipped responses ( evidence: my code doesn't work )

c) the AWS ES service used to ignore the request for gzipped response, and now it honors it. ( evidence: my code used to work )

I was not able to figure out how to get my client library to stop requesting gzipped responses (seems it would require modifying the faraday library), but by changing my code to look like https://github.com/elastic/elasticsearch-ruby/issues/457#issuecomment-326020618 , I was able to get my client library to understand the gzipped response.

Hope those data points help.


ただ、時系列がずれているので、AWSが順次アップデートをしていったのだろうか?

詳細はAWSにコンタクトする予定。

こちらは、ほぼ同時刻の被害者の方

https://qiita.com/s_nakamura/items/49b19f2544aa61229bbc


コメント


gzip対応してないのにAccept-encodingでgzip投げてた利用者側が悪いのでは?


仰る通りです。。

OSSのライブラリを使っている以上、そのライブラリの挙動の責任は利用者にありますね。この記事のタイトルから「AWSやべー」という声が聞こえてきそうですが、どちらかと言うと、「いままでgzip無視しててごめんね、今朝直しといたから」と言った感じですね。


Amazon Elasticsearchのgzipの件、全ノードでgzipが返ってくるわけじゃなくてあるノードでだけgzip返ってくる罠

挙動が戻ってまたエラーになったら...


レスポンスがgzipでない場合、何もせず通過させるので、この変更を入れておけば、仮に挙動がもとに戻っても大丈夫なはずです。

https://github.com/lostisland/faraday_middleware/blob/master/lib/faraday_middleware/gzip.rb#L25


追記 10/4 11:15 p.m. JST

とここまで書いてて気づいたが、 faraday_middleware によると、 Faraday.default_adapter == :net_http を使うと、Gzipは自動解凍されるよう。。。なんだこれ

  # This middleware is NOT necessary when these adapters are used:

# - net_http on Ruby 1.9+
# - net_http_persistent on Ruby 2.0+
# - em_http


追記 10/5 12:10 a.m. JST

真の原因は、これかな?(未検証)

https://github.com/elastic/elasticsearch-ruby/issues/457#issuecomment-326204925

faraday_middleware-aws-signers-v4 は IAM Role から Elasticsearch Service の認証通す middleware


Can this be the reason why compression is enabled by default ?

https://github.com/winebarrel/faraday_middleware-aws-signers-v4/blob/588b8c1086a72e2762ea3834bfff3d9f71b66024/lib/faraday_middleware/request/aws_signers_v4.rb#L70

if Net::HTTP::HAVE_ZLIB

env.request_headers['Accept-Encoding'] ||= 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3'
end