ISUCON6で準優勝でした


ISUCON 6 morimoto 36,067 

morimoto1,2( kasari , id:moshisora ) 

今年も作りました #isucon pic.twitter.com/y2fX4HiJys

 fujiwara (@fujiwara) October 22, 2016









SSE (Server Sent Events) 

 React  node 

react, , MySQL  Docker 




f:id:sfujiwara:20161024114926p:plain
11:02:53   PASS  942
11:21:28   PASS  1159
11:58:31   PASS  1364
12:31:15   FAIL  253
12:36:34   PASS  1616
12:39:18   PASS  2051  nginxをいれて /api 以下を直接 Perl に (fujiwara)
12:43:40   PASS  3175  並列度が高いのでPerlを200プロセスに (fujiwara)
12:46:41   PASS  3543
12:49:26   FAIL  12
12:53:18   PASS  2816
13:03:36   PASS  3314
13:35:14   FAIL  251
13:47:46   FAIL  251
14:07:14   PASS  3211  pointsをstrokesのカラムにJSONで保持 (kasari, moshisora)
14:09:41   FAIL  0  壊れたSVGを返してベンチマーカーがクラッシュしたらしい
14:10:56   FAIL  0
14:11:25   FAIL  0
14:14:25   PASS  3470
14:15:21   FAIL  0
14:16:38   FAIL  0
14:20:25   FAIL  0
14:24:03   PASS  4697  /img/* で返すSVGをPerlでレンダリング (fujiwara)
14:27:05   FAIL  252
14:29:53   PASS  4781
15:17:25   FAIL  106
15:21:32   PASS  7412  /img/* をRedisにCache(Perlで処理) (kasari)
15:31:52   PASS  6040
16:09:04   FAIL  253
16:10:24   FAIL  253
16:12:32   PASS  8020
16:54:56   FAIL  253
16:58:52   FAIL  253
17:10:31   PASS  9339  /api/stream/rooms SSEをGo + Redis PubSub実装に置き換え (fujiwara)
17:41:33   PASS  15241  React, Perl, Goをisu02で動かして2台構成
17:43:36   PASS  30714  React, Perl, Goを全台で動かす5台構成
17:45:12   PASS  29301
17:48:35   PASS  36067  React, Perl, Goを isu02〜05、isu01にnginx, MySQL, Redisの5台構成





1

130

 16:30 


 Perl  Perl Perl1000


MySQLDocker

nginx  /api  react Perl

 Perl 200 ()




1 StrokePoints11JSONStorke(kasari)(moshisora)

/img/ SVG


ReactPerlAPIJSON

ReactSVG


 Perl  SVG (fujiwara)
my $svg = qq{<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" width="${width}" height="${height}" style="width:${width}px;height:${height}px;background-color:white;" viewBox="0 0 ${width} ${height}">};
for my $s (@{ $room->{strokes} }) {
    my ($r, $g, $b, $a) = ($s->{red}, $s->{green}, $s->{blue}, $s->{alpha});
    my ($id, $w) = ($s->{id}, $s->{width});
    $svg .= qq{<polyline id="$id" stroke="rgba($r,$g,$b,$a)" stroke-width="$w" stroke-linecap="round" stroke-linejoin="round" fill="none" points="};
    $svg .= join(" ", map { $_->{x} . "," . $_->{y} } @{$s->{points}});
    $svg .= qq{"></polyline>};
}
$svg .= "</svg>";

 (4697) SVG  Redis  cache  7412 nginx (OpenResty)  Redis 

SSE 500ms sleep DBStroke Perl  Prefork server (Starlet) 

PerlGo


15:30Go


/api/stream/rooms  SSE Go

nginx



500msRedis PubSub 使

PerlStrokePublish

GoSubscribeJSON







Redisgoroutinesubscribechannel

context使3





 500ms  watcher_count 

 case <-time.After(500 * time.Millisecond): 



// func getAPIStreamRoomsID(ctx context.Context, w http.ResponseWriter, r *http.Request) {
// ...
    ch := make(chan *redis.Message, 10)
    nctx, cancel := context.WithTimeout(ctx, 3*time.Second)
    defer cancel()
    go func(ctx context.Context) {
        redisClient := redis.NewClient(&redis.Options{
            Addr: os.Getenv("REDIS_HOST") + ":6379",
            DB:   0, // use default DB
        })
        defer redisClient.Close()
        log.Println("starting psubscribe")
        pubsub, err := redisClient.PSubscribe(fmt.Sprintf("%d", room.ID))
        defer pubsub.Close()
        if err != nil {
            log.Println("psubscrie err", err)
            return
        }
        for {
            msg, err := pubsub.ReceiveMessage()
            if err != nil {
                log.Println("recv err", err)
                return
            }
            select {
            case <-ctx.Done():
                return
            default:
                ch <- msg
            }
        }
    }(nctx)
    for {
        select {
        case <-nctx.Done():
            return
        case msg := <-ch:
            var s Stroke
            err := json.Unmarshal([]byte(msg.Payload), &s)
            if err != nil {
                log.Println(err)
                return
            }
            d, _ := json.Marshal(s)
            printAndFlush(w, "id:"+strconv.FormatInt(s.ID, 10)+"\n\n"+"event:stroke\n"+"data:"+string(d)+"\n\n")
        case <-time.After(500 * time.Millisecond):
        }
// ...

1(fujiwara) 

17 Perl kasari  500ms  watcher 17:10 (9339)


 netdata  (React, Perl, Go) CPU使

Docker React, Perl, Go 251 nginx, Redis, MySQL 1network

5MySQL  too many connections 


my.cnf  max-connections = 10000 

 214


...???  systemd  limit  /etc/systemd/system/mysql.service.d/limits.conf 
[Service]
LimitNOFILE=1000000
LimitNPROC=1000000

1020501 docker-compose OS /etc/systemd/system/multi-user.target.wants/isu.service /etc/systemd/system/isu.service 01


 17:48:35  36,067 2

1711



ISUCON6裏話Nightに酒を贈りたい方はこちら→ https://t.co/2mxdarwDKf

 edvakf (@edvakf) October 23, 2016

 ISUCON (@isucon_official) October 22, 2016