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
670
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
詳解 AWS Lambdaコールドスタート
iwatatomoya
0
1.3k
真のサーバーレスへ向けたAuroraの進化Aurora Limitless Database
iwatatomoya
1
4.1k
OpentelemetryでアプリケーションのObservabilityを強化しよう
iwatatomoya
0
830
AWS Lambdaは俺が作った
iwatatomoya
2
2k
SnapStartの未来についての期待と妄想
iwatatomoya
1
1.3k
実例から学ぶ! AWSを活用したシステム開発の勘所
iwatatomoya
1
2.9k
目指せ完全制覇!3大クラウドの認定資格制度と勉強方法について
iwatatomoya
0
9.1k
知らなくても困らないけど、知ると楽しいAWS Lambdaの裏側の世界
iwatatomoya
0
6.4k
RDSプロキシは未来を変えるか
iwatatomoya
2
25k
Other Decks in Programming
See All in Programming
労務ドメインを快適に開発する方法 / How to Comfortably Develop in the Labor Domain
yuki21
1
250
Desafios e Lições Aprendidas na Migração de Monólitos para Microsserviços em Java
jessilyneh
2
140
ECMAScript、Web標準の型はどう管理されているか / How ECMAScript and Web standards types are maintained
petamoriken
3
390
ブラウザ互換の重要性 - あらゆるユーザーに価値を届けるために必要なこと
yamanoku
0
110
Swift Concurrencyとレースコンディション
objectiveaudio
1
410
From Idea to IDE: Developing Plugins for Android Studio
thisaay
1
140
null or undefined
susisu
24
6.2k
Scala におけるコンパイラエラーとの付き合い方
chencmd
2
420
Kotlin 2.0 and Beyond
antonarhipov
2
150
オートマトン学習しろ / Do automata learning
makenowjust
3
130
僕が思い描くTypeScriptの未来を勝手に先取りする
yukukotani
9
2.4k
2024 컴포즈 정원사
jisungbin
0
150
Featured
See All Featured
Designing for humans not robots
tammielis
248
25k
Docker and Python
trallard
39
3k
Into the Great Unknown - MozCon
thekraken
29
1.4k
Ruby is Unlike a Banana
tanoku
96
11k
Fantastic passwords and where to find them - at NoRuKo
philnash
48
2.8k
Large-scale JavaScript Application Architecture
addyosmani
508
110k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
36
1.7k
Typedesign – Prime Four
hannesfritz
39
2.3k
Keith and Marios Guide to Fast Websites
keithpitt
408
22k
Code Review Best Practice
trishagee
62
16k
Art, The Web, and Tiny UX
lynnandtonic
294
20k
The World Runs on Bad Software
bkeepers
PRO
64
11k
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