コピペコードで快適生活

明日使えるソースを自分のために

シェルスクリプトのアタマに添えるおまじない

シェルスクリプトを書くときに、アタマに添えるおまじないをメモ。

#!/bin/sh

# set -e
# スクリプトの実行中にエラー(exit 0以外)が発生すると、そこでスクリプトが終了させる。
# というかつけてないと、エラーしても次の処理に進むから怖い。
# 
# set -u
# 未定義の変数を使用すると、そこでスクリプトが終了させる。
# 
# set -o pipefail
# パイプの途中でエラーが起きた場合もエラーが発生させる。
set -euo pipefail

# どのパスから実行しても、スクリプトのあるディレクトリにcdしてから実行する。
cd `dirname $0`

# 以下、メイン処理を書く

参考

proxy先がTCPコネクションを切ったときブラウザには何が返るか

ブラウザ → proxy(nginx) → origin(apache) の通信経路で、originがTCPコネクションを切った場合、proxyは50xを返す。proxy(nginx)にはこんなログが出る。

proxy_1  | 2021/07/01 13:15:38 [error] 25#25: *2 upstream prematurely closed connection while reading response header from upstream, client: 172.20.0.1, server: localhost, request: "GET /php/ HTTP/1.1", upstream: "http://172.20.0.2:80/", host: "localhost"
proxy_1  | time:01/Jul/2021:13:15:38 +0000  remote_addr:172.20.0.1  host:localhost  scheme:http req:GET /php/ HTTP/1.1  status:502  size:494    response_time:5.655referer:-    agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36 upstream_addr:172.20.0.2:80 upstream_cache_status:- upstream_response_time:5.656

ブラウザで、ERR_CONNECTION_CLOSEDが出る場合は、ブラウザとproxy間の通信が切れたもの。

MySQLのバッファプール使用状況を確認する

ダーティページの使用状況を確認したかったので。

mysql> SHOW GLOBAL STATUS LIKE 'InnoDB\_buffer\_pool%';
+-----------------------------------+---------------+
| Variable_name                     | Value         |
+-----------------------------------+---------------+
| Innodb_buffer_pool_pages_data     | 464754        |  # バッファプール内のデータ合計
| Innodb_buffer_pool_pages_dirty    | 0             |  # ダーティページ
| Innodb_buffer_pool_pages_flushed  | 51792309      |  # ディスクフラッシュしたページ数
| Innodb_buffer_pool_pages_free     | 0             |  # バッファプールの空き
| Innodb_buffer_pool_pages_misc     | 59534         |
| Innodb_buffer_pool_pages_total    | 524288        |  # バッファプール内のページ数
| Innodb_buffer_pool_read_ahead_rnd | 82900402      |
| Innodb_buffer_pool_read_ahead_seq | 41051358      |
| Innodb_buffer_pool_read_requests  | 2642185748634 |  # バッファプールから読んだページ数
| Innodb_buffer_pool_reads          | 1272273714    |  # ディスクからバッファプールにロードしたページ数
| Innodb_buffer_pool_wait_free      | 0             |
| Innodb_buffer_pool_write_requests | 320720943     |  # バッファプールに書いたページ数
+-----------------------------------+---------------+
12 rows in set (0.00 sec)

mysql> SHOW GLOBAL STATUS LIKE 'Innodb\_pages%';
+----------------------+------------+
| Variable_name        | Value      |
+----------------------+------------+
| Innodb_pages_created | 1073458    |  # バッファプールに作成したページ数
| Innodb_pages_read    | 6795625969 |
| Innodb_pages_written | 51793282   |  # ディスクフラッシュしたページ数
+----------------------+------------+
3 rows in set (0.00 sec)

参考

nginxのproxy設定メモ

/etc/nginx/nginx.conf

# 略
http {
    # 略

    # proxy_cache_path: キャッシュファイルの本体
    #   keys_zone: 1mは共有メモリのサイズ。1MiBあたり約8000個のキーを保持できる
    #   max_size: 全キャッシュファイルのサイズ合計の上限
    #   inactive: 指定した期間内にアクセスされなかったキャッシュファイルは、その有効期間に関わらず削除される(デフォルトで10分)
    # proxy_temp_path: オリジンからの応答を一時的に保存するパス
    # 参考: https://qiita.com/aosho235/items/bb1276a8c43e41edfc6f
    proxy_cache_path /var/cache/nginx keys_zone=zone1:1m max_size=1g inactive=24h;
    proxy_temp_path  /var/cache/nginx_tmp;

    include /etc/nginx/conf.d/*.conf;
}

etc/nginx/conf.d/example.com.conf

# proxy先の設定
upstream my_app {
  # 送信先のサーバをクライアントIPから算出する
  ip_hash;

  # 送信先のサーバ情報
  # weightが大きいほど送信頻度が高くなる
  server 192.168.101:80 weight=1;
  server 192.168.102:80 weight=1;
}

# HTTPの設定
# HTTPSにリダイレクトする
server {
    listen  80 proxy_protocol;
    server_name www.example.com assets.example.com;
    return 301 https://$host$request_uri;
}

# HTTPS
# proxyする
server {
    listen 443 ssl http2 proxy_protocol;
    server_name www.example.com assets.example.com;

    # X-Forwarded-ForからproxyのIPアドレス(192.168.0.0/24)を削って
    # 一番右側のIPアドレスを、$remote_addr変数にセットする
    # 参考: https://christina04.hatenablog.com/entry/2016/10/25/190000
    set_real_ip_from 192.168.0.0/24;
    real_ip_header X-Forwarded-For;

    # ELB+SSLの場合は、こうする
    # set_real_ip_from 192.168.0.0/24;
    # real_ip_header proxy_protocol;

    # ステータスコードが20x,30xの場合にレスポンスヘッダに含める
    # 参考: https://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header
    add_header Front-End-Https on;

    # レスポンスヘッダに含まれるnginxのバージョンを消す
    server_tokens off;

    # リダイレクト時のサーバ名に何を使うか
    # on: server_nameディレクティブのサーバ名(デフォルト)
    # off: Hostヘッダの値
    # 参考: https://heartbeats.jp/hbblog/2012/04/nginx04.html
    server_name_in_redirect off;

    # アップロードのサイズ制限
    # 参考: https://qiita.com/notakaos/items/4816ad71b90a9967fa18
    client_max_body_size 10M;

    # クライアントリクエストボディをファイルとして書き出すか
    # on: ファイル書き出す+消さない
    # clean: ファイル書き出す+消す
    # off: ファイルに書き出さない(デフォルト)
    # 参考: http://mogile.web.fc2.com/nginx/http/ngx_http_core_module.html#client_body_in_file_only
    client_body_in_file_only clean;

    keepalive_timeout 5;

    # 使用する証明書の指定
    ssl_certificate /etc/nginx/ssl/example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    ssl_protocols             TLSv1.2 TLSv1.3;
    ssl_ciphers               AESGCM:HIGH:!aNULL:!MD5:!LOW:!SSLv2:!EXP:!eNULL;
    ssl_prefer_server_ciphers on;

    # プロキシ先に送信する際のヘッダ設定
    proxy_set_header X-Real-IP $remote_addr;     # クライアントのIPアドレス
    proxy_set_header X-Forwarded-Proto $scheme;  # クライアントとサービスエンドポイントで使用したプロトコル
    proxy_set_header Host $http_host;            # Hostヘッダ
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # X-Forwarded-Forに自身のIPを足した値をセットする
    proxy_set_header Authorization $http_authorization;

    # デフォルトでproxyに通さないヘッダを通す設定
    proxy_pass_header Accept;
    proxy_pass_header Server;

    # proxy先のタイムアウト設定
    proxy_read_timeout 300;
    proxy_connect_timeout 300;
    proxy_send_timeout 300;

    # proxy先がリダイレクトを返したときに、nginxがリダイレクト先を書き換えるか
    # proxy_redirect http:// https://;
    # とすると、httpをhttpsに書き換えてくれる
    proxy_redirect off;

    # setで変数に値をセットできる
    set $do_not_cache 1;
    if ($uri ~* "\.(jpeg|gif|png|jpg|webp)") {
        set $do_not_cache 0;
    }
    if ($request_method != GET) {
        set $do_not_cache 1;
    }

    # ファイルをキャッシュから取得するか
    # 0: キャッシュ使う
    # 1: キャッシュから取得しない
    proxy_cache_bypass $do_not_cache;

    # proxy先が返すCache-Controlヘッダを無視する
    proxy_ignore_headers Cache-Control;

    proxy_cache zone1;        # キャッシュに使うメモリ領域を指定。名前は任意の値を使用可。
    proxy_cache_valid 200 3m; # status=200の場合は3分キャッシュを使う
    proxy_cache_key "$scheme://$host$request_uri$is_args$args";

    # /* へのアクセスを my_app/* へプロキシする
    location / {
        proxy_pass https://my_app/;
    }

    # trailing slashあり
    # /info01/abc へのアクセスは、https://example.jp/abc へ転送される
    # 参考: https://blog.cosnomi.com/posts/674/
    location /info/ {
        proxy_pass https://example.jp/
    }

    # trailing slashなし
    # # /news/abc へのアクセスは、https://example.jp/news/abc へ転送される
    location /news/ {
        proxy_pass https://example.jp
    }

    location /blog/ {
        proxy_pass https://blog.example.com/;

        # proxy先が返したリダイレクト先を /blog/ に書き換える
        proxy_redirect https://blog.example.com /blog/;
        proxy_redirect http://blog.example.com /blog/;

        # proxy先が返したレスポンスの文字列を /blog に書き換える
        # sub_filter_once offにすることで、複数個の書き換えを行う
        sub_filter "https://blog.example.com" "/blog";
        sub_filter "http://blog.example.com" "/blog";
        sub_filter_once off;
    }
}

screenの代わりにnohup&を使う

時間のかかるバッチ処理を手動で実行するとき、 sshセッションが切断しても大丈夫なようにscreenコマンドを使っていたけど、 他の方法を知ったのでメモしておく。

やりかた

サンプルスクリプト

#!/bin/sh

# 永遠に標準出力と標準エラー出力を繰り返す
while true
do
  sleep 1

  # 標準出力
  echo `date` STD_LOG >&1

  # 標準エラー出力
  echo `date` ERR_LOG >&2
done

実行するコマンド

nohup sh ./script.sh 1> std.log 2> err.log &

コマンドの意味

  • &: 裏ジョブ実行
  • nohup: 通常裏ジョブは、親プロセスが終了(ssh接続断など)すると、HUPシグナルで終了させられるが、nohupつけることで回避できる
  • 1>: 標準出力をファイルにリダイレクト。ファイルに書き出さないと、あとで出力内容を確認できない。
  • 2>: 標準エラー出力をファイルにリダイレクト

出力結果

% tail -n 3 std.log
2021年 6月21日 月曜日 18時17分10秒 JST STD_LOG
2021年 6月21日 月曜日 18時17分11秒 JST STD_LOG
2021年 6月21日 月曜日 18時17分12秒 JST STD_LOG

% tail -n 3 err.log
2021年 6月21日 月曜日 18時17分10秒 JST ERR_LOG
2021年 6月21日 月曜日 18時17分11秒 JST ERR_LOG
2021年 6月21日 月曜日 18時17分12秒 JST ERR_LOG

所管

  • 標準出力と標準エラー出力をちゃんとリダイレクトしないと、出力結果を確認できなくなるのが注意点。
  • screen使える環境なら、screen使えばいいのでは。

よく見る圧縮形式メモ

雰囲気でしかわかってなかったので整理。

zip

  • WindowsMacの標準形式
  • 圧縮率は高くない
  • 4GBを超えるファイルは扱えない
  • 圧縮後に2GBを超えるファイルは扱えない
  • Macの標準機能で圧縮すると、Windowsでファイル名が文字化けする
  • Linuxでは標準で使えない
  • 複数ファイルやディレクトリごと圧縮ができる
# 単一ファイルを圧縮
zip file.zip file

# パスワード付き
zip -e file.zip file

# ディレクトリごと圧縮
zip -r dir.zip dir/

# 展開する
unzip dir.zip

gzip

  • Linuxの標準的な圧縮方式
  • 圧縮率はzipと同程度
  • 1ファイルしか圧縮できない
  • 複数ファイルを圧縮するときはtarと組み合わせて使う
# 単一ファイルを圧縮
# 元ファイルは残らない
gzip example.txt

# 元ファイルを残したい場合、-cオプションで標準出力する
gzip -c example.txt > example.txt.gz

# 単一ファイルを展開
# 元ファイルは残らない
gunzip example.txt.gz

# 元ファイルを残したい場合、-cオプションで標準出力する
gunzip -c example.txt.gz > example.txt

tar

  • 複数のファイルを1つにまとめるアーカイブ方式
  • tar自体は圧縮形式ではない
  • 圧縮形式との組み合わせ利用ができる
# 複数ファイルの圧縮
# -zオプションでgzip形式に圧縮される
tar czvf bk.tar.gz file1 file2
tar czvf bk.tar.gz dir

# 展開
# -zオプションでgzip形式を扱う
tar xzvf bk.tar.gz

参考

MySQLでバイナリログを削除する

バイナリログファイルの確認

メインDBで確認する

mysql> show master logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000091 |       141 |
# 略
| mysql-bin.000107 |        98 |
+------------------+-----------+
17 rows in set (0.00 sec)

レプリケーション先の反映状況を確認する

レプリカで確認する

mysql> show slave status\G
*************************** 1. row ***************************
             Slave_IO_State: Waiting for master to send event
# 略
            Master_Log_File: mysql-bin.000107
# 略

で、どこまで追いついているか確認する。 削除しようとするバイナリログ以前であれば反映まで待つ。

バイナリログの削除

メインDBで作業する

purge master logs to 'mysql-bin.000091';