Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
go-sqlite3を使ってCloud Spannerエミュレーターを作ってみた / Clou...
Search
kazegusuri
February 10, 2020
Technology
6.8k
5
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
go-sqlite3を使ってCloud Spannerエミュレーターを作ってみた / Cloud Spanner emulator with go-sqlite3
kazegusuri
February 10, 2020
More Decks by kazegusuri
See All by kazegusuri
handy-spanner GCPUG
kazegusuri
4
2.1k
Open SKT: メルペイ開発の裏側 / builderscon tokyo 2019 Open SKT
kazegusuri
22
28k
Keep watching and extending features of gRPC
kazegusuri
3
2.7k
Testing with microservices in merpay
kazegusuri
10
11k
Real World Mercari API Architecture
kazegusuri
1
6.5k
gRPC and REST with gRPC in practice
kazegusuri
19
8.2k
Fluentdで始めるPrometheus / Prometheus Tokyo Meetup #1
kazegusuri
1
2k
GRPCの実践と現状での利点欠点 / Go Conference 2016 Spring
kazegusuri
44
32k
OutputとBufferedOutputの間の何か
kazegusuri
2
3.5k
Other Decks in Technology
See All in Technology
なぜ「決定性」が 決定的に重要なのか? Durable Execution 基盤の数理的理解 #serverlessjp / ServerlessDays Tokyo 2026
ytaka23
3
1.1k
.NET WebAssemblyで実現するクライアントサイドAI推論:NuGetからViteまで、2つのエコシステムを繋ぐビルド戦略
yamachu
1
430
え、こんなに早く改修できるの?──新人エンジニアとスクラムマスターの2人が語る、AI×アジャイル開発の現場
ysasago
2
640
技術的負債から考える、AI時代のエンジニアリング投資 — ビズリーチの技術的負債と向き合った経験から、変更し続けられるソフトウェアを考える/ technical-debt-con2026
visional_engineering_and_design
4
3.5k
Slack上でインフラをトラブルシュートする! Agentic Platform Engineeringの第一歩
teru0x1
5
1.8k
【技術的負債conf】事業成長に伴う技術的負債の説明責任とAIによるモニタリング、認知的負債について
i35_267
3
2k
Azure Serverless 2026:Production-ready な AI エージェント基盤 / Azure Serverless 2026: Production-Ready AI Agent Platform
miyake
2
500
人間はどの意思決定を手放せるのか
kawasima
15
7.9k
「どのログを見ればいい?」 から始めた サーバーレス障害解析
y_waka1
1
120
AI時代、データエンジニアが一番おもろい
genshun9
0
680
AI 時代のスタートアップエコシステ厶から考究する技術的負債との向き合い方
m3m0r7
PRO
3
2.5k
品質と信頼性を地続きにする
grimoh
2
900
Featured
See All Featured
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.3k
Fashionably flexible responsive web design (full day workshop)
malarkey
409
67k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
570
From π to Pie charts
rasagy
1
380
How GitHub (no longer) Works
holman
316
150k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
4
1.2k
Typedesign – Prime Four
hannesfritz
42
3.2k
Odyssey Design
rkendrick25
PRO
2
810
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
340
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
430
Ten Tips & Tricks for a 🌱 transition
stuffmc
1
230
Transcript
go-sqlite3を使って Cloud Spannerエミュレータを つくってみた mercari.go #13
@kazegusuri • Merpay Backend Engineer • Architect Team 2015/11 2017/01
2018/01 SRE & Platform Platform Architect
トークの概要 handy-spannerの説明をしながら 01 SQLiteの話をして Goでどうやっているのか 03 02
Cloud Spanner • Google Cloud Platformが提供するフルマネージドデータベース ◦ スキーマ,トランザクション,強整合性,スケーラブル • Google
Cloud Client Libraryを使ってアクセス ◦ https://github.com/googleapis/google-cloud-go • gRPCでAPIを提供 ◦ gRPCの定義も公開されている ◦ https://github.com/googleapis/googleapis
handy-spanner • Cloud Spannerの(非公式)エミュレーター (Go) ◦ 現状では一番再現率が高いはず ◦ https://github.com/gcpug/handy-spanner ◦
https://speakerdeck.com/kazegusuri/handy-spanner-gcpug • SQLパーサーはmemefish (Go) ◦ Cloud SpannerのSQLを正確にパース可能 ◦ https://github.com/MakeNowJust/memefish • ストレージはSQLite
SQLite • "SQLデータベースエンジンを実装したインプロセスライブラリ" ◦ Full-Featured SQL ◦ Extensionによる機能拡張 • mattn/go-sqlite3
◦ https://github.com/mattn/go-sqlite3 ◦ Goのsqlite3用driver ◦ database/sqlから操作可能
Cloud Spannerエミュレーター • gRPCのAPIを実装してCloud Spannerの挙動を再現する • Google Cloud Client Libraryからアクセス先を切り替えて利用する
App Google Cloud Client Library Google Cloud Spanner handy-spanner SQLite
gRPC gRPC
Spannerの機能は大きく3つ • RPCによるデータの参照・更新 ◦ e.g. StreamingRead, Mutation(Commit) ◦ SQLiteのRead/Write(クエリ)に変換 •
SQLによるデータの参照・更新 ◦ e.g. ExecuteStreamingSql, ExecuteSql(DML) ◦ SQLiteのRead/Write(クエリ)に変換 • トランザクション管理 ◦ e.g. BeginTransaction, Commit, Rollback ◦ SQLiteのトランザクションとして管理
handy-spanner StreamingRead “SELECT FirstName, LastName FROM Singers WHERE FirstName =
‘foo’” SQLite SQLite SQL ReadRequest Table = Singers Columns = FirstName, LastName KeySet = ‘foo’ クエリ生成
handy-spanner ExecuteStreamingSql “SELECT * FROM Singers WHERE FirstName = ‘foo’”
SELECT * FROM WHERE Singers = FirstName ‘foo’ “SELECT * FROM Singers WHERE FirstName = ‘foo’” SQLite Spanner SQL AST SQLite SQL クエリ生成 クエリパース
何がSQLiteで難しいの? • SQLiteにないデータ型(配列, 構造体) • SQLiteにない操作の実現 (UNNESTなど) • Cloud Spannerの関数
• トランザクション
配列と構造体の実装 • SQLiteのJSON型を利用 • 配列はJSON ARRAY ◦ e.g. [1, 2,
3], ["foo", "bar"] • 構造体はJSON OBJECT ◦ ただしフィールドに順序があるのでkey, valueを配列で扱う ◦ e.g. {"keys": ["x", "y"], "values": [1, 2]}
配列と構造体は組み合わせ可能 • 配列の構造体の配列の構造体みたいなのが可能 ◦ もちろん配列の要素型や構造体のフィールドは任意 • 読み書き前に型の定義は正確にわかっている ◦ e.g. ARRAY<STRUCT<x
INT64, y ARRAY<STRING>>> • DataValue型 ⇔ JSONの相互変換を実現したい ◦ DataValueは型定義と値を保持したstruct []struct { x int64 y []string } type DataValue struct { Type DataType Value interface{} } type DataType struct { // INT64, STRING... }
JSONとの相互変換 • json.Marshalerとjson.Unmarshalerを実装する ◦ DataValue型からJSONへの変換処理をMarshaler ◦ JSONからDataValue型への変換処理をUnmarshaler • 型の定義を見ながら再帰的に展開していく func
(v *DataValue) MarshalJSON() ([]byte, error) { } func (v *DataValue) UnmarshalJSON([]byte) error { }
データベースから透過的に扱いたい • database/sql.Scannerとdatabase/sql/driver.Valuerを実装する ◦ Scannerはデータベースから値を取り出す(Scan)するとき ◦ Valuerはデータベースに値を書き込むとき • 実際の値(JSON)への変換はMarshal/Unmarshalにまかせる func
(v *DataValue) Value() (driver.Value, error) { b, err := v.MarshalJSON() if err != nil { … } return driver.Value(string(b)), nil } func (v *DataValue) Scan(src interface{}) error { s, _ := src.(string) return v.UnmarshalJSON([]byte(s)) }
関数 • Cloud Spannerには大量の関数がある ◦ 集計関数, 数学関数, 文字列関数, 配列関数, タイムスタンプ関数...
◦ https://cloud.google.com/spanner/docs/functions-and-operators • 全ての関数がSQLiteに存在する訳ではない ◦ ABS() など基本的なものはある ◦ 配列関数や, 文字列関数などほとんどの関数はない
関数 • リテラルやパラメータなどは入力値がわかるのでクエリ変換可能 • データベースの値に対する操作はできることに制限がある… SELECT DATE_ADD( DATE "2008-12-25", INTERVAL
5 DAY); SELECT DATE "2008-12-30"; クエリ変換 SELECT DATE_ADD( @date, INTERVAL 5 DAY); @date = "2008-12-25" SELECT DATE "2008-12-30"; クエリ変換 SELECT DATE_ADD( tbl.created_at, INTERVAL 5 DAY); クエリ変換 Spanner SQL SQLite SQL
SQLiteのデータを操作したい • SQLite上のデータはアプリケーションから直接操作できない ◦ 出力時にScanner, 入力時にValuerを通すことで加工はできる ◦ JSONのようにExtensionによりSQLite側に直接ロジックも追加可能 Extension SQLite
handy-spanner JSON driver Scanner Valuer
SQLiteのカスタム関数 • SQLiteのクエリからGoの関数が呼び出せる ◦ 任意の値を受け取って、任意の値を返す関数 Extension SQLite handy-spanner JSON driver
Scanner Valuer Function
カスタム関数の実装 • Goの関数の引数と戻り値がカスタム関数と一致 ◦ interface{}で任意の型も可能 ◦ 可変長引数も可能 • エラーも返せる SIGN()
関数の実装 SELECT SIGN(3) // => 1 SELECT SIGN(-2) // => -1
EXTRACT() 関数の実装 カスタム関数の実装
カスタム関数の登録 • SQLiteドライバーを再登録する ◦ github.com/mattn/go-sqlite3.SQLiteConnのRegisterFuncで関数を登録 • database/sql.Openで登録したドライバを指定
カスタム関数を使えば • DATE_ADDの機能をX_DATE_ADDと登録した場合 SELECT DATE_ADD( DATE "2008-12-25", INTERVAL 5 DAY);
クエリ変換 SELECT DATE_ADD( @date, INTERVAL 5 DAY); @date = "2008-12-25" クエリ変換 SELECT DATE_ADD( tbl.created_at, INTERVAL 5 DAY); クエリ変換 Spanner SQL SQLite SQL SELECT X_DATE_ADD( DATE "2008-12-25", INTERVAL 5 DAY); SELECT X_DATE_ADD( @date, INTERVAL 5 DAY); @date = "2008-12-25" SELECT X_DATE_ADD( tbl.created_at, INTERVAL 5 DAY);
カスタム関数を使えば • 仮想的にデータ型も定義可能なはず! • 例えば、位置情報型(Geometry) ◦ SQLiteには"(100, 200)"のような文字列で保存 ◦ 比較(=)などのオペレーターは関数に置き換える
SELECT tbl.pos1 = tbl.pos2 クエリ変換 SELECT GEO_EQUAL(tbl.pos1, tbl.pos2)
カスタム関数を使う場合の注意 • rows.Err()のチェックは必須 ◦ カスタム関数でエラーが発生時にScanやク エリはエラーにならない
時間があればトランザクションの難しさを… • SQLiteはスキーマレベル Lock ◦ 誰かがロックを取るの他の全員がロック待ちになる • Shared Cache Modeにするとテーブルレベル
Lock ◦ 誰かがテーブルを読み込むとRead Lock ◦ 誰かがテーブルを書き込むとWrite Lock ◦ Read Lock中はReadはできるがWriteはできない ◦ Write中は他の誰もReadできない • ずっとReadしているやつがいるといつまでもWriteできない…!
handy-spannerのトランザクション管理 • SQLiteのトランザクションがどのテーブルをどうロックしているか全部管理 • トランザクションの優先度をつける ◦ 必要に応じて任意のトランザクションを終了させる ◦ 通常ならデッドロックするケースでも動くようになる
まとめ • エミュレーションは面白い ◦ エミュレーション対象のことがわかる • SQLiteのハックは面白い ◦ Goの拡張だけでなくC拡張も使えばもっとできることは広がる •
開発デバッグ目的だけじゃなくプロダクション用途にも発展可能 ◦ S3互換ストレージのような ◦ CQL(Cassandra)とかJQL(Jira) みたいなクエリベース ◦ Redisみたいなコマンドベース