streampackチームの Tana です。
最近は、いろんな案件のリリース納期・作業が重なったり、現場でライブ配信サポートしたり、
バタバタしてましたが、やっと少し落ち着いて来たところです。
今回は、streampack の動画配信とは少し異なりますが、
アプリケーション周りに関して、共有できればと思います。
streampackとは?
VOD & LIVE を提供する動画配信プラットフォームです。
AWSを活用しモノシリックな Rails で作られており、
動画アップロード、変換から配信プレーヤーまで提供しています。
また下記などのいろんな機能などを保持し Feature Flag で案件に応じて制御しているのが特徴です。
- SaaSベースのマルチチャンネル機能
- VAST動画広告連携
- Cognitive系APIを使った動画解析とプレイヤー連携
- Analytics連携 ・・・ etc
最近の課題
オレオレなモノシリックなシステムの運用は楽ですが、さすがにずっと同じシステムで運用し続けるも、メンテが厳しくなって来ますし、一気に変化するのもパワーがいるので、少しずつ破壊し、新しいものを取り入れてたらと考えているところです。
まだ、JS では Rails Way に沿った CoffeeScript で書かれていたりするなど。。(汗
新しい取り組み
新しい案件的にLive関連のためにパフォーマンスが求められるため、
POC段階ではありますが、streampack 本体とは分離して、Go APIで提供できればと考えてます。
(Rails を使ってた多くのリーディングカンパニーが go を採用しているってのが大きいですがw)
Rails と比較しつつ話していきます。
Go言語の特徴
Go といえば、下記があるかと思います。
- パフォーマンス
- シンプルコード
- 並列処理
以前は C++ の経験はあるものの、スクリプト言語に慣れてしまってたものには少し慣れが必要です。
インストール
とりあえず、Macのローカル環境で動くものを提供。
$ brew install go --cross-compile-common
環境変数
export GOPATH=$HOME/go export PATH=$PATH:$GOPATH/bin
パッケージ
リモートパッケージの取得は go get xxx
を使って取得します。
下記は sql driver をインストールします。$ go get github.com/go-sql-driver/mysql
ruby でいう $ gem install mysql2
のようなものですね。
インストールされたパッケージは環境変数に設定した箇所に配置されます。
$HOME/go/pkg/darwin_amd64/github.com/xxx
開発環境
エディタは Atom で下記のプラグインをインストール
- go-plus
- go-debug
syntaxエラーを検知したり、ブレークポイントしてデバックしやすいようにします。
Rails console と同様に REPL も欲しいため、 gore も入れます。
文法に慣れるまでは playgroud で試すのが良さそうです。
https://play.golang.org/
DB Migration
DBの操作やMigrationなどは Rails の Active Record(ORM) と同様な機能が欲しいので
GORM で試します。事前に GORM のパッケージもインストールしておきます。
$ go get github.com/jinzhu/gorm
基本的な操作は下記にあります。
http://doc.gorm.io/
videoテーブル作成するために定義
video.go
type Video struct { gorm.Model Title string }
と定義し下記を実行すると、テーブルを作成してくれます。
video.go
Gorm.AutoMigrate(&Video{})
gorm.Model
は自動で id, created_at, updated_at, deleted_at(Soft delete) を作成してくれます。
DB接続
video.go
var DB *gorm.DB func initDB() { var err error DB, err = gorm.Open("mysql", "root:root@tcp(127.0.0.1:3306)/go_development?charset=utf8&parseTime=True&loc=Local") if err != nil { log.Fatal(err) } }
gorm.OpenにてDBの接続情報を定義します。いずれは Rails のように database.yml みたいに外だしした方が良さそうです。またグローバルで使えるように DB というglobal変数を定義します。先頭が大文字である必要があるので注意です。
GORMを使ったDB操作
特定のIDから取得
#ruby Video.find(id) #go DB.Find(&video, id)
IDの更新
#ruby video = Video.find(id) video.title = 'title' #go var video Video DB.Find(&video, id) video.Title = title DB.Save(video)
う〜ん、構造体を定義して参照しないといけないのはちょっと慣れが必要です。
API Framework
Restful形式のAPIは必須としたいため、あまり独自仕様にならないように gin と言うものを使います。お酒の名前のフレームワークが多いようです。
https://github.com/gin-gonic/gin
video.go
func main() { router := SetupRouter() router.Run(":8080") } func SetupRouter() *gin.Engine { router := gin.Default() v1 := router.Group("api/v1") { v1.GET("/videos", List) v1.GET("/videos/:id", Show) v1.POST("/videos", Create) v1.PUT("/videos/:id", Update) v1.DELETE("/videos/:id", Delete) } return router }
あとは、それぞれのメソッドを定義します。
Rails でいう routes.rb になります。 Railsの方が resource を使って一括で定義できるので楽そうです。
routes.rb
resource :video
それぞれの routing での関数を定義して、処理を書いていきます。
video.go
func Create(c *gin.Context) { title := c.Query("title") video := Video{Title: title} DB.Create(&video) c.JSON(http.StatusOK, gin.H{"message": "Created"}) } func Show(c *gin.Context) { id := c.Param("id") video := Video{} DB.Find(&video, id) c.JSON(http.StatusOK, video) } ... 省略 ...
c.Query はパラメータから取得
c.Param はURIから取得
Run – 実行
下記を実行し Postman などを使ってアクセスします。
$ go run video.go
200が返ってきて、DBが正常に保存されて入れば基本処理はOKそうです。
結論
学習コストはかかりますが、何よりも起動が早く、シンプルなため短期間でAPIサービスを作れそうなのが良さそうです。データが少ないとはいえ、APIレスポンスが早いのは Rails に比べるとかなりポイント高いです。
まだ、実戦で使えるために、継続的に試していく必要はありますが、今後もアップデートしていきたいと思います。