49hack

ゆるふわエンジニアが魔法使いになるまで

nginx.confを8万行削除した話

f:id:paranishian:20181010192436p:plain

強い気持ちでやりました😇

自分が関わる前からあったnginx.conf。

それはそれは大きく膨らんでおりました🐷

デプロイはchefで行っていたんですが、dry-runでも時間がかかりすぎて差分確認するのも一苦労、、という状態😢

少しでも快適な開発環境にすべく、やっていき!💪

TL;DR

大したことはやってなくて、アクセスログと照らし合わせて地道に削除していっただけなのであしからず🙇

削除の方針

nginx.confの中身を見ると、ほとんどがもはや機能しているかわからないリダイレクトのコードだったので、今回はそれらを削除していくことにしました。

今は使っていないURLでもどこかのブログやサイトで昔のURLが残っていることがあります 🤔💦

ただ、そのURLをどこまで面倒見るの?って話で、今回はプロダクトオーナーと相談して、

「直近3ヶ月でアクセス数がxxに満たない場合はSEO的にも価値がないので削除する」

という方針にしました。
(特に意味はないけど一応数字を伏せておいた😇)

アクセスログの保存と解析

サイトへのアクセスはすべてALBを経由してnginxに流れているので、ALBのアクセスログを見ていきます。

という流れでアクセスログデータを取得します。

ALBのアクセスログをS3に格納する

アクセスログのS3への格納作業自体はポチポチするだけで完了します👌
Application Load Balancer のアクセスログ - Elastic Load Balancing

(この作業を3ヶ月以上前にやってたので、現時点ですでにログデータがたまった状態です)

Athenaの連携とデータ取得

Athenaはこのへんのドキュメントとサイトを参考にしました👇

では、さっそくテーブルを作成していきます。

あらかじめパーティション(今回はdtにした)を設定して作成します。

CREATE EXTERNAL TABLE IF NOT EXISTS alb_logs (
    type string,
    time string,
    elb string,
    client_ip string,
    client_port int,
    target_ip string,
    target_port int,
    request_processing_time double,
    target_processing_time double,
    response_processing_time double,
    elb_status_code string,
    target_status_code string,
    received_bytes bigint,
    sent_bytes bigint,
    request_verb string,
    request_url string,
    request_proto string,
    user_agent string,
    ssl_cipher string,
    ssl_protocol string,
    target_group_arn string,
    trace_id string,
    domain_name string,
    chosen_cert_arn string,
    matched_rule_priority string,
    request_creation_time string,
    actions_executed string,
    redirect_url string,
    new_field string
    )
    PARTITIONED BY (dt string)
    ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
    WITH SERDEPROPERTIES (
    'serialization.format' = '1',
    'input.regex' = 
'([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*):([0-9]*) ([^ ]*)[:-]([0-9]*) ([-.0-9]*) ([-.0-9]*) ([-.0-9]*) (|[-0-9]*) (-|[-0-9]*) ([-0-9]*) ([-0-9]*) \"([^ ]*) ([^ ]*) (- |[^ ]*)\" \"([^\"]*)\" ([A-Z0-9-]+) ([A-Za-z0-9.-]*) ([^ ]*) \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\" ([-.0-9]*) ([^ ]*) \"([^\"]*)\"($| \"[^ ]*\")(.*)')
    LOCATION 's3://<your-alb-logs-directory>/AWSLogs/<ACCOUNT-ID>/elasticloadbalancing/<region>';

(locationの<>部分はよしなに変更してください。)

Athenaでは各クエリでスキャンされるデータ量に基づいて課金されるので、対象を絞るためにパーティションつくっておきます。
今回は直近3ヶ月のデータだけで十分だったので手動でパーティションを作りました。
(なのでパーティションの自動化も今回はしていません)

ALTER TABLE alb_logs ADD
  PARTITION (dt='2018-07') LOCATION 's3://<your-alb-logs-directory>/AWSLogs/<ACCOUNT-ID>/elasticloadbalancing/<region>/2018/07'
  PARTITION (dt='2018-08') LOCATION 's3://<your-alb-logs-directory>/AWSLogs/<ACCOUNT-ID>/elasticloadbalancing/<region>/2018/08'
  PARTITION (dt='2018-09') LOCATION 's3://<your-alb-logs-directory>/AWSLogs/<ACCOUNT-ID>/elasticloadbalancing/<region>/2018/09'

パーティションの確認

show partitions alb_logs

リクエストの取得

パーティションを指定してデータ取得します。

SELECT count(*) AS request_count,
         request_url
FROM alb_logs
WHERE dt >= '2018-07'
        AND dt <= '2018-09'
GROUP BY  request_url
ORDER BY  request_count DESC

結果ファイルをcsvでダウンロードすると、以下のようなデータが確認できます。

"request_count","request_url"
"12345","https://sample.com:443/path/to/hoge"
"10000","https://sample.com:443/path/to/fuga"
"8000","http://sample.com:80/path/to/piyo"
...

あとは、grepsedなどのコマンドを駆使してリクエスト数を確認し、nginx.confと照らし合わせて削除していくだけです。(つらそう😇)

例えば、ポート番号が邪魔なのでこんなことをしてパスだけ確認したりとか。

egrep ':\d+\/path\/to\/' results.csv | sed -E "s/http.+:(443|80)\//\//g"

今回はじめてawksedを使いましたが、まだまだ使いこなせてない感😪

気の遠くなるような作業かと思いましたが、意外とトップレベルで削除できるものが多かったのでなんとかなりました。
(たとえば /path/to/hogegrepで引っかからなかったら/path/to/hoge/1/path/to/hoge/2など、配下のURLに関するコードも一気に削除できるよね、みたいな。)

地道な削除作業が完了し、QAを経て無事リリースできました🎉

リリース後は特に障害も起きず、chefでのデプロイもスムーズになったので頑張った甲斐がありました。よかった。

幸せに開発するためには自分で環境を変えて行かなあかんのや!という強い気持ち。

以上です🤗