GithubHelp home page GithubHelp logo

isucon / isucon13 Goto Github PK

View Code? Open in Web Editor NEW
82.0 82.0 19.0 37.69 MB

License: MIT License

Makefile 0.04% Go 94.23% Shell 0.26% Python 0.97% Dockerfile 0.06% HTML 0.01% TypeScript 1.44% CSS 0.01% Perl 0.74% HCL 0.04% Rust 0.58% Ruby 0.31% PHP 1.32%

isucon13's Introduction

CAUTION: this project is open for only #isucon administrators

/webapp
/webapp/perl
/webapp/ruby
/webapp/nodejs

/tools
/tools/benchmark
/tools/domchecker
/tools/scoreboard

** Webアプリの基本方針
-処理はすべてリクエストを受け取ってから実施する
--DBへのクエリ
--テンプレートからのレンダリング
-全てのコンテンツをアプリケーションから渡す
--js/css/画像も含めて
-キャッシュ等はとりあえず全て無し

** 実装するリクエストハンドラ
- /
-- GET
-- articleのリスト(投稿順(id順) 最新10個)
--- SELECT id,title,body,created_at FROM article ORDER BY id DESC LIMIT 10

- /article/:articleid
-- GET
-- articleページの表示 (article + comments)
--- SELECT id,title,body,created_at FROM article WHERE id=?
--- SELECT name,body,created_at FROM comment WHERE article=? ORDER BY id

なお全ページ、左側のサイドバーに「新しいコメントがついた順に記事10件」を表示
--- SELECT article FROM comment GROUP BY article ORDER BY created_at DESC LIMIT 10

- /post
-- GET
-- 記事投稿用HTML ただしベンチ対象外のURLとする

- /post
-- POST
-- 記事投稿
-- パラメータはform形式で title, body
--- INSERT INTO article SET ...
-- レスポンスは / へのリダイレクト(成功)、もしくは適当なエラー用のHTTPステータス

- /comment/:articleid
-- POST
-- コメント投稿 (投稿フォームは /article/:articleid の末尾)
-- パラメータはform形式で name, body
--- INSERT INTO comment SET ...
-- レスポンスは /article/:articleid へのリダイレクト(成功)、もしくは適当なエラー用のHTTPステータス

** 添付するstaticファイル

- 画像
-- isuconロゴを適当なサイズにして流用、ページトップのバナー画像にする

- js
-- jquery 最新版の minify 済みファイル
-- jquery-ui 最新版の minify 済みファイル
-- isucon.js デザイン調整用

- css
-- jquery-ui の適当なスタイル用のもの一式
-- isucon.css デザイン調整用

isucon13's People

Contributors

catatsuy avatar drumato avatar eagletmt avatar fujiwara avatar kamijin-fanta avatar kazeburo avatar kfly8 avatar misodengaku avatar notchi590 avatar okashoi avatar pastak avatar sunakan avatar tukejonny avatar yamachu avatar yuk1-ishida avatar yutaura avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

isucon13's Issues

静的ファイルのバリデーション

ベンチマーカーのassetdirを指定すると、静的ファイル群が置いてあるパスからファイルを読み出して各ファイルが改変されていないかチェックする想定がある

現状未実装なので、これをきちんとやる
(assetdirからの読み出し自体はisucon9-finalのものを流用)

powerdns のスキーマ管理

ansibleはパッケージに含まれるスキーマを適用して、indexをいじる
dockerはrepo上にあるスキーマを適用する

これを統一しておきたい

当日マニュアル: Security Groupについてを書く

ミドルウェアなどで必要となる場合、Security Groupは変更してもOK。
ただし、運営やベンチマークに必要なポートが開放されなくなった場合は失格になります、というのを明記しておく

DNS水責めの設計

  • ランダムな文字列を生成しての名前解決
  • エラーではない場合(名前解決結果が空やrefusedはOK) は成功でカウントアップ
  • RcodeOKで名前解決結果が参加者のインスタンスではない場合、致命的エラー
  • n割で名前解決ができると、HTTPsで接続しに行くやつがいる(負荷要素で結果は問わない
  • 数%の確率でdotの数が多いクエリがある 
  • 負荷を徐々にあげていく

bench: GET /livestream?tag のクエリパラメータをエンコードする

diff --git a/bench/isupipe/client.go b/bench/isupipe/client.go
 index 8df9d0e..7e7d291 100644
 --- a/bench/isupipe/client.go
 +++ b/bench/isupipe/client.go
 @@ -514,11 +514,13 @@ func (c *Client) GetLivestreamsByTag(
  		option(&pat)
  	}
  
 -	urlPath := fmt.Sprintf("/livestream?tag=%s", tag)
 -	req, err := c.agent.NewRequest(http.MethodGet, urlPath, nil)
 +	req, err := c.agent.NewRequest(http.MethodGet, "/livestream", nil)
  	if err != nil {
  		return bencherror.NewInternalError(err)
  	}
 +	query := req.URL.Query()
 +	query.Add("tag", tag)
 +	req.URL.RawQuery = query.Encode()
  
  	resp, err := c.sendRequest(ctx, req)
  	if err != nil {

bench /initializeで失敗した場合のログ

2023-11-11T11:57:52.124Z	info	isupipe-benchmarker	webappの初期化を行います
不正な広告レベル

500が返った結果、広告レベルが取得できなくてこのエラーになるようですが、選手には分かりづらいのでstatus!=200の場合「initializeが失敗しました」と返した方がよいです。

catatsuy試し解きメモ

直した方がよさそうなこと

  • nginxの設定ファイルの位置。sites-enableを使う方が自然では
  • initializeがコケると不正な広告レベルと言われる
  • tx.ExecContext(ctx, query, livecomment.Comment, ngword.Word) のrollbackなど、rollback忘れと思われる処理が色々ある

感想

  • まずslow queryがinitializeで荒れるので大変
    • 自分はファイル先頭に SET long_query_time = 60.0; を頑張って書いていった
    • これは過去もあった気がするのと、知らなくても気合いで何とかできるので参加者に頑張ってもらう
  • インデックスを貼っても少ししか変わらず、N+1クエリばかりでつらい
  • isudnsの方はinitializeの処理はないが、スロークエリには出てくる
  • インデックスやN+1クエリを解消してもスコアが上がらない、スロークエリを見る限り改善はしてそうなので心が折れそうになる
    • N+1クエリを解決しているはずなのに下がったりすることもある
  • moderateHandlerで処理をキューにして遅らせていいなら、レギュレーションに明記が必要、リアルタイムでやる必要がある場合も明記した方がよさそう
  • NGワード登録のところはChatGPTに聞いたら大体答えが返ってきた
  • alpはregisterとloginが多いが、一旦無視している
  • N+1クエリはChatGPTに聞くとそれっぽいけど微妙に壊れているコードが提案されることがある

課金サーバの実装

ひとまず、誰がいくら支払ったか、投げ銭の記録を取れるサーバを作る

DNS名前解決のretryをいれる?

2-3回のリトライはしてもいいのかも
水責め時、ベンチ実行時はやらない。
pretest、finalcheck時にのみリトライ行う

fujiwara試し解きメモ 2023-11-11

https://scrapbox.io/isucon13operation/2023-11-10_fujiwara%E8%A9%A6%E3%81%97%E8%A7%A3%E3%81%8D#654f62b033e5190000458616

エラーログ、まだ err が握りつぶされてそう #205 (実際のエラー内容がログにでていない + 出力元が main.go で統一されてしまってどこが出所か分からない)

Nov 12 00:22:31 isucon-app isupipe[289292]: {"time":"2023-11-12T00:22:31.202621676+09:00","level":"ERROR","prefix":"echo","file":"main.go","line":"220","message":"error at /api/livestream: code=500, message=failed to fill livestream"}

  • pdnsはzone file backendにしてmysqlと無関係にした

  • ng_word判定、N+1をいくつか解消して売上3000程度までいった

  • GET のエンドポイントで begin / commit を全て外してみたところ、なぜか売上が 0 になった

    • 0になる理由がベンチのログから分からない
  • が、/api/livestream/search だけまだトランザクションが残っていたのを外したら 4500 に

  • DNSを別ホストに逃がしたらベンチがCPU 400%使うようになった

  • search/livestreams で limit も tag も引数に付いてこないので適当に LIMIT 1, 10, 100 としたらどれもベンチを完走した (本来のアプリ仕様を満たさない改変)

    • pretestで検出しないといけない、負荷走行時のリクエストパターンにも含める必要がある

ここまでの所感

N+1が fillなんとか関数で発生している、これが多くの箇所から呼ばれているので解消がとても面倒くさい、けどボトルネックなのでやらざるを得ないので、ここから腕力で N+1 をなんとかするゲームになりそう。

売上: 10178の時点で

mysql> select sum(tip) from livecomments;
 +----------+
 | sum(tip) |
 +----------+
 |  4958790 |
 +----------+

これと売上はどういう関係になっているんでしょう?

構造決め

/
--- webapp
      |_____ frontend
           |_ viteのsccafoldしたやつら
      |_____ go
           |_ main.go
           |_ movie_handlers.go
           |_ user_handlers.go
           |_ channel_handlers.go
           |_ ...
      |_____ sql
           |_ create_database.sql
           |_ create_table.sql
           |_ insert_data.sql

webapp: ユーザ機能に関するOpenAPI定義

1~3日以内にできるといいのかな、という想定

必要そうな作業

以下、セッションIDをCookieで扱う方式と仮定して記載

実装方針

ログアウト機能はつくらないという話だったので含めない

  • ユーザテーブルの内容から、componentsに User を定義
  • それぞれのエンドポイントを定義
    • エンドポイント一覧
      • ユーザ新規登録(Registration)
      • ユーザログイン
    • リクエスト内容
    • レスポンス内容
    • ドキュメント

スパムの仕様の新規性

過去問題と同様のスパム判定処理だと焼き直しになってしまい、競技者の体験を損ねるのではないか

仕様の詰めもあるが、単純にAho-Corasickで判定するだけのこと以上のネタを考えたい

マニュアルに DNS は UDPでAレコードを返すのみを返すことと明記する

UDPでlistenすること、Aレコードを返すことを明記する
UDPで問い合わせた時にtc bitがつくのはいいけど、最初からTCPで問い合わせたりはしないよと

CNAMEを返されても再帰クエリしないよ、と明記する
Aレコード以外が帰ってきたらエラーにする
AAAAの問い合わせは無視してok

pdnsはALIASレコードあるので使おうと思えば使える

ユーザ名指定でライブ配信取得できるように

プロフィール画面で、ユーザのライブ配信を一覧できないとかなり寂しい感じになるということで、追加することになりました

ベンチマーカーでは、プロフィール訪問時に叩くことになります

[Go] errをログに出力する

現在のコードでは以下のようなエラーハンドリングになっていますが、実際に発生したerrをどこにも出力しないため原因を見つけるのがたいへん難しくなっています。

tx, err := dbConn.BeginTxx(ctx, nil)
if err != nil {
    return echo.NewHTTPError(http.StatusInternalServerError, "failed to begin transaction")
}

c.Logger().Errorf()を使って別途エラーログを吐くか、NewHTTPErrorのメッセージに err.Error() を含める必要があります。

catatsuy感想

isucon13/webapp/go/main.go

Lines 110 to 119 in 074362c

for i := 0; i < 10; i++ {
if err := db.Ping(); err != nil {
logger.Errorf("failed to ping to MySQL: %v", err)
time.Sleep(1 * time.Second)
continue
}
return db, nil
}

このコードは他の言語に移植が難しいので、これを追加するならsystemdの起動順を定義しておいた方がよさそう。

Idになっているのは意図的ですか?GoだとIDにすることが多いです。

paymentMu sync.RWMutexは最終的にどうする予定ですか?これは他言語に移植できません。

Makefileの.PHONYは上に書く方が一般的だと思います。

スキーマでidがintとBIGINTが混ざっていますが、全部BIGINTでもいいかもですね。

goのディレクトリの中の.gitignoreの一番下にisupipeと書かれていますが、どこでgitignoreされているかが競技者から分かりにくいかもしれません。

webpapp/go/initial_livestreams.sqlは何のために存在していますか? initializeで必要な他の言語実装でも必要なのでgoディレクトリはおかしいです。

Dockerfileのbullseyeは1つ前のDebianなので、できるなら新しいバージョンにしたいですね。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.