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{})

videos_table.png

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

video_go_—___Desktop_goapi.png

200が返ってきて、DBが正常に保存されて入れば基本処理はOKそうです。

結論

学習コストはかかりますが、何よりも起動が早く、シンプルなため短期間でAPIサービスを作れそうなのが良さそうです。データが少ないとはいえ、APIレスポンスが早いのは Rails に比べるとかなりポイント高いです。
まだ、実戦で使えるために、継続的に試していく必要はありますが、今後もアップデートしていきたいと思います。

元記事はこちら

streampackでGo