はじめに
こんにちは、村田です。Go言語でWebサーバを実装していた際にDynamoDBを扱うライブラリとしてGregさんの https://github.com/guregu/dynamo を使っていました(2年ほど稼働していますが、特に問題も出ていません)
当時Go初心者だった私は「go dynamo」とすぐさまGoogle先生に問い合わせ、「guregu/dynamoがオススメ」とのエントリーを多数発見しました。オブジェクトの取り回しが隠蔽化されていてとにかく実装が簡単だと記事にも書いてありましたし、私自身も実際そう感じました。
すでにタイトルからお察しかと思いますが、本記事は連載第1回目です。時代の移ろいに合わせてDynamoDB×Go界隈の事情も刻一刻と変化しています。まずは私の利用していたSDK(guregu/dynamo)についてから本連載をスタートします。
SDK(guregu/dynamo)を使ってDynamoDBへアクセスする
ローカルの検証環境を準備
ソースコードに触る前にまずは環境の準備から。
DynamoDB LocalをDocker上で動かすのが楽なので今回はそちらを使います。
docker pull amazon/dynamodb-local |
DynamoDB Localへのアクセスはaws cliを利用するのでそちらも準備します。アクセス時はEndpointのURLを引数で指定してあげる必要があります。
$ aws dynamodb list-tables --endpoint-url http://localhost:8000 --region ap-northeast-1 |
怒られちゃいました…
FakeでもいいのでCredentialを指定しなければならないので aws configure
を使って指定します。
$ aws configure |
…ということで気を取り直して、
$ aws dynamodb list-tables --endpoint-url http://localhost:8000 |
OKそうですね。あとはテーブルを作成したら準備OKです。
今回は以下のようなスキーマでテーブルを作成します。
- テーブル名
MyFirstTable
- HashKey
MyHashKey
-S
- RangeKey
MyRangeKey
-N
$ aws dynamodb create-table --endpoint-url http://localhost:8000 --table-name MyFirstTable --attribute-definitions AttributeName=MyHashKey,AttributeType=S AttributeName=MyRangeKey,AttributeType=N --key-schema AttributeName=MyHashKey,KeyType=HASH AttributeName=MyRangeKey,KeyType=RANGE --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 |
ちなみにですが、DynamoDB Localの場合は設定したCapacity Unitは考慮されないので適当な値を設定しても問題ありません。
ソースコード書いていきます
※ソースは全て https://github.com/mura123yasu/go-guregu-dynamo にアップしているので適宜参考にしてください。
クライアントを準備
環境変数から諸々の値を取得するようにしつつ、クライアントを生成します。
テーブル名は先程作成した MyFirstTable
を設定します。
func main() { |
単純なCRUD
ここからはCRUD処理の実装を進めます。
Create
Createで利用するメソッドは Put
です。
Put対象のitemを準備して渡すだけで簡単ですが1点注意事項があります。itemはPut先テーブルのKeyをすべて含むものでなければなりません。今回であれば MyHashKey
と MyRangeKey
です。
func main() { |
Read
Readで利用するメソッドは Get
です。他にも Scan
も使えるので用途に合わせて色々試してみて下さい。
私達が実装したWebサーバでは、DynamoDBに対するアクセスはキーアクセスのみに限定していたため、Getの利用で事足りました。
func main() { |
Update
利用するメソッドは Update
です。
少し余談にはなるのですが、Webサーバ実装時はUpdateは使いませんでした。常にPut処理を行っており、全体シーケンスを検討する中で冪等性を保つためにそのような設計にしていました。
func main() { |
Delete
利用するメソッドは Delete
です。
Keyさえ指定していれば問題ないのは他メソッドと変わりません。
func main() { |
Conditional Check
これはもうゴリゴリに使い倒しました。以下の例はとてもシンプルなものですが、実際には If("MyText = ?", "some word")
の部分に様々な条件を記載します。書き方は色々あるので必要に応じて確認してみてください。
func main() { |
要件を満たすためにほぼほぼマストで必要だったConditional Checkですが、しっかり設計しておかないと一番泣きを見ることになる部分になります。
例えば、開発当時ロックの機構をこのConditional Checkで実現しており、ロック取得者以外がレコードを更新できないようになど制御をかけていたのですが、一連のシーケンスの中で予期しない割り込みが発生すると永遠に更新できないレコードが登場し…もちろん設計ミスによるものですが、とても苦しみました(原因究明の時間は非常に楽しかった記憶もありますが笑)
一連のソースを実行してみる
さて、紹介してきた一連の動作を最後に実行してみましょう。DynamoDB Localを使用する場合は環境変数にて DYNAMO_ENDPOINT
だけ指定してRunするだけ。簡単ですね。
git checkout https://github.com/mura123yasu/go-guregu-dynamo.git |
※ちなみにコミットしているソースはConditional CheckのUpdateだけが失敗しますが、想定通りなので問題ありません。
最後に
連載初日の記事はいかがだったでしょうか? レベル的には初学者の方に向けた内容だったかなと思います。「まずはGo言語でDynamoDBをつついてみたい」という方が本記事を通じて簡単にチャレンジできたら幸いです。
DynamoDB×Go連載企画 の1本目でした。次は武田さんのAWS SDKによるDynamoDBの基本操作です。
DynamoDB×Go以外にも多くの連載企画があります。特にGo Cloud連載が今回のテーマに近いです。