Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
AWS SDKのClientはFactory経由で作ろう
Search
TomoyaIwata
September 26, 2023
Programming
1
800
AWS SDKのClientは Factory経由で作ろう
「緊急開催!サーバーレス座談会 in JAWS-UG 大阪」にてLTさせて頂いた際の資料です
https://jawsugosaka.doorkeeper.jp/events/162714
TomoyaIwata
September 26, 2023
Tweet
Share
More Decks by TomoyaIwata
See All by TomoyaIwata
これでLambdaが不要に?!Step FunctionsのJSONata対応について
iwatatomoya
2
4.8k
Qdrantでベクトルデータベースに入門してみよう
iwatatomoya
0
600
詳解 AWS Lambdaコールドスタート
iwatatomoya
1
2.3k
真のサーバーレスへ向けたAuroraの進化Aurora Limitless Database
iwatatomoya
1
4.7k
OpentelemetryでアプリケーションのObservabilityを強化しよう
iwatatomoya
0
1k
AWS Lambdaは俺が作った
iwatatomoya
2
2.4k
SnapStartの未来についての期待と妄想
iwatatomoya
1
1.4k
実例から学ぶ! AWSを活用したシステム開発の勘所
iwatatomoya
1
3.2k
目指せ完全制覇!3大クラウドの認定資格制度と勉強方法について
iwatatomoya
0
9.4k
Other Decks in Programming
See All in Programming
本当だってば!俺もTRICK 2022に入賞してたんだってば!
jinroq
0
260
家族・子育て重視/沖縄在住を維持しながらエンジニアとしてのキャリアをどのように育てていくか?
ug
0
240
Kubernetesで実現できるPlatform Engineering の現在地
nwiizo
2
1.7k
eBPF Updates (March 2025)
kentatada
0
130
PHPer's Guide to Daemon Crafting Taming and Summoning
uzulla
2
1.1k
いまさら聞けない生成AI入門: 「生成AIを高速キャッチアップ」
soh9834
12
3.8k
令和トラベルにおけるコンテンツ生成AIアプリケーション開発の実践
ippo012
1
270
SLI/SLOの設定を進めるその前に アラート品質の改善に取り組んだ話
tanden
2
730
Going Structural with Named Tuples
bishabosha
0
170
OUPC2024 Day 1 解説
kowerkoint
0
400
SideKiqでジョブが二重起動した事象を深堀りしました
t_hatachi
0
240
Firebase Dynamic Linksの代替手段を自作する / Create your own Firebase Dynamic Links alternative
kubode
0
180
Featured
See All Featured
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
12
610
Java REST API Framework Comparison - PWX 2021
mraible
29
8.5k
The Cost Of JavaScript in 2023
addyosmani
48
7.6k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
12k
Build The Right Thing And Hit Your Dates
maggiecrowley
34
2.6k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
8
700
Why Our Code Smells
bkeepers
PRO
336
57k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
135
33k
KATA
mclloyd
29
14k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
331
21k
Designing for Performance
lara
606
69k
Code Reviewing Like a Champion
maltzj
522
39k
Transcript
AWS SDKのClientは Factory経由で作ろう クラスメソッド株式会社 岩⽥ 智哉 1
2 ⾃⼰紹介 l クラスメソッド株式会社 サーバーサイドエンジニア l 2023 Japan AWS Top
Engineer l 2023 Japan AWS All Certifications Engineer l 前⼗字靭帯再建⼿術リハビリ中 岩⽥ 智哉
3 ⾔いたいこと AWS SDKのClientは Factory経由で作ろう
4 LambdaとEC2/ECSの違い リクエストとコンピューティング環境がN:1 リクエストとコンピューティング環境が1:1
5 リクエストとコンピューティング環境が1:1だと… ソケット ソケット ソケット ソケット DynamoDB等のAWSサービス ソケット ソケット Lambda実⾏環境で⽣成するソケットは1つで⼗分
(なことが多い)
6 これらを意識すると AWS SDKのClientの扱いが 最適化できる
7 良くない例1 import boto3 class TableA: def __init__(self): self._client =
boto3.client('dynamodb') def put_item(self, item): self._client.put_item(TableName='tableA', Item=item) class TableB: def __init__(self, client): self._client = boto3.client('dynamodb') def put_item(self, item): self._client.put_item(TableName='tableB', Item=item) def handler(event, context): table_a = TableA() table_a.put_item({'foo': 'bar’}) table_b = TableB() table_b.put_item({'hoge': 'fuga'})
8 何が良くないのか︖
9 よくある解決策 class TableA: def __init__(self, client): self._client = client
def put_item(self, item): self._client.put_item(TableName='tableA', Item=item) class TableB: def __init__(self, client): self._client = client def put_item(self, item): self._client.put_item(TableName='tableB', Item=item) import boto3 client = boto3.client('dynamodb’) def handler(event, context): table_a = TableA(client) table_a.put_item({'foo': 'bar'}) table_b = TableB(client) table_b.put_item({'hoge': 'fuga'})
10 そうはいっても • 現実世界のアプリはもっと複雑。呼び出し階層も深くなる • 呼び出し先の呼び出し先の呼び出し先…にclientを伝搬するのは⾯倒 • clientの処理化処理はもっと⾊々やることがある import boto3
client = boto3.client('dynamodb’) def handler(event, context): table_a = TableA(client) table_a.put_item({'foo': 'bar'}) table_b = TableB(client) table_b.put_item({'hoge': 'fuga'})
11 提案 Factoryクラスを使おう︕
12 実装例(簡易版) import boto3 class Boto3ClientFactory: # ⽣成したclientクラスのインスタンスをクラス変数に保持しておく _clients =
{} @classmethod def get_singleton_client(cls, service_name, **kwargs): # 対象サービスのclientクラスを⽣成済みならクラス変数のキャッシュから返却 # 複数リージョンを扱う場合はキャッシュキーにリージョンを含めるなど追加の考慮が必要 if service_name in cls._clients: return cls._clients[service_name] client = boto3.client(service_name, **kwargs) cls._clients[service_name] = client return client
13 Factoryクラスの追加実装例 • タイムアウト値の調整 • デフォルト値はLambda実⾏環境の設定値としては不適切 • connect_timeout:60, read_timeout:60 •
Event Systemを利⽤したフックの登録 • API呼び出し前にパラメータをクラス変数に保存 • 例外キャッチ時にクラス変数に保存したパラメータをログ出⼒ • ⾮シングルトンなclientクラス⽣成処理 • たまにはPromise.All的な実装が必要になることもある
14 Factoryクラスの利⽤例 client = Boto3ClientFactory.get_singleton_client('dynamodb') def handler(event, context): table_a =
TableA(client) table_a.put_item({'foo': 'bar'}) table_b = TableB(client) table_b.put_item({'hoge': 'fuga'}) def foo(): bar() def bar(): baz() def baz(): client = Boto3ClientFactory.get_singleton_client('dynamodb') table_a = TableA(client) table_a.put_item({'foo': 'bar'}) def handler(event, context): foo() タイムアウト値など適切に設定された clientクラスが1発で取得可能 呼び出し階層の深いところまでclientクラ スを引き回さなくて良くなる
15 Provisioned Concurrency利⽤時の注意 Boto3ClientFactory.get_singleton_client('dynamodb’) def handler(event, context): … Init処理の中でclientクラスの⽣成を「空打ち」しておく
16 初回のClientクラス⽣成処理は重い https://github.com/boto/botocore/blob/40d6219947f4d047088cbeb80f8f222f599f9c7c/botocore/loaders.py • 初回のclientクラス⽣成時はJSONファイルを読み込んで動的にクラスを⽣成するので「重い」 • 2回⽬以後はキャッシュを使う • Init処理の中でclientクラス向けのキャッシュを「暖気」することでProvisioned Concurrencyに最適化
https://github.com/boto/botocore/blob/40d6219947f4d047088cbeb80f8f222f599f9c7c/botocore/data/dynamo db/2012-08-10/service-2.json
17 以上 ありがとうございました
18