1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Amazon Aurora DSQL を使ってみる (4) アプリも含めたマルチリージョン冗長構成イメージ

Posted at

1. はじめに

2. やったこと

  • Aurora DSQLをus-east-1/us-east-2のマルチリージョンで作成し、検証用のテーブルを作成する。
  • us-east-1/us-east-2それぞれにEC2インスタンスにおいて、Flaskアプリ(メモ帳的なもの)からリージョン内のAurora DSQLエンドポイントに接続し、Webから入力されたコメントをAurora DSQLのテーブルに保存する。
  • Flaskアプリを立てた、各リージョンのEC2インスタンスのEIPをRoute53のAレコードに登録する。通常時は50%/50%の加重ルーティングとし、ラウンドロビンで両方への読み書きができることを確認する。また、障害やメンテナンス時は加重ルーティングの値を変更し、片寄せができることを確認する。

3. 構成図

image.png

4. 手順

4.1 Aurora DSQL 検証用テーブル作成

  • 以下の列を持つ検証用テーブルを作成する。
    • comment: WEBから入力されたコメント
    • time: コメントが入力された日付/時刻
    • region: コメントが書き込まれたリージョン
create-table.sql
postgres=> CREATE TABLE comment_list (comment VARCHAR(50) NOT NULL, time TIMESTAMP NOT NULL, region VARCHAR(50) NOT NULL);
  • テーブルは以下のようになる。
comment time region
hello 2025-02-25 13:15:17 us-east-1
bye 2025-02-25 13:14:10 us-east-1
thanks 2025-02-25 13:10:10 us-east-2

4.2 Flaskアプリ(メモ帳的なもの)の作成

必要資材のインストール

  • Amazon Linux 2023に、以下の必要資材をインストールする。
    • Flask: WEBサイト構築のため
    • psycopg3: DSQL(PostgreSQL)への接続のため
    • boto3: DSQLのパスワード(トークン)の取得のため
  • FlaskからのSQL接続用に、Flask-SQLAlchemyを使いたかったが、DSQL接続時の必須設定となっている「sslmode=require」の対応方法がよく分からず今回は断念して、psycopg3でそのままSQL文を実行している。
[ec2-user@ip-10-0-0-65 ~]$ sudo dnf install pip
[ec2-user@ip-10-0-0-65 ~]$ pip install flask
[ec2-user@ip-10-0-0-65 ~]$ pip install "psycopg[binary]>=3”
[ec2-user@ip-10-0-0-65 ~]$ pip install boto3

WEBサイト構成ファイルの作成

  • 以下の2つのファイルを作成する。
    • myapp.py: メインロジック
    • templates/memo-post.html: htmlのテンプレート
  • おおまかな仕様としては以下。
    • Flaskサーバにユーザが「http://x.x.x.x:5000/」でhttpアクセス(GET)すると、コメントの入力画面が表示される。ユーザがコメントを入力して送信ボタンを押すと、同じパスにhttpアクセス(POST)が行われる。
    • FlaskサーバがPOSTリクエストを受けると、入力されたコメントを取得し、「コメント、処理した時刻、自分のリージョン」の3つをAurora DSQLのテーブルへINSERTする。INSERTした後、テーブルをSELECTして全レコードを取得し、memo-post.html(テンプレート)にレコードの内容を埋め込んでhtmlとして出力する。
    • us-east-1のFlaskサーバを用いて書き込まれたコメントはus-east-1のAurora DSQLからus-east-2のAurora DSQLへ同期されるため、us-east-2側のFlaskサーバでもすぐに参照できる。
myapp.py
from flask import Flask, render_template, request
import psycopg
import boto3
from datetime import datetime

# DSQLのエンドポイントとリージョンは、自リージョンのものをそれぞれ指定
cluster_endpoint = "xxxxxxxxxxxxxxxxxxxxxxxx.dsql.us-east-1.on.aws" 
region = 'us-east-1'
client = boto3.client("dsql", region_name=region)
password_token = client.generate_db_connect_admin_auth_token(cluster_endpoint, region)

conn = psycopg.connect(
    dbname='postgres',
    user='admin',
    password=password_token,
    host=cluster_endpoint,
    sslmode='require'
)

conn.set_autocommit(True)
cur = conn.cursor()

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        cur.execute("SELECT * FROM comment_list ORDER BY time DESC")
        results = cur.fetchall()
        formatted_results = []
        for row in results:
            formatted_time = row[1].strftime('%Y-%m-%d %H:%M:%S')
            formatted_results.append((row[0], formatted_time, row[2]))
        return render_template('memo-post.html', comments=formatted_results)
     
    if request.method == 'POST':
        comment = request.form['data1']
        itime = datetime.now()
        cur.execute("INSERT INTO comment_list(comment, time, region) VALUES(%s, %s, %s)",(comment, itime, region))
        cur.execute("SELECT * FROM comment_list ORDER BY time DESC")
        results = cur.fetchall()
        formatted_results = []
        for row in results:
            formatted_time = row[1].strftime('%Y-%m-%d %H:%M:%S')
            formatted_results.append((row[0], formatted_time, row[2]))
        return render_template('memo-post.html', comments=formatted_results)       

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
memo-post.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>
<body>
<h1>DSQL マルチリージョンメモ帳 us-east-1</h1>
<form action="/" method="POST">
        <input name="data1"></input>
        <button type="submit">送信</button>
    </form>
</body>

<h1>Comments</h1>
<ul>
    {% for comment in comments %}
        <li>{{ comment[0] }} - {{ comment[1] }} - {{ comment[2] }}</li>
    {% endfor %}
</ul>
</html>

4.3 Route53レコード登録

  • 所持しているパブリックドメイン(ここでは xxxxx.netとする)に、Aレコードを登録する。今回は以下のように登録する。
  • 通常時は2つのFlaskサーバのIPアドレスが半々に返却される。加重の設定値を変更することで片寄せなどを行うことができる。
レコード名 タイプ ルーティングポリシー 差別化要因
memo A 加重 50 xx.xx.xx.242 (us-east-1のインスタンス)
memo A 加重 50 yy.yy.yy.149 (us-east-2のインスタンス)

4.4 Flaskアプリからの読み書きの確認

通常時の動作

  • http://memo.xxxxx.net:5000 にアクセスすると、us-east-1/us-east-2のどちらかのFlaskサーバに半々の割合で接続される。(以下の画面はus-east-1側に接続した場合)

image.png

  • コメント欄に「hello」と入力し送信すると、コメント、入力時刻、書き込んだリージョン、の3つの情報がINSERTされ保存され、その後SELECTした結果がComments欄に表示される。今回はus-east-1側で書き込まれていることが分かる。

image.png

  • しばらくして同じURL(http://memo.xxxxx.net:5000)に再度アクセス(GET)すると、アクセス先がus-east-2側のFlaskサーバとなっている。GETアクセス時にSELECT文が実行されるが、先ほどus-east-1側でINSERTされた内容がus-east-2側に同期されてきているため、us-east-2側でもus-east-1側で登録したコメントが表示される。

image.png

  • コメント欄に「bye」と入力し送信(POST)すると、コメント、入力時刻、書き込んだリージョン、の3つの情報がINSERTされ保存され、その後SELECTした結果がComments欄に表示される。レコードは両方のリージョン間で双方向同期されており、最初にus-east-1側で「hello」が、次にus-east-2側で「bye」が書き込まれたことが分かる。(Comments欄は新しいものを上に表示)

image.png

片系障害時の動作

  • 片方のリージョンのFlaskサーバやAurora DSQLに障害が発生した場合、加重の値を変更して、トラフィックを片寄せする。今回は以下のように値を変更する。
レコード名 タイプ ルーティングポリシー 差別化要因
memo A 加重 0 xx.xx.xx.242 (us-east-1のインスタンス)
memo A 加重 100 yy.yy.yy.149 (us-east-2のインスタンス)
  • レコードの設定変更反映後は、us-east-2側のIPアドレスのみが返却されるため、片寄せを行うことができる。

5. 所感

  • しょぼいWEBアプリだが、一応アプリケーションも含めた使い方イメージが説明できるようになった。
  • Aurora DSQLの接続では必須となっている「sslmode=require」の対応方法が分からず、SQLAlchemyのようなORマッパーを使うことができず、今回はSQLを直打ちしてしまった。今後やるときは改善したい。

6. 参考サイト/記事

  • Flaskの基本的な使い方やDB接続の手順確認のため、主に以下のサイトを参考とさせて頂いた。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?