1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PHP歴14年のソシャゲサーバーエンジニアがGoでガチャAPIを作ることにした話

1
Posted at

対象読者

  • PHP(特にLAMP構成)で長くやってきて、Goが気になっているエンジニア
  • ソシャゲ・高負荷系のバックエンド経験があり、次の技術スタックを模索している人
  • 「Goの入門記事は読んだけど、次に何を作ればいいかわからない」人

この記事は連載の第1回です。今回は「なぜGoなのか」と環境構築まで。次回から実装に入ります。

自己紹介

サーバーサイドエンジニアとして約14年、ほぼ一貫してPHP/LAMPスタックでソーシャルゲームのバックエンドを作ってきました。ガチャ、ランキング、イベントスパイク時のトランザクション処理など、いわゆる「高負荷との戦い」が主戦場です。インフラはAWSとAlibaba Cloudを両方運用してきました。

つまり、キャリアの大半が「PHPで高負荷を捌く」仕事です。そんな人間がなぜ今Goを学ぶのか、から書きます。

なぜ今、Goなのか

1. 求人市場のシフトを肌で感じた

最近、キャリアの棚卸しを兼ねて転職市場を眺めているのですが、バックエンドの求人でGoを採用している企業が明らかに増えています。SaaS、HRTech、ゲームバックエンドまで、モダンな開発体制を打ち出す企業ほどGo率が高い印象です。

一方でPHPの求人は「既存システムの保守・改修」寄りの文脈が増えてきました。PHP自体は今も現役ですが、「これから作るもの」の言語としてGoが選ばれるケースが増えているのは、求人票を見ていると否定しがたい流れです。

2. コンテナ時代との相性が良すぎる

PHPアプリをコンテナ化すると、だいたいこうなります。

  • PHP-FPM + Nginxの2プロセス構成(またはApache + mod_php)
  • ランタイム、拡張モジュール、Composer依存を含んだそれなりのサイズのイメージ
  • プロセスマネージャの設定チューニング

Goはビルドするとシングルバイナリが出てきます。極端な話、scratchイメージにバイナリを1個置くだけでコンテナが動く。イメージは数十MB以下、起動は一瞬。Kubernetesでのスケールアウトやサーバーレス環境との親和性が高いのは、この「ビルド成果物が自己完結している」性質によるところが大きいです。

長年PHPのデプロイとオートスケールの面倒を見てきた身としては、これは素直に羨ましい。

3. 高負荷ドメインの人間として、並行処理に期待している

ソシャゲのバックエンドは、イベント開始やガチャ更新の瞬間にトラフィックが数倍〜数十倍に跳ねます。PHPは基本「1リクエスト=1プロセス」のモデルなので、スパイク対策はプロセス数、コネクションプール、キャッシュ、キューイングといったアーキテクチャ側の工夫で吸収してきました。

Goにはgoroutineという軽量な並行処理の仕組みが言語レベルで組み込まれています。数千・数万の並行タスクを1プロセスで捌ける設計は、まさに自分が戦ってきた領域に効くはずで、これを自分の手で確かめたいというのが正直なモチベーションです。

4. 触ってみたら、PHP脳でも意外と入りやすかった

学習を始める前は「静的型付けでコンパイルが必要な言語」に身構えていたのですが、実際に触ると文法の心理的距離は思ったより近いです。

PHPの感覚 Goでの対応
$user = new User() user := User{} (:= で宣言と代入)
Laravel/CodeIgniterのルーター net/httpのServeMux(1.22以降はパスパラメータも標準対応)
Composer Go Modules(go mod)
連想配列 map[string]int など型付きのmap

もちろん型システム、エラーハンドリング(if err != nilの世界)、ポインタなど「PHPにない考え方」はあります。ただ、Webアプリを書くという目的に限れば、最初の一歩のハードルはかなり低いと感じました。

何を作るか: ガチャAPI

入門書の写経では続かないタイプなので、自分が一番詳しいドメインでAPIを作ることにしました。題材はガチャです。

リポジトリ: gacha-api-go(整備でき次第公開予定)

仕様(第1弾)

  • 重み付き抽選: レアリティごとに整数の重みを持たせる(合計100,000)。浮動小数点を使わないのは、確率表記との突合や検証のしやすさという運用上の理由から
  • 天井(pity)カウンター: 100連でSSR確定。カウンターは専用テーブルで管理
  • REST API: 単発ガチャ、10連ガチャ、天井カウンター参照、排出履歴の4エンドポイント
  • DB: MySQL 8.0

ガチャは「確率の正確性」「同時アクセス時の整合性」「監査可能なログ」が同時に要求される、実は言語の腕試しにちょうどいい題材です。実務で運用してきたドメインだからこそ、「PHPならこう書く、Goだとこうなる」の比較が具体的にできます。

将来的には同じ仕様をPHP 8でも実装して、コードとパフォーマンスを比較する記事も書く予定です。

環境構築: Docker + Go + MySQL 8

ローカルにGoを直接入れず、Dockerで完結させます。

ディレクトリ構成

gacha-api-go/
├── cmd/
│   └── api/
│       └── main.go
├── internal/
│   ├── handler/
│   ├── service/
│   └── repository/
├── docker/
│   └── mysql/
│       └── init.sql
├── docker-compose.yml
├── Dockerfile
├── go.mod
└── go.sum

cmd/ にエントリポイント、internal/ にアプリ本体という構成はGoコミュニティで広く使われている標準的なレイアウトです。PHPで言うと public/index.phpapp/ の関係に近いイメージです。

docker-compose.yml

services:
  api:
    build: .
    ports:
      - "8080:8080"
    volumes:
      - .:/app
    depends_on:
      db:
        condition: service_healthy
    environment:
      DB_DSN: "gacha:gacha@tcp(db:3306)/gacha_db?parseTime=true"

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: gacha_db
      MYSQL_USER: gacha
      MYSQL_PASSWORD: gacha
    ports:
      - "3306:3306"
    volumes:
      - db-data:/var/lib/mysql
      - ./docker/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 5s
      timeout: 5s
      retries: 10

volumes:
  db-data:

Dockerfile(開発用)

FROM golang:1.22

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . .

CMD ["go", "run", "./cmd/api"]

本番用にはマルチステージビルドでバイナリだけをコピーする構成にしますが、それは実装が進んでから別記事で扱います。

動作確認

docker compose up -d
docker compose exec api go version
# go version go1.22.x linux/amd64

docker compose exec db mysql -ugacha -pgacha gacha_db -e "SELECT 1;"

Goのコンテナからmysqlドライバ(go-sql-driver/mysql)でDBに接続できるところまで確認して、環境構築は完了です。

まとめと次回予告

  • Goを学ぶ理由: 求人市場のシフト、コンテナ親和性、並行処理への期待、そしてPHPからの学習コストが思ったより低いこと
  • 題材は自分の主戦場であるガチャAPI。重み付き抽選+天井カウンター
  • 環境はDocker + Go 1.22 + MySQL 8.0で構築

次回は本丸の重み付き抽選ロジックの実装です。整数の重み(合計100,000)を使った抽選アルゴリズムと、そのテーブル設計をGoでどう書くかを扱います。PHPで同じ処理を書いてきた人ほど「なるほど」と思える比較を入れる予定なので、興味があればフォローしてもらえると嬉しいです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?