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
Go in production - case of Gannoy -
Search
monochromegane
October 17, 2017
Technology
540
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Go in production - case of Gannoy -
fukuokago#9
https://connpass.com/event/68358/
monochromegane
October 17, 2017
More Decks by monochromegane
See All by monochromegane
適応的スパムフィルタのための軽量な類似メッセージカウンタ / jsai2026-adaptive-spam-filter
monochromegane
0
4.2k
ベクトル検索のフィルタを用いた機械学習モデルとの統合 / python-meetup-fukuoka-06-vector-attr
monochromegane
3
800
Claude Codeセッション現状確認 2026福岡 / fukuoka-aicoding-00-beacon
monochromegane
4
580
Go言語での実装を通して学ぶLLMファインチューニングの仕組み / fukuokago22-llm-peft
monochromegane
0
260
不確実性下における目的と手段の統合的探索に向けた連続腕バンディットの応用 / iot70_gp_rff_mab
monochromegane
2
410
なめらかなシステムと運用維持の終わらぬ未来 / dicomo2025_coherently_fittable_system
monochromegane
0
25k
ベクトル検索システムの気持ち
monochromegane
38
13k
Go言語での実装を通して学ぶ、高速なベクトル検索を支えるクラスタリング技術/fukuokago-kmeans
monochromegane
1
310
Go言語でターミナルフレンドリーなAIコマンド、afaを作った/fukuokago20_afa
monochromegane
2
370
Other Decks in Technology
See All in Technology
“ID沼入口” - 基本とセキュリティから始める、考え続けるためのID管理技術勉強会 告知&イントロ
ritou
0
430
NDIAS CTF 2026 問題解説会資料
bata_24
0
180
勉強会企画をアプリで構造化してみた 〜そこで見えた、AIとの付き合い方〜 / I've structured a study group plan using an app.
pauli
0
320
Zoom2Youtube.Claude
kawaguti
PRO
2
440
Agentic AI 時代のテスト手法: Kiro とはじめるプロパティベーステスト (AWS Summit Japan 2026 | DEV212)
ymhiroki
0
210
フルカイテン株式会社 エンジニア向け採用資料
fullkaiten
0
11k
FinOps X 2026 Recap from Engineer Side #JapanFinOps
chacco38
0
260
背中から、背中へ /paying forward to community
naitosatoshi
0
230
金融の未来を考える / Thinking About the Future of Finance
ks91
PRO
0
160
Control Planeで育てるBtoB SaaSの認証基盤 - SRE NEXT 2026
pokohide
1
450
初めてのDatabricks勉強会
taka_aki
2
240
End-to-Endで考える信頼性 —LINEアプリにおけるクライアント開発×SRE連携の実践
maruloop
3
1.4k
Featured
See All Featured
Mind Mapping
helmedeiros
PRO
1
280
Music & Morning Musume
bryan
47
7.3k
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
500
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.3k
KATA
mclloyd
PRO
35
15k
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
The Curious Case for Waylosing
cassininazir
1
430
How to Talk to Developers About Accessibility
jct
2
280
What's in a price? How to price your products and services
michaelherold
247
13k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
440
Transcript
- case of Gannoy - ࡾ༔հ / Pepabo R&D Institute,
GMO Pepabo, Inc. 2017.10.17 Fukuoka.go#9 Go in production
ϓϦϯγύϧΤϯδχΞ ࡾ ༔հ / @monochromegane 2 http://blog.monochromegane.com Yusuke Miyake ϖύϘݚڀॴ
ݚڀһ
1. Goຊ൪ӡ༻ͷཁ݅ 2. Goຊ൪ӡ༻ͷ࣮ݱ 3. ·ͱΊ 3 ࣍
1. GannoyʹΈΔ Goຊ൪ӡ༻ͷཁ݅
Gannoy Approximate nearest neighbor search server and dynamic index written
in Golang. https://github.com/monochromegane/gannoy
Similar images search system using Gannoy 6 Features Similar items
Gannoy [2048]float64 query by http find similar features mapping similar features to items response Deep CNN index Features [2048]float64 Deep CNN register by http
• HTTP based Approximate nearest neighbor search server • Using
labstack/echo • Go 1.8+ 7 Gannoy
Goຊ൪ӡ༻ͷཁ݅
• Graceful restart • Daemonize • Monitoring • Log rotation
9 Goຊ൪ӡ༻ͷཁ݅ • Configuration • Build • Deploy
2. GannoyʹΈΔ Goຊ൪ӡ༻ͷ࣮ݱ
Graceful restart 11 go-server-starter + http.Server#Shutdown() import "github.com/lestrrat/go-server-starter/listener" e :=
echo.New() listeners, err := listener.ListenAll() if err != nil && err != listener.ErrNoListeningTarget { fmt.Fprintln(os.Stderr, err) os.Exit(1) } e.Listener = netutil.LimitListener(listeners[0], opts.MaxConnections) Listen from start_server socket.
Graceful restart 12 go-server-starter + http.Server#Shutdown() go func() { if
err := e.Start(""); err != nil { e.Logger.Info("Shutting down the server") } }() sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, sig) <-sigCh ctx, cancel := context.WithTimeout(context.Background(), time.Duration(opts.ShutDownTimeout)*time.Second) defer cancel() if err := e.Shutdown(ctx); err != nil { e.Logger.Fatal(err) } Start server as goroutines. Wait SIGTERM. Graceful shutdown using http.Server.
Daemonize 13 Systemd [Unit] Description=Gannoy DB ConditionPathExists=/usr/bin/start_server ConditionPathExists=/usr/bin/gannoy-db After=network.target [Service]
User=gannoy Group=gannoy Type=simple PIDFile=/var/run/gannoy/server_starter.pid ExecStart=/usr/bin/start_server --port 8080 --pid-file /var/run/gannoy/server_starter.pid -- / usr/bin/gannoy-db -c /etc/gannoy/gannoy-db.toml ExecReload=/bin/kill -HUP $MAINPID ExecStop=/bin/kill -TERM $MAINPID [Install] WantedBy=multi-user.target gannoy-db.service
Monitoring 14 health-check endpoint + Consul e.GET("/health", func(c echo.Context) error
{ return c.NoContent(http.StatusOK) }) { "service": { (snip) "port": 80, "checks": [ { "script": "/usr/bin/check-http -u http://localhost/health", "interval": "30s" } ] } } health-check endpoint consul.d/gannoy.json
Log ratation 15 logrotate /var/log/gannoy/gannoy-db.log { daily rotate 7 missingok
notifempty compress postrotate kill -HUP `cat /var/run/gannoy/server_starter.pid` endscript } gannoy-db.logrotate reopen logfile.
Configuration 16 monochromegane/conflag // Parse option from args and configuration
file. conflag.LongHyphen = true conflag.BoolValue = false parser := flags.NewParser(&opts, flags.Default) _, err := parser.ParseArgs(os.Args[1:]) if err != nil { os.Exit(1) } if opts.Config != "" { if args, err := conflag.ArgsFrom(opts.Config); err == nil { if _, err := parser.ParseArgs(args); err != nil { os.Exit(1) } } } _, err = parser.ParseArgs(os.Args[1:]) if err != nil { os.Exit(1) } Read option from config. Overwrite option from args. data-dir = "/var/lib/gannoy" log-dir = "/var/log/gannoy" lock-dir = "/var/run/gannoy" server-starter = true auto-save = true gannoy-db —data-dir=“data”
Configuration 17 monochromegane/conflag http://blog.monochromegane.com/blog/2015/05/30/conflag/
Build 18 rpmbuild + docker-compose . !"" Dockerfile.rpmbuild !"" docker-compose.yml
!"" rpmbuild # !"" RPMS # # $"" x86_64 # # $"" gannoy-0.0.1-8.x86_64.rpm # !"" SOURCES # # !"" gannoy-db.logrotate # # !"" gannoy-db.service # # $"" gannoy-db.toml # $"" SPECS # $"" gannoy.spec $"" version.go version: '2' services: gannoy-rpmbuild: build: context: . dockerfile: Dockerfile.rpmbuild command: cp /root/rpmbuild/RPMS/x86_64/ gannoy-0.0.1-8.x86_64.rpm /tmp/rpmbuild/RPMS/ x86_64/. volumes: - .:/tmp:rw RUN rpmbuild -bb /root/rpmbuild/SPECS/gannoy.spec $ docker-compose build gannoy-rpmbuild $ docker-compose run gannoy-rpmbuild docker-compose.yml Dockerfile.rpmbuild
Deploy (and test) 19 Puppet + Serverspec class gannoy::install {
include ::go_start_server $rpm = 'gannoy-0.0.1-8.x86_64.rpm' file { "/usr/local/src/${rpm}": ensure => present, source => "puppet:///modules/gannoy/${rpm}", mode => '0755', owner => 'root', notify => Package['gannoy'], } -> package { 'gannoy': ensure => '0.0.1-8', source => "/usr/local/src/${rpm}", provider => rpm, } (snip) } (snip) describe service('gannoy-db') do it { should be_enabled } end describe package('gannoy') do it { should be_installed.with_version('0.0.1-8') } end (snip)
·ͱΊ
• σʔϞϯԽ͕ඞཁͳGoΞϓϦͷຊ൪ӡ༻όΠφϦҎ֎ʹඞཁͳ ϑΝΠϧ͕͋ΔͷͰύοέʔδϯάͨ͠΄͏͕औΓճָ͕͠ • ΦϓγϣϯͱઃఆϑΝΠϧͷڞ௨Խʹconflag͕ศར • ϕετϓϥΫςΟεࡧதɻσΟεΧογϣϯ͠·͠ΐ͏ɻ 21 ·ͱΊ
ݚڀһɺੵۃతʹืूதʂ http://rand.pepabo.com/