pixiv private isucon 2016 ��ά (2/5)
����������:
���ץ���ɤ�
�����������ɤ��ɤߤʤ�����������ι������İ����Ƥ����ޤ���
- �ե졼������ goji ��ȤäƤ��롣 goji �Υ����Ȥ򸫤��Ʊ��̾���ǿ������ե졼��������ľ�����ߤ��������ɡ�����ϸŤ�����ȤäƤ�ߤ����Ǥ���
- ���å����� Gorilla �Υ饤�֥��� memcached store ���Ȥ߹�碌�Ƥ���
- �ƥ�ץ졼�Ȥ������󥰤Τ��Ӥ˥���ѥ��뤷�Ƥ�Τ��Ť�����
- �����ȤΥ桼�����򤤤������桼�����ơ��֥뤫�����ĥ�äƤ�Τ� JOIN ������å��夬����������
- �����ǡ����� MySQL ���ͤù���Ǥ�Τϡ��ե�����˽Ф�ɬ�פ����ꤽ����(�ե�����ʤ����KB�����ɤ�Ǥ��֤��뤱��ɡ�DB���ȴ�ñ����ˡ���Ȱ��٤����Τ������ɤ�Ǥ��ޤ��Τǡ�����˥����������褿�Ȥ��˥��꤬Â��ʤ��ʤ�ޤ�����
�ɤ�Ǥ���Ȳ����������ݥ���Ȥ���������ФƤ����ΤΡ������ʤꤢ��������¤�������ȥХ��ä��Ȥ��˺���ޤ����Ϥ���ϴ���Ū������ȥܥȥ�ͥå��˹ʤä����塼�˥󥰤Ǥ���
�ǽ��DB�Υ��ͥ������ס�������Ǥ��Ƥʤ��Τ����ꤷ�Ƥ����ޤ��礦��2�����ʤ�Ǥ���ʤˤ������󥳥ͥ�����󤢤äƤ�����ʤ��ϥ����Ȥꤢ�������礤¿���8�ˤ��Ƥ����ޤ���
+ db.SetMaxOpenConns(8) + db.SetMaxIdleConns(8) defer db.Close()
���������������ɤ�
�������Ѱդ��Ƥ��������������������ץġ���ʼ���Ƥ⤤���Ǥ��������Τ�������������ISUCON�ε�����õ���Ƥߤ���ɤ��ġ��뤬�Ҳ𤵤�Ƥ���Ϥ��Ǥ��ˤ򡢥������������䥢�ץ��URL�롼�ƥ��󥰤�����򻲹ͤ˥������ޥ������ޤ��礦��
�ͤξ��ϼ������ץȤǡ����Τ褦�ʽ��פ򤷤ޤ�����
Request by count 8028 GET /image/* 644 GET / 551 GET /js/jquery-2.2.0.js 551 GET /css/style.css 551 GET /js/jquery.timeago.ja.js 551 GET /favicon.ico 551 GET /js/jquery.timeago.js 551 GET /js/main.js 450 POST /login 299 GET /posts/* 235 GET /@user 130 POST / 98 GET /login 90 POST /comment 79 POST /register 78 GET /admin/banned 56 GET /posts?max_created_at= 50 GET /logout 1 GET /initialize Request by total time (total avg [sec]) 198.379 0.308041925466 GET / 168.858 0.021033632287 GET /image/* 47.605 0.202574468085 GET /@user 34.491 0.0766466666667 POST /login 30.444 0.543642857143 GET /posts?max_created_at= 15.095 0.0504849498328 GET /posts/* 7.068 0.0894683544304 POST /register 6.7 0.0515384615385 POST / 6.51 0.0118148820327 GET /favicon.ico 6.483 0.0117658802178 GET /js/jquery-2.2.0.js 5.784 0.010497277677 GET /js/jquery.timeago.js 5.213 0.0094609800363 GET /js/jquery.timeago.ja.js 5.095 0.00924682395644 GET /css/style.css 4.997 0.00906896551724 GET /js/main.js 2.478 0.0275333333333 POST /comment 2.257 0.0230306122449 GET /login 1.314 0.0168461538462 GET /admin/banned 1.131 0.02262 GET /logout 0.061 0.061 GET /initialize Request by out bytes (total avg) 2485959550 309661 GET /image/* 142499069 258619 GET /js/jquery-2.2.0.js 12206011 18953 GET / 4287247 18243 GET /@user 4105501 7451 GET /js/jquery.timeago.js 1912146 34145 GET /posts?max_created_at= 1108574 3707 GET /posts/* 980229 1779 GET /css/style.css 487635 885 GET /js/main.js 357048 648 GET /js/jquery.timeago.ja.js 195356 434 POST /login 177772 1814 GET /login 149872 272 GET /favicon.ico 34286 434 POST /register 23530 181 POST / 22200 444 GET /logout 16833 187 POST /comment 13104 168 GET /admin/banned 161 161 GET /initialize
����ǹͤ���Τϡ���˼���2���Ǥ���
- �ȥåץڡ�����
/image/
�˳ݤ�����֤����ֽŤ����ä˥ȥåץڡ�����ǽ�˥��塼�˥󥰤���Τ��ɤ������� - �Ӱ��
/image/
������Ū���Ӱ�ͥå��ˤʤ�褦���ä��顢�����Ϻư��̤��ˤ����Τǡ��إå�����Ŭ�ڤ����ꤹ��Х��饤����Ȥ� "304 Not Modified" ���֤���褦�ˤʤä��ç¤ï¿½Ê¥Ö¥ì¡¼ï¿½ï¿½ï¿½ï¿½ï¿½ë¡¼ï¿½ï¿½ï¿½ï¿½ï¿½ë¤«ï¿½â¤·ï¿½ï¿½Ê¤ï¿½ï¿½ï¿½
pprof
�Ȥꤢ���� app �� CPU ���Ť��Τǡ�CPU�ץ��ե����뤫��Ϥ�ޤ��礦�� pprof �δ���Ū�ʻȤ����ϡ������� Blog ��񤤤��ΤǤ���򻲾Ȥ��Ƥ���������
- Go pprof ������ (CPU Profile �ȥ��ޥ�ɥ饤��ġ���)
- Go pprof ������ (CPU �ʳ��Υץ��ե�����)
diff --git a/app.go b/app.go index 861ff03..eb52f47 100644 --- a/app.go +++ b/app.go @@ -9,6 +9,7 @@ import ( "io/ioutil" "log" "net/http" + _ "net/http/pprof" "net/url" "os" "os/exec" @@ -826,6 +827,8 @@ func main() { + + db.SetMaxOpenConns(8) + db.SetMaxIdleConns(8) defer db.Close() + go http.ListenAndServe(":3000", nil) + goji.Get("/initialize", getInitialize) goji.Get("/login", getLogin) goji.Post("/login", postLogin)
$ go tool pprof app http://localhost:3000/debug/pprof/profile Fetching profile from http://localhost:3000/debug/pprof/profile Please wait... (30s) Saved profile in /home/isucon/pprof/pprof.localhost:3000.samples.cpu.001.pb.gz Entering interactive mode (type "help" for commands) (pprof) top 10 14440ms of 29650ms total (48.70%) Dropped 546 nodes (cum <= 148.25ms) Showing top 10 nodes out of 214 (cum >= 7370ms) flat flat% sum% cum cum% 2270ms 7.66% 7.66% 8650ms 29.17% runtime.mallocgc 2220ms 7.49% 15.14% 2220ms 7.49% runtime.memclr 2150ms 7.25% 22.39% 2840ms 9.58% runtime.scanobject 1930ms 6.51% 28.90% 2060ms 6.95% syscall.Syscall 1280ms 4.32% 33.22% 1280ms 4.32% runtime.heapBitsSetType 1240ms 4.18% 37.40% 1270ms 4.28% runtime.(*mspan).sweep.func1 1000ms 3.37% 40.78% 1000ms 3.37% runtime.memmove 930ms 3.14% 43.91% 5070ms 17.10% database/sql.convertAssign 750ms 2.53% 46.44% 2240ms 7.55% time.parse 670ms 2.26% 48.70% 7370ms 24.86% github.com/go-sql-driver/mysql.(*textRows).readRow
����������Ť��Ǥ��͡����� MySQL ���������ä���̤�ѡ������Ƥ���ʬ���Ť���
����������Ť���硢����Υ��������Ȥ��Ƥ���ʬ�򸫤Ĥ����٤��Ƥ�����ˡ�⤢��ޤ�������äȹ⤤�쥤�䡼�ǤΥ��ץ�Υ��塼�˥󥰤�������Ǥ������ξ�� -cum ���ץ�����Ȥäƥȥåץ�����˥ץ��ե�����򸫤ޤ���
(pprof) top -cum 40 10.25s of 29.65s total (34.57%) Dropped 546 nodes (cum <= 0.15s) Showing top 40 nodes out of 214 (cum >= 2.22s) flat flat% sum% cum cum% 0 0% 0% 28.99s 97.77% runtime.goexit 0 0% 0% 25.69s 86.64% net/http.(*conn).serve 0 0% 0% 25.40s 85.67% net/http.(*ServeMux).ServeHTTP ... 0 0% 0% 25.08s 84.59% github.com/zenazn/goji/web/middleware.Recoverer.func1 0 0% 0% 22.42s 75.62% github.com/zenazn/goji/web.netHTTPHandlerFuncWrap.ServeHTTPC 0 0% 0% 20.61s 69.51% main.getIndex 0 0% 0% 20.26s 68.33% github.com/jmoiron/sqlx.(*DB).Select 0 0% 0% 20.26s 68.33% github.com/jmoiron/sqlx.Select ...
��̤ˤ���ꥯ�����ȥϥ�ɥ顼�� getIndex
�����Ǥ��������˽��椷�ޤ��礦��
�����������ɤι�ñ�̤Υץ��ե�����򸫤�ˤϥǥХå�����ɬ�פʤΤǡ� pprof ��ư���˥��ץ�ΥХ��ʥ����ꤷ�Ƥ���ɬ�פ�����ޤ���
�Х��ʥ����ꤷ˺��� URL �����ǥץ��ե�������äƤ��ޤä����⡢��ư�����Ȥ��� "Saved profile in ..." ��ɽ������Ƥ���ѥ��˥ץ��ե������̤���¸����Ƥ���Τǡ����٥ץ��ե�����󥰤��ʤ��Ƥ�
go tool pprof app <�ץ��ե������̤Υѥ�>
������פǤ���
isucon:~/private_isu/webapp/golang$ go tool pprof app /home/isucon/pprof/pprof.localhost:3000.samples.cpu.001.pb.gz Entering interactive mode (type "help" for commands) (pprof) list main.getIndex Total: 29.65s ROUTINE ======================== main.getIndex in /home/isucon/private_isu/webapp/golang/app.go 0 20.61s (flat, cum) 69.51% of Total . . 388: . . 389: http.Redirect(w, r, "/", http.StatusFound) . . 390:} . . 391: . . 392:func getIndex(w http.ResponseWriter, r *http.Request) { . 120ms 393: me := getSessionUser(r) . . 394: . . 395: results := []Post{} . . 396: . 18.39s 397: err := db.Select(&results, "SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` ORDER BY `created_at` DESC") . . 398: if err != nil { . . 399: fmt.Println(err) . . 400: return . . 401: } . . 402: . 1.34s 403: posts, merr := makePosts(results, getCSRFToken(r), false) . . 404: if merr != nil { . . 405: fmt.Println(merr) . . 406: return . . 407: } . . 408: . . 409: fmap := template.FuncMap{ . . 410: "imageURL": imageURL, . . 411: } . . 412: . . 413: template.Must(template.New("layout.html").Funcs(fmap).ParseFiles( . . 414: getTemplPath("layout.html"), . . 415: getTemplPath("index.html"), . . 416: getTemplPath("posts.html"), . . 417: getTemplPath("post.html"), . 70ms 418: )).Execute(w, struct { . . 419: Posts []Post . . 420: Me User . . 421: CSRFToken string . . 422: Flash string . 690ms 423: }{posts, me, getCSRFToken(r), getFlash(w, r, "notice")}) . . 424:} . . 425: . . 426:func getAccountName(c web.C, w http.ResponseWriter, r *http.Request) { . . 427: user := User{} . . 428: uerr := db.Get(&user, "SELECT * FROM `users` WHERE `account_name` = ? AND `del_flg` = 0", c.URLParams["accountName"])
����ε����κǸ�� myprofiler �Ǹ��Ĥ����� posts ����� LIMIT �ʤ������꤬�Ť�����Ǥ��͡�MySQL ¦�����Ǥʤ����������̤η�̤�����������ƥѡ������Ƥ� app ¦�Ǥ���ֽŤ��ʤäƤ���褦�Ǥ���
���Υ�����η�̤����Ѥ��Ƥ��� makePosts()
����򸫤Ƥߤ�ȡ��롼�פν�ü�ˤ���� if ʸ������ޤ���
if len(posts) >= postsPerPage { break }
������� continue
ʸ��ʤ��Τǡ����Τޤ� postsPerPage
�� LIMIT ���ޤ��礦�� (��: ���줬��ǧ��Â�Ǹ�ǥϥޤ�ޤ�)
diff --git a/app.go b/app.go index eb52f47..3dd9804 100644 --- a/app.go +++ b/app.go @@ -394,7 +394,7 @@ func getIndex(w http.ResponseWriter, r *http.Request) { results := []Post{} - err := db.Select(&results, "SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` ORDER BY `created_at` DESC") + err := db.Select(&results, "SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` ORDER BY `created_at` DESC LIMIT 20") if err != nil { fmt.Println(err) return
���ơ���¬�Ǥ��������Ϸ�¬�ȥץ��ե�������̤ˤ������������Ǥ��������֤�����̵���Τǥץ��ե����뤷�ʤ����¬�Ǥ���
������:
{"pass":true,"score":12848,"success":22272,"fail":1201,"messages":["1�ڡ�����ɽ�����������ο���Â��ޤ��� (GET /)","������쥯����URL������������ޤ���: expected '^/$', got '/login' (GET /login)"]}
����顣���顼���ǤƤ��ޤ��������ץ�Υ����򸫤�ȡ�
fork/exec /bin/bash: cannot allocate memory
���꤬Â��ʤ��� fork �˼��Ԥ��Ƥޤ�����
top:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 11931 isucon 20 0 406248 183372 9052 S 74.8 17.9 0:19.55 app 720 mysql 20 0 1226416 215076 10404 S 65.5 21.0 3:24.11 mysqld
CPU ������ app �� mysql �������������Ǥ��͡�Â���Ƥ�200�ˤ������Ϥ��ʤ��Τǡ�CPU�ʳ�����ʬ���ͥå��ˤ�Ϥ���Ƥ������Ǥ���
myprofiler:
17 SELECT * FROM `posts` WHERE `id` = N 12 SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` WHERE `created_at` <= S ORDER BY `created_at` DESC 4 SELECT * FROM `users` WHERE `id` = N 3 SELECT * FROM `users` WHERE `id` = ?
posts ���� id �����1�쥳���ɼ������Ť��ʤ�ޤ����� N+1 ���ʡ�
�����ץ������ƤӽФ������
fork �˼��Ԥ���Τϡ�¿ʬ�ʥ���åפ��ʤ������ǡ��˥����С����ߥåȤ����դˤʤäƤ��ơ�fork �����ִ֤� app ��Ʊ�������Υ������äƤ�⤦1�ץ���������ʤ�������Ȼפ��ޤ���
CPU����Ψ��2�����ʤΤ�200%�������Ϥ��ʤ��Τ� fork �Τ��� (Go �Υ�󥿥�����Թ�� fork ���뤿��ˤ��� goroutine ���ö�ߤ�ʤ��Ȥ����ʤ����Ԥ����֤�ȯ������) ���⤷��ʤ��Τǡ���������̺︺�Τ���˲����ե������DB�����ڤ�Ф����⳰���ץ������ƤӽФ����������ͥ�褷�ޤ��礦��
�����ץ��������ɤ�Ǥ�Ȥ����򸫤�ȡ� openssl dgst -sha512
���ޥ�ɤ� sha512 �����������Ȥ�׻����Ƥ���褦�Ǥ��� Go �� sha512 ��׻�������ˡ��Ĵ�٤ơ�Ʊ�����Ϥ򤹤�ץ�������񤤤Ƥߤޤ���
$ cat t.go < app.go package main import ( "crypto/sha512" "fmt" "io/ioutil" "os" ) func main() { data, _ := ioutil.ReadAll(os.Stdin) fmt.Printf("%x\n", sha512.Sum512(data)) } isucon@ip-10-0-1-202:~/private_isu/webapp/golang$ go run t.go < t.go b252b55576a4f4e321d5761b6dc980b8ee41fd9767765c785861a73b736f6a59aa7f40f7ba0d92c508dea32a20bc800e0198056c3dc8b33d5ac445f27b163d17 isucon@ip-10-0-1-202:~/private_isu/webapp/golang$ openssl dgst -sha512 < t.go (stdin)= b252b55576a4f4e321d5761b6dc980b8ee41fd9767765c785861a73b736f6a59aa7f40f7ba0d92c508dea32a20bc800e0198056c3dc8b33d5ac445f27b163d17
����ò»²¹Í¤ï¿½ app.go ��ñ¤´ï¿½ï¿½ï¿½ï¿½Þ¤ï¿½ï¿½ï¿½
@@ -125,14 +125,7 @@ func escapeshellarg(arg string) string { } func digest(src string) string { - // openssl�ΥС������ˤ�äƤ� (stdin)= �Ȥ����Τ��Ĥ��ΤǼ�� - out, err := exec.Command("/bin/bash", "-c", `printf "%s" `+escapeshellarg(src)+` | openssl dgst -sha512 | sed 's/^.*= //'`).Output() - if err != nil { - fmt.Println(err) - return "" - } - - return strings.TrimSuffix(string(out), "\n") + return fmt.Sprintf("%x", sha512.Sum512([]byte(src))) }
���ơ��ץ��ե��������¬�Ǥ������ץ�Υ����ˤ� fork ���顼���ä��ޤ�����
������:
{"pass":true,"score":26755,"success":24050,"fail":119,"messages":["1�ڡ�����ɽ�����������ο���Â��ޤ��� (GET /)"]}
�����󡢤ޤ����顼�ФƤޤ��͡������ LIMIT Â�����Τ��ޥ������ʡ�
top:
Tasks: 84 total, 1 running, 83 sleeping, 0 stopped, 0 zombie %Cpu(s): 54.2 us, 20.7 sy, 0.0 ni, 15.0 id, 1.4 wa, 0.0 hi, 8.3 si, 0.4 st KiB Mem: 1022972 total, 958404 used, 64568 free, 18292 buffers KiB Swap: 0 total, 0 used, 0 free. 425600 cached Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 720 mysql 20 0 1357488 210336 4476 S 78.6 20.6 5:19.05 mysqld 763 isucon 20 0 619612 198632 9120 S 70.2 19.4 0:13.54 app 2904 www-data 20 0 92028 4088 1928 S 11.3 0.4 0:29.40 nginx 2572 isucon 20 0 34344 11148 2160 S 7.3 1.1 0:28.48 tmux
idle �� 15% �ޤDz����äƤޤ��������̤ꡣ ���ȡ� tmux �� 7% �ޤ���ޤ����� Goji �Υ�������å�������Τǡ��Ǹ�ˤ��ڤ�ʤ��Ȥ����ޤ���͡�
myprofiler:
## 2016-05-25 20:18:44.06 +0900 13 SELECT * FROM `posts` WHERE `id` = N 9 SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` WHERE `created_at` <= S ORDER BY `created_at` DESC 9 SELECT * FROM `comments` WHERE `post_id` = N ORDER BY `created_at` DESC LIMIT N 6 SELECT * FROM `users` WHERE `id` = ? 6 SELECT `id` FROM `posts` WHERE `user_id` = N 4 SELECT * FROM `users` WHERE `id` = N 4 SELECT COUNT(*) AS `count` FROM `comments` WHERE `post_id` = ? 2 SELECT COUNT(*) AS `count` FROM `comments` WHERE `post_id` = N 2 SELECT * FROM `comments` WHERE `post_id` = ? ORDER BY `created_at` DESC LIMIT N 2 SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` WHERE `user_id` = N ORDER BY `created_at` DESC
������
makePosts()
��ľ���Ƥߤ�ȡ���Ƥ����桼�����������������Ƥ���������ؤ��ɲä򤷤ʤ��褦�ʥ����ɤˤʤäƤ��ޤ�����
(Go ���� early return (continue) ���ǥ������Ȥ����Ȥ�¿���ΤǤ�����ʬ��ƨ���Ƥ��ޤ���)
if p.User.DelFlg == 0 { posts = append(posts, p) }
SELECT ���ʳ��Ƕ����� JOIN ���Ƥ�����������Υե��륿��󥰤�¹Ԥ��Ƥ��ޤ��ޤ���
@@ -394,7 +387,7 @@ func getIndex(w http.ResponseWriter, r *http.Request) { results := []Post{} - err := db.Select(&results, "SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` ORDER BY `created_at` DESC LIMIT 20") + err := db.Select(&results, "SELECT posts.`id`, `user_id`, `body`, `mime`, posts.`created_at` FROM `posts` INNER JOIN `users` ON posts.user_id=users.id WHERE users.del_flg = 0 ORDER BY `created_at` DESC LIMIT 20") if err != nil { fmt.Println(err) return
������:
{"pass":true,"score":27399,"success":23615,"fail":0,"messages":[]}
���٤Ϥ������̤�ޤ�����
top:
Tasks: 83 total, 4 running, 79 sleeping, 0 stopped, 0 zombie %Cpu(s): 53.9 us, 23.6 sy, 0.0 ni, 9.8 id, 4.2 wa, 0.0 hi, 8.2 si, 0.2 st KiB Mem: 1022972 total, 948340 used, 74632 free, 12604 buffers KiB Swap: 0 total, 0 used, 0 free. 486056 cached Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 720 mysql 20 0 1359224 209144 4576 S 85.9 20.4 6:06.96 mysqld 910 isucon 20 0 487224 139892 8884 S 67.9 13.7 0:09.58 app 2904 www-data 20 0 91852 2828 844 R 10.7 0.3 0:35.40 nginx 2572 isucon 20 0 34472 10100 928 S 6.7 1.0 0:33.64 tmux
����ä� mysql ���Ť��Ǥ��͡�
myprofiler:
15 SELECT * FROM `posts` WHERE `id` = N 7 SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` WHERE `created_at` <= S ORDER BY `created_at` DESC 6 SELECT * FROM `comments` WHERE `post_id` = N ORDER BY `created_at` DESC LIMIT N 5 SELECT * FROM `users` WHERE `id` = ? 5 INSERT INTO `comments` (`post_id`, `user_id`, `comment`) VALUES (?,?,?) 5 SELECT COUNT(*) AS `count` FROM `comments` WHERE `post_id` = N 5 SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` WHERE `user_id` = N ORDER BY `created_at` DESC 4 INSERT INTO `posts` (`user_id`, `mime`, `imgdata`, `body`) VALUES (?,?,?,?) 4 INSERT INTO `users` (`account_name`, `passhash`) VALUES (?,?) 3 SELECT * FROM `users` WHERE `id` = N
JOIN ��Â�������ɡ�����Ǥ�ޤ� post �� id �ǰ����Τ��Ť��ߤ����Ǥ���
pprof top40 -cum:
... 0 0% 0.38% 13.88s 76.18% github.com/zenazn/goji/web/middleware.AutomaticOptions.func1 0.01s 0.055% 0.44% 8.85s 48.57% github.com/zenazn/goji/web.netHTTPHandlerFuncWrap.ServeHTTPC 0 0% 0.44% 6.11s 33.53% main.getIndex 0.02s 0.11% 0.55% 4.92s 27.00% github.com/jmoiron/sqlx.(*DB).Get 0.01s 0.055% 0.6% 4.90s 26.89% github.com/jmoiron/sqlx.Get 0 0% 0.6% 4.78s 26.23% github.com/zenazn/goji/web.handlerFuncWrap.ServeHTTPC 0.02s 0.11% 0.71% 4.65s 25.52% main.makePosts 3.82s 20.97% 21.68% 4.06s 22.28% syscall.Syscall ...
pprof list makePosts:
ROUTINE ======================== main.makePosts in /home/isucon/private_isu/webapp/golang/app.go 20ms 4.65s (flat, cum) 25.52% of Total . . 173:} . . 174: . . 175:func makePosts(results []Post, CSRFToken string, allComments bool) ([]Post, error) { . . 176: var posts []Post . . 177: 10ms 10ms 178: for _, p := range results { . 1.05s 179: err := db.Get(&p.CommentCount, "SELECT COUNT(*) AS `count` FROM `comments` WHERE `post_id` = ?", p.ID) . . 180: if err != nil { . . 181: return nil, err . . 182: } . . 183: . . 184: query := "SELECT * FROM `comments` WHERE `post_id` = ? ORDER BY `created_at` DESC" . . 185: if !allComments { . 20ms 186: query += " LIMIT 3" . . 187: } . . 188: var comments []Comment . 1.38s 189: cerr := db.Select(&comments, query, p.ID) . . 190: if cerr != nil { . . 191: return nil, cerr . . 192: } . . 193: . . 194: for i := 0; i < len(comments); i++ { . 770ms 195: uerr := db.Get(&comments[i].User, "SELECT * FROM `users` WHERE `id` = ?", comments[i].UserID) . . 196: if uerr != nil { . . 197: return nil, uerr . . 198: } . . 199: } . . 200: . . 201: // reverse . . 202: for i, j := 0, len(comments)-1; i < j; i, j = i+1, j-1 { . . 203: comments[i], comments[j] = comments[j], comments[i] . . 204: } . . 205: 10ms 10ms 206: p.Comments = comments . . 207: . 1.35s 208: perr := db.Get(&p.User, "SELECT * FROM `users` WHERE `id` = ?", p.UserID) . . 209: if perr != nil { . . 210: return nil, perr . . 211: } . . 212: . . 213: p.CSRFToken = CSRFToken . . 214: . . 215: if p.User.DelFlg == 0 { . 60ms 216: posts = append(posts, p) . . 217: } . . 218: if len(posts) >= postsPerPage { . . 219: break . . 220: } . . 221: }
���֤Τ����äƤ륯���꤬�����ȼ����������1�쥳���ɼ�����������Υ�����ʤΤǡ���ñ�ʥ���������̤��ꤲ�Ƥ�Τ�����ǽŤ��ΤǤ��礦��
�ץ졼���ۥ�������륯����ϡ��ǥե���ȤǤ� prepared statement ��Ȥ��ΤƤˤ��Ƥ��� (prepare, execute, close ��3���ޥ��) �Τǡ�����Ū�� prepared statement ������Ѥ��륳���ɤ�񤯤��� prepared statement ��Ȥ�ʤ��褦�ˤ���Τ������Ǥ���
�ǹ���ǽ���ܻؤ��ʤ�����Ѥ����������Ǥ�������������ñ�ʤΤ� prepared statement ��Ȥ�ʤ����Ǥ��� dsn �� interpolateParams=true
��Â�������� (�ͤ�����������ǽ�Ǥ��� ����)
diff:
@@ -805,7 +805,7 @@ func main() { } dsn := fmt.Sprintf( - "%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true&loc=Local", + "%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true&loc=Local&interpolateParams=true", user, password, host,
������:
{"pass":true,"score":30076,"success":25687,"fail":0,"messages":[]}
30k �������
top:
Tasks: 83 total, 5 running, 78 sleeping, 0 stopped, 0 zombie %Cpu(s): 63.1 us, 17.4 sy, 0.0 ni, 8.5 id, 3.4 wa, 0.0 hi, 7.4 si, 0.2 st KiB Mem: 1022972 total, 960140 used, 62832 free, 13192 buffers KiB Swap: 0 total, 0 used, 0 free. 472760 cached Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 720 mysql 20 0 1359224 209132 4128 S 79.7 20.4 6:56.71 mysqld 1010 isucon 20 0 514368 157192 8888 S 66.8 15.4 0:08.93 app 2904 www-data 20 0 91876 2824 844 R 11.3 0.3 0:41.86 nginx 1015 isucon 20 0 21176 18648 3444 R 8.3 1.8 0:01.31 myprofiler 2572 isucon 20 0 34920 10472 916 S 7.3 1.0 0:38.28 tmux
myprofiler:
18 SELECT * FROM `posts` WHERE `id` = N 11 INSERT INTO `posts` (`user_id`, `mime`, `imgdata`, `body`) VALUES (N,S,_binaryS,S) 9 SELECT * FROM `users` WHERE `id` = N 7 SELECT * FROM `comments` WHERE `post_id` = N ORDER BY `created_at` DESC LIMIT N 6 SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` WHERE `user_id` = N ORDER BY `created_at` DESC 5 SELECT `id`, `user_id`, `body`, `mime`, `created_at` FROM `posts` WHERE `created_at` <= S ORDER BY `created_at` DESC 4 SELECT COUNT(*) AS `count` FROM `comments` WHERE `post_id` = N 2 INSERT INTO `users` (`account_name`, `passhash`) VALUES (S,S) 1 SELECT * FROM `users` WHERE `account_name` = S AND `del_flg` = N 1 INSERT INTO `comments` (`post_id`, `user_id`, `comment`) VALUES (N,N,S)
pprof:
(pprof) top40 -cum 4.23s of 18.58s total (22.77%) Dropped 583 nodes (cum <= 0.09s) Showing top 40 nodes out of 317 (cum >= 2.07s) flat flat% sum% cum cum% 0 0% 0% 17.10s 92.03% runtime.goexit ... 0 0% 0.22% 8.84s 47.58% github.com/zenazn/goji/web.netHTTPHandlerFuncWrap.ServeHTTPC 0 0% 0.22% 5.66s 30.46% main.getIndex 0 0% 0.22% 4.90s 26.37% github.com/zenazn/goji/web.handlerFuncWrap.ServeHTTPC 0 0% 0.22% 4.04s 21.74% github.com/jmoiron/sqlx.(*DB).Get 0.04s 0.22% 0.43% 4.04s 21.74% github.com/jmoiron/sqlx.Get 0 0% 0.43% 3.73s 20.08% html/template.(*Template).Execute 0.03s 0.16% 0.59% 3.50s 18.84% main.makePosts 0 0% 0.59% 3.32s 17.87% github.com/jmoiron/sqlx.(*DB).Select 0 0% 0.59% 3.32s 17.87% github.com/jmoiron/sqlx.Select 0.93s 5.01% 5.60% 3.23s 17.38% runtime.mallocgc 0 0% 5.60% 3.12s 16.79% text/template.(*Template).Execute 0.08s 0.43% 6.03% 3.12s 16.79% text/template.(*state).walk 0.01s 0.054% 6.08% 3.07s 16.52% text/template.(*state).walkTemplate 0 0% 6.08% 3.02s 16.25% text/template.(*state).walkRange 0 0% 6.08% 3.02s 16.25% text/template.(*state).walkRange.func1 0.13s 0.7% 6.78% 2.96s 15.93% runtime.systemstack
���������ƥ�ץ졼�ȤνŤ�����̤˸����Ϥ�ޤ��������ޤ�DB�������Ť���
�ޤȤ�
������: 4745 (�������) -> 14208 (����) -> 30076 (����)
���ơ����������ץ��ե�����ǽŤ��Ȥ������٤����塼�˥󥰤ϡ����������ҹʤ�˶�Ť��Ƥ��ޤ����� ����Ϥ�äȥɥ饹�ƥ��å��ʥ��塼�˥󥰤˰ܤäƤ��������Ȼפ��ޤ���
����� pprof �� myprofiler ��Ȥä����塼�˥󥰤ξҲ�ΰտޤ����ä��ΤǤ���äȤ�ꤹ���Ƥ��ޤ��ޤ����� �ºݤˤϤ�ä��������¤��ɬ�פȤ���褦�ʥ��塼�˥󥰤�ͤ��Ƽ¹Ԥ��ʤ��ȡ���Ⱦ�˻��֤�Â��ʤ��ƥ����ϤˤʤäƤ��ޤ��Τǵ���Ĥ��ޤ��礦��
@methane