エラー内容
今朝起きたら、 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を受け取れるように変更する。
...
gem 'faraday_middleware'
...
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でない場合、何もせず通過させるので、この変更を入れておけば、仮に挙動がもとに戻っても大丈夫なはずです。
追記 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#L70if Net::HTTP::HAVE_ZLIB env.request_headers['Accept-Encoding'] ||= 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3' end