Skip to content

Commit

Permalink
Feature/fix webapp bottlenecks3 (#133)
Browse files Browse the repository at this point in the history
* クライアントの人気判定, シナリオ整理
* 予約枠テーブル
* hostヘッダではなくURLパラメータから取る
* docker-compose分割
* スパム判定修正
* NGワードにマッチする過去投稿を削除するように
  • Loading branch information
tukeJonny committed Oct 30, 2023
1 parent a3fa1a5 commit 8f85800
Show file tree
Hide file tree
Showing 31 changed files with 9,164 additions and 240 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/bench-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ jobs:
- name: Setup containers(mysql,pdns,webapp)
working-directory: ./development
run: |
sudo docker compose -f docker-compose-go.yml down --volumes
sudo docker compose -f docker-compose-go.yml up -d --build
sudo docker compose -f docker-compose-go.yml ps
sudo docker compose -f docker-compose-go.yml -f docker-compose-common.yml down --volumes
sudo docker compose -f docker-compose-go.yml -f docker-compose-common.yml up -d --build
sudo docker compose -f docker-compose-go.yml -f docker-compose-common.yml ps
# bench
- name: "[bench] Get deps"
Expand All @@ -45,7 +45,7 @@ jobs:
env:
TZ: Asia/Tokyo
run: |
go test -v ./...
go test -p=1 -v ./...
- name: "[bench] Benchmark"
working-directory: ./bench
Expand Down
2 changes: 1 addition & 1 deletion bench/cmd/bench/bench.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ var run = cli.Command{
lgr.Info("webappの初期化を行います")
initClient, err := isupipe.NewClient(
agent.WithBaseURL(config.TargetBaseURL),
agent.WithTimeout(30*time.Second),
agent.WithTimeout(1*time.Minute),
)
if err != nil {
return cli.NewExitError(err, 1)
Expand Down
13 changes: 8 additions & 5 deletions bench/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package config
const (
// NOTE: あまり並列度高く長い時間ベンチさせると、ポートが枯渇する
// FIXME: 2以上にすると、シナリオの実装上、ランダムに選ばれたlivestream_idが重複したworker fnが同時に走り、
// POST /livestream/:livestream_id/enter が重複した配信に対して行われ、
// テーブルのUNIQUE制約(user_id-livestream_id)を侵す可能性がある
// 対策としては、アルゴリズム側で必ず重複しないように調整するか、
// worker parallelismを1にしつつ、視聴者のシミュレータをgoroutineで吐き出して並行性を担保する
// とりあえず後者で対応
//
// POST /livestream/:livestream_id/enter が重複した配信に対して行われ、
// テーブルのUNIQUE制約(user_id-livestream_id)を侵す可能性がある
// 対策としては、アルゴリズム側で必ず重複しないように調整するか、
// worker parallelismを1にしつつ、視聴者のシミュレータをgoroutineで吐き出して並行性を担保する
// とりあえず後者で対応
//
// DefaultBenchmarkerParallelism = 5
// シナリオテストのタイムアウト[秒]
// ScenarioTestTimeoutSeconds = 3
Expand All @@ -16,5 +18,6 @@ const (
var (
// 広告費用
// 1~10で設定
// NOTE: webappのinitializeによって更新される
AdvertiseCost = 1
)
3 changes: 3 additions & 0 deletions bench/internal/config/logger.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
package config

// NOTE: ベンチマーカー実行ログを当該パスに書き出す
//
// supervisorがそれを拾い、ポータルにPOSTする
var LogPath string
12 changes: 12 additions & 0 deletions bench/internal/config/reservation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package config

// 2024-04-01 01:00:00
// NOTE: 2024-04-01 00:00:00 ~ 2024-04-01 01:00:00は初期データで予約済み
const BaseAt = 1711900800

// 同時配信枠数
// NOTE: ベンチマーカー調整項目
const NumSlots = 2

// NOTE: 初期データ予約済みの1時間分を引く必要がある
const NumHours = (24 * 365) - 1
1 change: 1 addition & 0 deletions bench/internal/config/slack.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
package config

// FIXME: workerの実装がまだなのでSlack通知なにもしてない. 11月前半のつなぎ込みで発砲試験する
var SlackWebhookURL string
8 changes: 7 additions & 1 deletion bench/internal/config/webapp.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package config

import "fmt"
import (
"fmt"
"time"
)

const (
TargetPort = 8080
)

// FIXME: httpsになりそうなので、スキームも置き換えられるようにする
var (
TargetBaseURL string = fmt.Sprintf("http://pipe.u.isucon.dev:%d", TargetPort)
TargetNameserver string = "127.0.0.1"
DNSPort int = 1053
)

var RequestTooSlowThreshold = 500 * time.Millisecond
6 changes: 2 additions & 4 deletions bench/internal/scheduler/reservation_scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@ import (
"sync"

"github.com/biogo/store/interval"
"github.com/isucon/isucon13/bench/internal/config"
)

// 同時配信枠数
const NumSlots = 2

var ErrNoReservation = errors.New("条件を満たす予約がみつかりませんでした")

var (
ReservationSched = mustNewReservationScheduler(1711900800, NumSlots, (24*365)-1)
ReservationSched = mustNewReservationScheduler(config.BaseAt, config.NumSlots, config.NumHours)
)

func init() {
Expand Down
8 changes: 8 additions & 0 deletions bench/isupipe/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,11 @@ func assertSearchLivestream() {
}

// FIXME: いくらか画面表示内容に問題がないことをチェックする

// moderateにより登録されたNGワードが含まれるコメントが残っていたら失格
// FIXME: ベンチ側では、ngワードのmoderate後に含まれる投稿を見つけたら失格扱いにする
func assertModeratedComment() {
// NGワード一覧取得

// 1つづつ検査
}
13 changes: 11 additions & 2 deletions bench/isupipe/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ import (
var ErrCancelRequest = errors.New("contextのタイムアウトによりリクエストがキャンセルされます")

type Client struct {
agent *agent.Agent
username string
agent *agent.Agent
username string
isPopular bool

// ユーザカスタムテーマ適用ページアクセス用agent
// ライブ配信画面など
Expand Down Expand Up @@ -79,6 +80,14 @@ func (c *Client) LoginUserName() (string, error) {
return c.username, nil
}

func (c *Client) IsPopular() bool {
return c.isPopular
}

func (c *Client) IsTooSlow(startTime, endTime time.Time) bool {
return endTime.Sub(startTime) >= config.RequestTooSlowThreshold
}

// sendRequestはagent.Doをラップしたリクエスト送信関数
// bencherror.WrapErrorはここで実行しているので、呼び出し側ではwrapしない
func sendRequest(ctx context.Context, agent *agent.Agent, req *http.Request) (*http.Response, error) {
Expand Down
21 changes: 16 additions & 5 deletions bench/isupipe/client_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/isucon/isucon13/bench/internal/bencherror"
"github.com/isucon/isucon13/bench/internal/benchscore"
"github.com/isucon/isucon13/bench/internal/config"
"github.com/isucon/isucon13/bench/internal/scheduler"
)

type User struct {
Expand Down Expand Up @@ -49,7 +50,7 @@ type Theme struct {
DarkMode bool `json:"dark_mode"`
}

func (c *Client) GetTheme(ctx context.Context, streamer *User, opts ...ClientOption) error {
func (c *Client) GetStreamerTheme(ctx context.Context, streamer *User, opts ...ClientOption) (*Theme, error) {
var (
defaultStatusCode = http.StatusOK
o = newClientOptions(defaultStatusCode, opts...)
Expand All @@ -59,23 +60,30 @@ func (c *Client) GetTheme(ctx context.Context, streamer *User, opts ...ClientOpt
endpoint := fmt.Sprintf("/api/user/%s/theme", streamer.Name)
req, err := c.agent.NewRequest(http.MethodGet, endpoint, nil)
if err != nil {
return bencherror.NewInternalError(err)
return nil, bencherror.NewInternalError(err)
}
resp, err := sendRequest(ctx, c.agent, req)
if err != nil {
return err
return nil, err
}
defer func() {
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
}()

if resp.StatusCode != o.wantStatusCode {
return bencherror.NewHttpStatusError(req, o.wantStatusCode, resp.StatusCode)
return nil, bencherror.NewHttpStatusError(req, o.wantStatusCode, resp.StatusCode)
}

var theme *Theme
if resp.StatusCode == defaultStatusCode {
if err := json.NewDecoder(resp.Body).Decode(&theme); err != nil {
return nil, err
}
}

benchscore.AddScore(benchscore.SuccessGetUserTheme)
return nil
return theme, nil
}

func (c *Client) DownloadIcon(ctx context.Context, user *User, opts ...ClientOption) error {
Expand Down Expand Up @@ -223,6 +231,8 @@ func (c *Client) Register(ctx context.Context, r *RegisterRequest, opts ...Clien
return user, nil
}

// ログインを行う.
// NOTE: ログイン後はログインユーザとして振る舞うので、各種agentやユーザ名、人気ユーザであるかの判定フラグなどの情報もここで確定する
func (c *Client) Login(ctx context.Context, r *LoginRequest, opts ...ClientOption) error {
var (
defaultStatusCode = http.StatusOK
Expand Down Expand Up @@ -254,6 +264,7 @@ func (c *Client) Login(ctx context.Context, r *LoginRequest, opts ...ClientOptio
}

c.username = r.UserName
c.isPopular = scheduler.UserScheduler.IsPopularStreamer(c.username)

// cookieを流用して各種ページアクセス用agentを初期化
domain := fmt.Sprintf("%s.u.isucon.dev", r.UserName)
Expand Down
2 changes: 2 additions & 0 deletions bench/isupipe/client_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package isupipe
import (
"context"
"testing"
"time"

"github.com/isucon/isucandar/agent"
"github.com/isucon/isucon13/bench/internal/config"
Expand All @@ -15,6 +16,7 @@ func TestClientUser_Login(t *testing.T) {

client, err := NewClient(
agent.WithBaseURL(config.TargetBaseURL),
agent.WithTimeout(1*time.Minute),
)
assert.NoError(t, err)

Expand Down
5 changes: 5 additions & 0 deletions bench/scenario/attacker.go
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
package scenario

func DnsWaterTortureAttackScenario() error {
// FIXME: internal/attackerパッケージを用いて実装
return nil
}
134 changes: 0 additions & 134 deletions bench/scenario/basic.go

This file was deleted.

Loading

0 comments on commit 8f85800

Please sign in to comment.