kasei_sanのブログ

かせいさんのIT系のおぼえがきです。胡乱の方はnoteとtwitterへ

RDS Auroraのreaderからのpg_dumpの途中で接続が切れる場合、max_standby_streaming_delay を上げると良いよ

タイトルで言いたいことだいたい言っちゃったんですが、

readerエンドポイントでpg_dump を実行していたら、大きめのテーブルをdumpしている時に接続がちょこちょこ途切れる現象が発生していました。 それで、DBのログを見てみたら以下のエラーがありました

FATAL:  terminating connection due to conflict with recovery
DETAIL:  User was holding a relation lock for too long.

これは、以下のサイトに詳しいのですが

www.fujitsu.com

「writer側の更新によるWAL(トランザクションログ)が、reader側に更新される」のと、「reader側の参照処理」がコンフリクトした場合に、一定時間が経過すると、参照側の接続が切られる という、psqlの機能のために発生しています

で、その待機時間を設定するためのオプションが、max_standby_streaming_delay です

max_standby_streaming_delay のポイント

  • postgreSQLのデフォルト値は30秒
  • Amazon Aurora PostgreSQL では、14秒
  • Amazon Aurora PostgreSQL で、設定できる最大値は 30秒

30秒で処理しきれない参照処理がある場合はどうしたら良いの?

  • 諦めてwriterエンドポイントで処理する
  • もしくは、SQLを分割するなど対策をする

参考

www.postgresql.jp

Amazon Athenaでアクセスログから、特定PATHの分ごとのアクセス数をカウントする方法

以下は、2023/11/18の15:00〜15:10の間の https://example.com:443/hoge への分単位のアクセス数を取るSQL

SELECT
    minute,
    COUNT(minute) AS count
    FROM (
        SELECT 
            date_trunc('minute', from_iso8601_timestamp(time)) AS minute
        FROM "alb_access_logs"
        WHERE 
            (time BETWEEN '2023-11-18T15:00:00' AND '2023-11-18T17:10:00') AND
            request_url like 'https://example.com:443/hoge'
    )
GROUP BY minute

date_trunc は、タイムスタンプを特定の範囲に丸めるもの ( minute とか day とか )

また、date_trunc にわたす前に、time を from_iso8601_timestamp で、ISO 8601 に変える必要がある

AUTOVACUUMが動かない時に調べること

AUTOVACUUMの設定

SELECT name, setting
FROM pg_settings
WHERE name LIKE '%autovacuum%';
  • autovacuumon であること
  • 他の数値も異常な値でないこと(どう考えても実行されない閾値とか)

AUTOVACUUMの最終実行日時

SELECT relname, last_autovacuum,last_autoanalyze FROM pg_stat_user_tables
WHERE 
    last_autovacuum is not NULL OR
    last_autoanalyze is not NULL;

テーブル毎のオプション

SELECT relname, reloptions
FROM pg_class
WHERE array_length(reloptions, 1) IS NOT NULL;
  • {autovacuum_enabled=false} が設定されていると、AUTOVACUUMされない

AUTOVACUUM実行対象のテーブル一覧

WITH vbt AS (SELECT setting AS autovacuum_vacuum_threshold FROM 
pg_settings WHERE name = 'autovacuum_vacuum_threshold'),
vsf AS (SELECT setting AS autovacuum_vacuum_scale_factor FROM 
pg_settings WHERE name = 'autovacuum_vacuum_scale_factor'), 
fma AS (SELECT setting AS autovacuum_freeze_max_age FROM pg_settings WHERE name = 'autovacuum_freeze_max_age'),
sto AS (select opt_oid, split_part(setting, '=', 1) as param,
split_part(setting, '=', 2) as value from (select oid opt_oid, unnest(reloptions) setting from pg_class) opt)
SELECT '"'||ns.nspname||'"."'||c.relname||'"' as relation,
pg_size_pretty(pg_table_size(c.oid)) as table_size,
age(relfrozenxid) as xid_age,
coalesce(cfma.value::float, autovacuum_freeze_max_age::float) autovacuum_freeze_max_age,
(coalesce(cvbt.value::float, autovacuum_vacuum_threshold::float) +
coalesce(cvsf.value::float,autovacuum_vacuum_scale_factor::float) * c.reltuples)
AS autovacuum_vacuum_tuples, n_dead_tup as dead_tuples FROM
pg_class c join pg_namespace ns on ns.oid = c.relnamespace 
join pg_stat_all_tables stat on stat.relid = c.oid join vbt on (1=1) join vsf on (1=1) join fma on (1=1)
left join sto cvbt on cvbt.param = 'autovacuum_vacuum_threshold' and c.oid = cvbt.opt_oid 
left join sto cvsf on cvsf.param = 'autovacuum_vacuum_scale_factor' and c.oid = cvsf.opt_oid
left join sto cfma on cfma.param = 'autovacuum_freeze_max_age' and c.oid = cfma.opt_oid
WHERE c.relkind = 'r' and nspname <> 'pg_catalog'
AND (age(relfrozenxid) >= coalesce(cfma.value::float, autovacuum_freeze_max_age::float)
OR coalesce(cvbt.value::float, autovacuum_vacuum_threshold::float) + 
coalesce(cvsf.value::float,autovacuum_vacuum_scale_factor::float) * 
c.reltuples <= n_dead_tup)
ORDER BY age(relfrozenxid) DESC LIMIT 50;

👇こちらから拝借

docs.aws.amazon.com

参考

qiita.com

Railsのdatabase.ymlのpoolの適正数

先に結論

Railsの中でスレッド処理をしていないのであれば

  • Unicornの場合 1
  • Pumaの場合 スレッドの数

なんで UnicornとPumaで数が違うの?

ざっくりいうと、Unicornはマルチプロセスで、Pumaはマルチスレッドだから (厳密には違うけど)

それで、コネクションプールはRailsのプロセスごとに持ってる

マルチプロセスのUnicornでは、1worker = 1プロセス なので、workerが消費するのは、1つのコネクションだけ。 なので、database.ymlの pool の値は 1 が適正

それに対して、マルチスレッドのPumaでは、1つのプロセスで複数のスレッドが動作する。 そのため、スレッドの数だけコネクションが必要になる

参考

blog.kasei-san.com

AWSコスト最適化ガイドブック 読書メモ

初学者やAWS詳しくない人が、最適な使い方を学ぶのには良い本でした

逆にある程度くわしい人は、知らないところをつまみ食いすればそれで終わる感じでした

ざっくり

  • AWSのコスト最適化についてのアドバイス集
  • それに合わせて、各サービスの最適な使いかたの紹介
  • EC2、RDS、ストレージ系、lambda、ECS、DynamoDBなど

感想

  • AWSの中の人が書いているので信頼度は高いと感じた
  • 基本的なことはしっかり抑えられている
  • その分、自分が知らなかった! というものはほとんど無かった

どんな人が読むべきか?

  • AWS詳しくないけど前任者が居なくなってインフラを任せさられた! って人や初心者が読むべき
  • AWSソリューション認定アーキテクト、アソシエイトを取得した人が、各サービスの実践的な使い方を学ぶのには最適なんじゃないでしょうか
  • 少なくとも、資格取ってこれ読んでくれれば、最低限の戦力になってくれそうな気がする

メール関係の用語おぼえがき

勉強する必要が出たのでおぼえがき

レピュテーション(reputation)

「レピュテーション(reputation)」とは、電子メールの送信元の信頼性や評判を示す指標

  • スパムメールや悪意のあるメールの送信者と、信頼性のあるメール送信者を区別するために使用される
  • レピュテーションが低い内に、大量のメールを送信すると、受信側で受け入れが制限されることがある スロットリング と呼ばれる
  • レピュテーションは、ISPやメールサーバ毎にそれぞれ保有しているため、同じ送信元でもスロットリングされたり、されなかったりする
  • 基本的にはIPアドレス単位で判断される(他の要素も勘案されるらしい)
  • なので、 共有IPのメールサービスを使う場合、他のユーザの行動によって巻き添えを食う場合がある
  • そのため、 商用でメールを送るシステムを作る場合、個別IPにするのが無難
  • ただし、個別IPでメールシステムを立ち上げた場合、以下の IPウォームアップ が必要になる

ブラックリスト

スパムや悪質なメールを送信する、IPアドレスやドメインを共有しているリスト

ここに入ったからといって、ただちにメールが受け入れられなくなる訳では無いが、レピュテーションの評価に強く影響を受ける

この辺が有名らしい

  • Spamhaus
  • SURBL
  • Barracuda Reputation Block List
  • Invalument
  • Spamcop
  • MultiRBL

苦情

メールを受信したユーザが「迷惑メールを報告」などのボタンを押すこと

  • 苦情率が高いと、レピュテーションに大きく影響を受けたり、メールサービスからBANされたりする
  • さらにブラックリストに乗せられることもある

IPウォームアップ

新規にメールサーバを立ち上げた場合、レピュテーションが低い状態でいきなり大量のメールを送信すると、スロットリングされることがある

そのため、少しづつメールを送って、レピュテーションを高めていく作業をIPウォームアップと呼ぶ

sendgrid.kke.co.jp

バウンス

メールが配信できなかった。ということを指す用語

受信側からエラーコードが返ってくる

  • 4xxはソフトバウンス
  • 5xxはハードバウンス

ソフトバウンス

受信側の都合でメールが受信できない

  • メールボックスがビジーである
  • ポリシー上の理由で一時的にブロックされている
  • 処理中のエラー
  • システムストレージが不十分

など

なお、スロットリングはソフトバウンス扱い

ハードバウンス

受信側ではどうにもできない理由でメールが受信できない

  • 構文エラー、パラメータエラー、未実装の命令
  • 存在しない、無効なメールアドレス

など

レピュテーションが低下するため、ハードバウンスは避けなければならない

ハードバウンスを避けるにはどうしたら良いの?

無効なメールアドレスにはメールを送らない

メールシステムを利用しているのであれば、ハードバウンスが帰ってきたメールアドレスは送信リストから削除して、受信側に迷惑をかけないようにする

参考

👇4.2.3 数字順の返信コード に受信側のレスポンスコード一覧がある

tex2e.github.io

sendgrid.kke.co.jp

スロットリング

スロットリングとは、システムの過負荷や特定利用者による資源の独占を回避するため、一定の制限値を超えた場合に意図的に性能を低下させたり、要求を一時的に拒否したりする制御のこと。

e-words.jp

メールシステムにおいては、受信側が大量のメールの受信を制限する機能

  • 一度に大量のメールを送ると発生する
  • システム的には ソフトバウンス 扱い

スロットリングを防ぐにはどうしたら良いの?

  • レピュテーションを高める
    • 最初は、まとめて送信せずに時間を置いて少しづつ送信する
    • ただし、無効なメールアドレスが多く含まれていたりすると、なかなか受け入れてもらえない
  • 複数のIPアドレスで送信する
    • これはこれで、それぞれのレピュテーションがある程度無いと無意味

参考

sendgrid.kke.co.jp sendgrid.kke.co.jp

サプレッションリスト

メールサービスに存在する、ハードバウンスや苦情等を受け取って送信対象外とするメールアドレスの一覧

  • Amazon SESでは、
    • リージョン単位の グローバルサプレッションリスト
    • アカウント単位の アカウントサプレッションリスト
    • さらに、Configuration set-level suppression というのがある
  • SendGridでは、アカウント単位の バウンスリスト がある

それぞれ挙動は微妙に違う

グローバルサプレッションリストについて

キャリアメールだと「特定のドメイン以外受信しない」設定があるため、特定のドメイン外のメールを受けてハードバウンスを食らった場合に、 受信可能なドメインのメールもサプレッションリストのせいで送信できない 、という問題があるらしい

qiita.com

(ハード)バウンスはメールアドレスが存在しないなど、恒久的なエラーの場合に発生するものなので、一度バウンスすると他のユーザからも送信不可能にするSESの仕組みは非常に合理的といえます。ただし、日本で使用する場合に問題になるのが携帯キャリアへ送信する場合です。

例えば、ドメイン指定拒否をしている人に対して、許可されたドメイン以外から送信すると、バウンスが発生します(挙動はキャリアによって異なります)。そうすると当然Suppression Listに掲載されてしまうので、許可されたドメインから送信していた人もSuppression Listに引っかかってしまい、送信ができなくなってしまいます。リストから削除しても、また他のドメインから送信されてしまうと、また巻添いを食らってしまいます。これがSESが携帯キャリアへの配信と相性が悪いと言われる所以だと考えています。

参考

dev.classmethod.jp

sendgrid.kke.co.jp

qiita.com

参考

sendgrid.kke.co.jp