GoããDockeräžã®Elasticsearchã«æ¥ç¶ããéã«ãããã¯ãŒã¯ã®Sniffingã§ããã£ã
åé¡
Docker 㧠Elasticsearch ãèµ·åããŸãã
services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:7.4.0 environment: - discovery.type=single-node ports: - 9200:9200 - 9300:9300
以äžã® Elasticsearch ã¯ã©ã€ã¢ã³ãã©ã€ãã©ãªãå©çšããhttp://127.0.0.1:9200
ãžæ¥ç¶ãã«è¡ããŸãã
c, err := elastic.NewClient() // ããã©ã«ãã§127.0.0.1:9200ãžæ¥ç¶ if err != nil { log.Println(err) }
no active connection found: no Elasticsearch node available
ãšãšã©ãŒãšãªãæ¥ç¶ã§ããŸããã
ã¡ãªã¿ã«ä»¥äžã§ã¯æ¥ç¶ã§ããŸãã
res, err := http.Get("http://127.0.0.1:9200/?pretty=true")
解決ç
以äžã®ããã«elastic.SetSniff(false)
ãåŒæ°ã«äžããã°ã Docker äžã® Elasticsearch ã«æ¥ç¶ã§ããŸãã
c, err := elastic.NewClient(elastic.SetSniff(false))
1 æé以äžããã§æéã溶ãããŠããŸããŸããã
åå
ããã©ã«ãã§ã¯ã¯ã©ã€ã¢ã³ããã¯ã©ã¹ã¿ã®å šããŒããèªåçã«èŠã€ãã«ãããããã®ããŒãã«ãªã¯ãšã¹ããæãã(Sniffing)ãããããã®ããŒãã¯å€éšããã¯çŽæ¥ã¢ã¯ã»ã¹ã§ããªãããæ¥ç¶ã«å€±æããŸãã
ããã§ååŸãããããŒããšã¯å
·äœçã«ã¯ä»¥äžã®ãªã¯ãšã¹ãã§ååŸãããŸãã
ãã®äŸã§ã¯ã172.18.0.3:9200
ã«ã¢ã¯ã»ã¹ãã«ããããšã«ãªããŸããã127.0.0.1:9200
ãéããªãã®ã§ãšã©ãŒã«ãªããŸãã
$ curl http://localhost:9200/_nodes/http\?pretty\=true
"nodes" : { "bzn5IyC2T3GJj_MGhdwyFQ" : { "transport_address" : "172.18.0.3:9300", "host" : "172.18.0.3", "ip" : "172.18.0.3", "build_type" : "docker", "http" : { "bound_address" : [ "0.0.0.0:9200" ], "publish_address" : "172.18.0.3:9200", "max_content_length_in_bytes" : 104857600 }
å®éã®ã³ãŒã
NewClient
ã¡ãœããå
ã®æ¡ä»¶åå²ã§ãã
æå¹ã®å Žåãsniff
ã¡ãœãããåŒã°ããŸãã
if c.snifferEnabled { // Sniff the cluster initially if err := c.sniff(ctx, c.snifferTimeoutStartup); err != nil { return nil, err } } else { // Do not sniff the cluster initially. Use the provided URLs instead. for _, url := range c.urls { c.conns = append(c.conns, newConn(url, url)) } }
sniff
ã¡ãœããå
ã§ã¯ããŒãæ
å ±ãååŸããsniffNode
ã¡ãœããããããã㧠Docker å€ããã¯éä¿¡ã§ããªãPublishAddress
ãååŸããããšã§ä»åã®åé¡ãçºçããŸããã
func (c *Client) sniffNode(ctx context.Context, url string) []*conn { var nodes []*conn // Call the Nodes Info API at /_nodes/http req, err := NewRequest("GET", url+"/_nodes/http") // ãã®ãªã¯ãšã¹ãã§ããŒãæ å ±ãååŸããããã㧠Docker å€éšããã¢ã¯ã»ã¹ã§ããªãURLãååŸããŠããŸã if err != nil { return nodes } // ç¥ res, err := c.c.Do((*http.Request)(req).WithContext(ctx)) if err != nil { return nodes } defer res.Body.Close() var info NodesInfoResponse if err := json.NewDecoder(res.Body).Decode(&info); err == nil { if len(info.Nodes) > 0 { for nodeID, node := range info.Nodes { if c.snifferCallback(node) { if node.HTTP != nil && len(node.HTTP.PublishAddress) > 0 { url := c.extractHostname(c.scheme, node.HTTP.PublishAddress) // ããã§ããŒãæ å ±ãååŸããŠãã if url != "" { nodes = append(nodes, newConn(nodeID, url)) } } } } } } return nodes }
ã¯ã©ã€ã¢ã³ãã¯olivere/elastic
ãelastic/go-elasticsearch
ã
ã¹ã¿ãŒæ°ãæå€ã§ãããå®éã«elastic/go-elasticsearch
ããæ±ããããã£ãã®ã§ãã¡ããæ¡çšããŸããã
ãã«ããŒãã¿ãŒã³ã§ã¯ãšãªãäœæã§ããã®ãã·ã³ãã«ã§åãããããã§ãã
äŸãã°ãres, err := c.Search().Index(targetIndex).Query(multiMatchQuery).Size(1).Do(context.Background())
ã®ããã«ã¯ãšãªãæžããŸãã
åè
Goãäœç³»çã«åŠãã§ããã¡ã¢ããã®1
ã¯ããã«
ããã°ã©ãã³ã°èšèª Go ã®ç ä¿®ãåè¬ããŠããã®ã§åŠã³ãã¡ã¢ããŠãããŸãã
ããã°ã©ãã³ã°èšèªGo (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)
- äœè :Alan A.A. Donovan,Brian W. Kernighan
- çºå£²æ¥: 2016/06/20
- ã¡ãã£ã¢: åè¡æ¬ïŒãœããã«ããŒïŒ
Go ã§ã¯ã©ã®ãããªåé¡è§£æ±ºãããããšããã
Google 㯠C++ãå©çšããŠãæ€çŽ¢ãšã³ãžã³ãªã©ããã©ãŒãã³ã¹ãæ±ãããããµãŒãã¹ãäœæããŠããŸããã C++ã®åé¡ç¹ãšããŠä»¥äžãããããã§ãã
- ã³ã³ãã€ã«ãé ã
- èšèªæ©èœãå€ã(åã ãè²ã ãªãµãã»ããã䜿ã£ãŠãã)
Go ã§ã¯ãè€éã§äžå®å®ãªã³ãŒãããããããŠããæ©èœã¯é¿ããŠããŸãã Go ã¯ãã€ã³ã¿ã«ã€ããŠãããŠå¶çŽããããŸãã C ãªã©ã§ã¯ãã€ã³ã¿ã®ã€ã³ã¯ãªã¡ã³ããã§ããŸãã ããã«ãããã¡ã¢ãªç Žå£ãç°¡åã«ã§ããŠããŸããŸãã ãŸããGo ã¯æ©èœãå°ãªãäœãããŠããŸãã
GC ãšäžŠåããã°ã©ãã³ã°
GC ããªããšå€§å€ã§ãã
GC ããªããšèªåã§ã¡ã¢ãªãfree
ããªããšãããŸããã
äŸãã°ããã£ãã«ããã«ããŒã¿ãæž¡ããæã¯æž¡ããåŽãšåãåãåŽã§ã©ã¡ããåé€ãã責åãè¿œãã®ãã¿ãããªåé¡ãçºçããŸãã
䞊è¡åŠçã§ã¯ã誰ãã©ããåé€ãã責åã決ããã®ãé£ããã§ãã
ããã§ãGC ããããšç°¡åã«ãªããŸãã
Java ãæžããŠãããšã¡ã¢ãªãéæŸãããŠããã€ããã§ãå®ã¯éæŸãããŠããªãã£ãã¿ãããªããšãèµ·ããããã®ã§ãGC ããã£ãããã£ã㧠GC ã®æåãææ¡ããå¿ èŠããããŸãã
ãžã§ãã¯ãªã¯ã¹
Go ã§ã¯ããšæ°å¹Žã§ãžã§ããªã¯ã¹ãè¿œå ãããããã§ãã åãããããäŸã ãšãsort ããã±ãŒãžã§ãã åããšã«ã¡ãœãããããæåèŠãæéåæãæããŸããã ãžã§ããªã¯ã¹ã解決ããŠãããã§ãããã
æååé£çµ
æ¬ã®ç·Žç¿åé¡ã§ãæååé£çµãããå Žåã«+
ã䜿ãæãšstrings.Join
ã䜿ãæã§ããã©ãŒãã³ã¹ãæ¯èŒãããã®ããããŸããã
æ³åéããstrings.Join
ã䜿ã£ãæ¹ãæ©ãã£ãã§ãã
strings.Join
ã§ã¯ãstrings.Builder
ã䜿ã£ãŠå
šãŠãã€ãã§åŠçãããããæ©ãããã§ãã
func Join(a []string, sep string) string { switch len(a) { case 0: return "" case 1: return a[0] } n := len(sep) * (len(a) - 1) for i := 0; i < len(a); i++ { n += len(a[i]) } var b Builder b.Grow(n) b.WriteString(a[0]) for _, s := range a[1:] { b.WriteString(sep) b.WriteString(s) } return b.String() }
mapã§é åºä¿èšŒãããªã
èšèªä»æ§äžå®çŸ©ãããŠããªããšããæå³ã§ã¯ãªãïŒæå³çã«ä¹±æãããŠããŸãã
func main() { m := map[string]int{"a": 1, "b": 2, "c": 3, "d": 4} for k, v := range m { fmt.Print(k, v, " ") } }
äŸãã°ãäžã®ã³ãŒãã§ã¯åºåã¯a1 b2 c3 d4
, b2 c3 d4 a1
, c3 d4 a1 b2
, d4 a1 b2 c3
ã®ããããã«ãªããŸãã
ã¹ã¿ãŒãã®èŠçŽ ããããã ãã§ãã©ã³ãã ã®é åºã«ãªãããã§ã¯ãªãããã§ãã
ã¡ãªã¿ã«ãmap ã®æ¯èŒã§ã¯reflect.DeepEqual
ã¡ãœããã䜿ãããããšãå€ãã§ãã
ãã®äžã®å®è£
ãšããŠã¯ä»¥äžã®ããã«ãªã£ãŠããŸããã
case Map: if v1.IsNil() != v2.IsNil() { return false } if v1.Len() != v2.Len() { return false } if v1.Pointer() == v2.Pointer() { return true } for _, k := range v1.MapKeys() { val1 := v1.MapIndex(k) val2 := v2.MapIndex(k) if !val1.IsValid() || !val2.IsValid() || !deepValueEqual(val1, val2, visited, depth+1) { return false } } return true
untyped value
Go ã§ã¯å®æ°ã untyped value ãšããŠæ±ãããŸãã å®æ°ã®åã¯æ±ºãŸã£ãŠããããå€æ°ã«ä»£å ¥ãããšããåŒã®äžã§æ±ºãŸããŸãã
func main() { x := 1 y := 0.1 fmt.Println(x + y) // invalid operation: x + y (mismatched types int and float64) fmt.Println(1 + 0.1) // 1.1 fmt.Println(1 + y) // 1.1 fmt.Println(x + 0.1) // constant 0.1 truncated to integer type MyInt int var myInt MyInt = 42 fmt.Println(10 + myInt) // 52 fmt.Println(x + myInt) // invalid operation: mismatched types int and MyInt }
fmt.Println(10 + myInt)
ã®ããã«èªåã§å®çŸ©ãã MyInt åãšå®æ° 10 ãèšç®ã§ããã®ã¯æžæããŸããã
ããã¯ãèªåã®é ã®äžã§åæã« 10 㯠Int åãšå€æããŠããããã§ãã£ãŠãuntyped value ã®æŠå¿µãç¥ããšçŽåŸããŸããã
ãããã«
ä»åã¯æåã®ç« ãèªãã ã¡ã¢ã§ããã®ã§æµ ãæãå ·åã«ãªããŸããããä»åŸã®ç« ã§ã¯ããæ·±æãããŠããããšæããŸãã
ISUCON10äºéžæéããŸããã次ã¯æ±ºåè¡ãã
ã¯ããã«
瀟ã®åæ 3 人ã®ãã¹ã¿ã³ãã©ãªãŒãããŒã 㧠ISUCON10 äºéžã«åºå ŽããŸããã æçµã¹ã³ã¢ã¯ 1727 ç¹ã§äºéžæéããŸããã 50äœãããã§ããã æ¬æŠåºå ŽããŒããŒã2158ç¹ãªã®ã§ãããš1,2æãšãããšããã§ããã
ãã£ãããš(ããŒã ã§)
äºéžå
ISUCON9 äºéžåé¡ã 3 人ã§è§£ããªããç·Žç¿ããŸããã ååã®åãã確èªãããããã ISUCON ã§äœ¿ãããææ³ãç·Žç¿ããŠãããŸããã
- Git ãªããžããªã®äœæ
- Makefile äœæ
- ãããã€ã¹ã¯ãªããäœæ
- pt-query-digest, kataribe, pprof, htop ã§èšæž¬
- DB ã®ã€ã³ããã¯ã¹
- N+1 ã¯ãšãªã®è§£æ¶
- IO 䞊åå
- ãªã³ã¡ã¢ãªå
- è€æ°å°æ§æ
ãªã©ãç·Žç¿ããŸããã ãã¡ãããäžäººã§å šéšã§ããããã«ããããã§ã¯ãªããã£ãã圹å²åæ ãããŸããã
äºéžäž:åºç€
ç·Žç¿ãšåãã§ãMySQL ãš Nginx ã§ãããšããŸããã
ç·Žç¿ããããšãçã
ãšè¡ããŸããã
Git ãªããžããªã®äœæãMakefile ã®äœæããããã€ã¹ã¯ãªããã®äœæãpt-query-digest, kataribe, pprof ã®å°å
¥ãããŸããã
èšæž¬ãããšã/nazotte
ãéããã§èŠãããšããªã SQL ãæžããŠããð€ãšãªããŸããã
ãŸãã/api/(estate|chair)/search
ã/api/recommended_estate/:id
ãéããã§ããã
tips
Makefile ãäºåã«äœã£ãŠãããã®ã§ãããšãŠã䟿å©ã§ãã
make setup
ã§ã·ã¥ããšã€ã³ã¹ã¿ã³ã¹ã«åæããŒã«ãã€ã³ã¹ããŒã«ããããmake slow
ãmake kataru
ããã ãã§èªåã§åæçµæã slack ã«æçš¿ãããããã«ããããmake before
ãmake restart
ã§ã·ã¥ããšãã³ãåã«æºåãããã§ããŸãã
äºéžäž:äžç€
/nazotte
ã® N+1 ã¯ãšãªã®è§£æ¶ãè¡ããŸããã
ããŒã ã¡ã³ããŒãã¢ããªå
ã§äžããããå€è§åœ¢ã®äžã«ç¹ãå«ãŸããŠãããå€å®ããã¢ã«ãŽãªãºã ãæžããŠãããŸããã
ãªãã£ãŠæ©èœãããŒã ã¡ã³ãããé²ç ãŒãã§èŠããã€ã ãã£ãŠèšã£ãŠãã¢ããªã±ãŒã·ã§ã³ã§å€å¥ããŠn+1解æ¶ããŠããã #isucon
— kotaroooo0 (@kotaroooo0) 2020幎9æ12æ¥
Nginx 㧠Bot ã匟ãã®ãå°éã«æžããŸããã èšå®ãã¡ã€ã«ã§ã®æžãå Žæãæ£èŠè¡šçŸåšãã§è¥å¹²ããããŸããã
DB ãš APP ã®ã€ã³ã¹ã¿ã³ã¹åå²ãããŸããã ã€ã³ã¹ã¿ã³ã¹ãåé¢ãããš htop ã§ã®èšæž¬ãåããããããªã£ãŠè¯ãã§ããã
äºéžäž:çµç€
pprof å€ããMySQL, Nginx ã®ãã¥ãŒãã³ã°ãè¡ããŸããã ç·Žç¿ã§ã¯ããŸãå¹æãã§ãªããŠæåŸ ããã«ãè¡ã£ããšããçµæ§å¹æãã§ãŸããã ã¡ã¢ãªã«ã¯äœè£ããã£ãã®ã§ãã¯ãšãªãã£ãã·ã¥ããããã¡ããŒã«ã最沢ã«äœ¿ããŸããã ããã«ãããã¹ã³ã¢ 1700 ãè¶ ããŠããŠããã§æéããªãã®ã§ãããŸããã
äºéžäž:ããŒãžããªã£ããã®äŸé€
MySQL8 ãžã®ããŒãžã§ã³ã¢ãããããããšããŸããã éé ã€ã³ããã¯ã¹ã匵ãããããæ§èœã¢ãããæåŸ ãããŸããããã¯ãšãªãã£ãã·ã¥æ©èœããªããã 5.7 ããããã©ãŒãã³ã¹ã¯äžãããŸããã§ããã éé ã€ã³ããã¯ã¹ã貌ããããªãããœãŒã察象㫠-1 ãããããªã©ãå転ããŠããæé ã€ã³ããã¯ã¹ã貌ãã°ãããšãããã¯ãããããã§ãã
ç©ä»¶ãã¡ã¢ãªå
šèŒãããããšããŸããã
/estate/detail
ãæãåŒã°ããŠãããããæžããã° DB ã¯è»œããªããªãšæããŸããã
æŽæ°åŠçãªãããå
šéšèŒããããã®ã§ã¯ãšæããŸããããã³ã㯠verify ã§èœã¡ãŸããã
çµãã£ãŠããæ°ä»ããŸããããããããŠããåèµ·åãã¹ãéããªããªãã verify ã§èœã¡ãŠè¯ãã£ãã§ãã
åèµ·åãã¹ãã§ã¯/initialize
ã¯å©ãããªãã¿ããã§ãã
ãµãŒãçµæãã¡ã¢ãªãã£ãã·ã¥ããããšããŸããã
/api/(estate|chair)/search
ã®ã¯ãšãªãéãã£ãã®ã§ãæ€çŽ¢çµæãã¡ã¢ãªãã£ãã·ã¥ããããšããŸããã
ãã®ãšã³ããã€ã³ãã§ã¯ã察象件æ°ãååŸãã SQL ã 1 åããã®ããšããŒãžããšã®å¯Ÿè±¡ç©ä»¶ãååŸãã SQL ã 1 åå®è¡ããŠããŸããã
ããŒãžããšã®å¯Ÿè±¡ç©ä»¶ãååŸãã SQL ã¯äœåºŠãå©ãããããšã¯å°ãªãããã€ãã£ãã·ã¥ãé£ãããã ã£ãã®ã§ã察象件æ°ãååŸãã SQL ããã£ãã·ã¥ããããšæããŸããã
ãããããã³ãã® verify ã§èœã¡ãŸããã
äºéžäž:ãã£ãã»ããè¯ãã£ãããš
ã¢ããªã±ãŒã·ã§ã³ã®ãããã°ã¢ãŒããªãããã°åºåãªãã«ããæ¹ãè¯ãã£ãã§ãã
ä»å㯠DB ã« 2 ããŒãã«ãããªãããªãã〠JOIN ããªãã£ãããããŒãã«ããšã«ã€ã³ã¹ã¿ã³ã¹ãåããããšãã§ããŸããã
ãªãDBåå²ããã®æãã€ããªãã£ãã®ããæãã㪠#isucon
— kotaroooo0 (@kotaroooo0) 2020幎9æ12æ¥
ãŸããã¯ãšãªãç°¡æœã«ããããã«äºåã«èšç®ããŠã«ã©ã è¿œå ããããããšè¯ãã£ãããã§ãã äŸãã°ãç©ä»¶æ€çŽ¢ã§ãã¢ã®é«ããšããŠæå®ã§ããã®ã¯ 4 ãã¿ãŒã³ãããªãã®ã§ DB ã«ããã® 4 ãã¿ãŒã³ã§ä¿åãããããŸãã
ãããã«
åé¡ããã£ããšãã«æã¡æãã·ã¥ããšããããæããããããã«ãªããããªãšæããŸããã DB ã® CPU 䜿çšã 100%ã«åŒµãä»ããŠããã«ããã¯ã«ãªã£ãŠããã®ã¯åãããŸããããã¯ãšãªãæžãããªã³ã¡ã¢ãªåãè¡ãããã¯ãšãªã軜ããã INDEX ã貌ãããSELECT æãæé©åãããã¿ãããªéžæè¢ããåãããŸããã§ããã DB ãäºã€ã«åå²ããæã¡æã¯èããããŸããã§ããã ãŸããã«ã©ã ãè¿œå ããããšã«ãã£ãŠé«éåããæã¡æãèããããŸããã§ããã DB ã«é¢ããŠã¯ãæ®æ®µããã€ã³ãã©ã觊ã£ãŠã人ãªãçµéšããæãã€ãããããã®ããªãã
ããã§ãç·Žç¿ããããšã¯ã§ããããã¡ãããš ISUCON ã§ããã®ã§æºè¶³ã§ããã 次ã¯æ±ºåè¡ããŸã
3ã¶æã®ããã°ã¡ã³ã¿ãªã³ã°ãéããŠåŠãã ããšèããããš
ããã°ã¡ã³ã¿ãªã³ã°ã«ã€ããŠ
6, 7, 8 æãš @kakakakakkuããã®ããã°ã¡ã³ã¿ãªã³ã°ãåããŸããã é± 2 ã§èšäºãæçš¿ããã«ãŒã«ãå®ããŠãããéæã§ããªãæã¯æ¬¡ã®é±ã«è¶³ããªãåãè¿œå ã§æžããŸãã äŸãã°ãé£äžæ¯ã«ãªã 1 èšäºãæžããªãã£ãé±ããããŸãããã次ã®é±ã« 4 èšäºæžããŸããã ããã°ã¡ã³ã¿ãªã³ã°ã®å 容ã«ã€ããŠã¯ãã¡ãã詳ããã§ãã
å§ãããã£ãã
fukabori.fm ãèããŠãããš@kakakakakkuãããã²ã¹ãã§åºæŒããŠããåããããŸããã
é¢çœãã£ãã®ã§@kakakakakkuããã® Twitter ãèŠã«è¡ããšãããŸããŸããã°ã¡ã³ã¿ãŒãåéããŠããŸããã ã¡ããã©ããã°ãæžããŠãããããšããæããããããã°ãæžããªããšãããªãç¶æ³ã«è¿œã蟌ã¿ããã£ãã®ã§ãå¢ãã§å¿åããŠã¿ããšããã¡ã³ãã£ãŒã«éžã°ããŸããã
ææ
ããã°ã¡ã³ã¿ãªã³ã°ãç¶ããçµæã®ããã°è³Œèªè æ°ãš PV æ°ã®æ°å€ãšããŠã¯ä»¥äžã«ãªããŸãã
ããã°è³Œèªè æ°
ããã°è³Œèªè æ°: 0 人 -> 15 人
ããã°è³Œèªè æ°ã¯ãªããªã䌞ã³ãŸããã§ããã ä»ã¯ã賌èªãã¿ã³ãèŠã€ããããããŒãã䜿ã£ãã賌èªãã¿ã³ãå¢ãããããã賌èªãããããããã«ããŠããŸãã
PV æ°
- | 6 æ | 7 æ | 8 æ |
---|---|---|---|
PV | 395 | 373 | 9871 |
8 æ㯠2 èšäºããºã£ãã®ã§ã1 äž PV è¿ãã«ãªããŸããã @kakakakakkuããã« Twitter ã§ã·ã§ã¢ããŠããã ããããšããã£ããã«ã¯ãŠãã§äžäœã«ãªã PV ã䌞ã³ãŸããã Twitter ã®ãã©ãã¯ãŒæ°ã¯éèŠã§ãå€ããã°å€ãã»ã©æ¡æ£ãããããã®ã§ããã°ãšåæã« Twitter ãè²ãŠãå¿ èŠããããªãšæããŸããã äžåºŠãããºã£ãŠãã Twitter ã§ãã©ããŒãããããšãå¢ããã®ã§ãçæ¹ãå¢ããã°çæ¹ãå¢ããã埪ç°ã«å ¥ããŸãã
åããŠããºãçµéšãããŠãè³æ±ããããåºãŸããã ããºãããšãç®çã«èšäºãæžããªãããã«æ°ãã€ãããã§ãã ãŸããçŸåšã¯ã¯ãŠãã Twitter ãããäž»ãªæµå ¥ã§ãGoogle ããã®æµå ¥ããã£ãšå¢ãããšå®å®ã㊠PV ãå¢ãããšæããŸãã ãã®ããã«ã¯ãæ€çŽ¢ãããããããŒã¯ãŒãã«é¢ããèšäºãæžãããããå¿ èŠããããŸããããªãã®ããã«ããã°ãæžããŠãã®ãåãããªããªãã®ã§é£ãããšããã§ãã
ããã°ã¡ã³ã¿ãªã³ã°ã§åŠãã ããšãèããããš
誀åè±å
åã¯èªãåŽã§ãæžãåŽã§ããããŸã誀åè±åã¯æ°ã«ããªãã¿ã€ãã§ããã ããããããã°ãæžã以äžãèªãåŽãšããŠã¯è²ã ãªäººãããŸãã æè¡ã¡ã¢ã®ããã ãã«ããã°ãæžããªãè¯ãã§ãããæè¡çãã¬ãŒã³ã¹åäžãç»å£ããããªã©ã®ç®æšã®å Žåã¯ä¿¡é Œã«ç¹ããã®ã§æ°ãã€ããæ¹ãããã§ãã
ããããèªåã®ããã°ã®èª€åè±åã¯ãªããæ°ä»ãã«ããã®ã§ä»çµã¿ã§ã«ããŒããŸãããã åã¯ãtextlint + VS Code ãå ¥ããŠãŸãã çµå±ãåºæåè©ã¯æ ¡æ£ããŠãããªãã®èªåã§é 匵ããããããŸããã (VS Code ã®æ£ããè¡šèšãšãæ°ãã€ããªããšééããã)
ã€ã³ããããšã¢ãŠããããã®ãã©ã³ã¹
ããã€ã³ãããã®ã¢ãŠããããã®ãã©ã³ã¹ã倧åã«ããããšèããŸãã ããããåã¯ã€ã³ãããéå€ãå ·äœçã«ã©ãè¯ããªããåãããŸããã§ããã ããã¯çµå±ãªãããã°ãæžãã®ããšãã話ã«ãªããŸãã
1ã€ç®ã®çç±ã¯ããŸãã·ã³ãã«ã«èŠããŠããããšãã§ããªãããã§ãã äŸãã°ãã1 幎åã® 8 æã«ã©ããªä»äºãããŠããããã©ããªå匷ãããŠãããã1 ã¶æåäœã§ãæãåºãããšã¯é£ããã§ãã ã ããããå€éšèšæ¶è£ 眮ã§ããããã°ã«é ŒããŸãã åããããªèšäºãããŠæå³ããã®ãããããªãããããªãèšäºã§ããã®ããšæãããšããããŸãããæå€ãšèªå以å€ã®äººã«ã¯é¢çœããšæããŠãããããããããšãããããããããããããŠèªãŸããªããããããšæ°æ¥œã«èããŠããŸãã
2ã€ç®ã®çç±ã¯ãã€ã³ãããããæ°ã«ãªã£ãã ãã§ïŒç解床ãæµ ãããšãå€ãããã§ãã ãšã«ããè³ã«ã€ã³ããããããã®ããã¿ãã ããŠæžããšããè¡çºãã¢ãŠããããã«ãªããç解ãæ·±ãŸãäžã«å®çããããã§ãã å ããŠãããã°ãšããŠå ¬éããªããŠãããã®ã§ã¯ãšæããããããŸããããèŠããåæã§ãªãããæžããšç解ãæ·±ãŸããŸãã
æè¡çãªãã¬ãŒã³ã¹
å人ç
åãããã°ã 3 ã¶æéæžããŠããäžã§ã¯ã瀟å ã®å 茩ãšã³ãžãã¢ãåã®ããã°ãèªãã§åã®ããšãèªèããŠãããŠããããå¯æ¥ãæ¢ãäžã§ã¹ã«ãŠãã¡ãã»ãŒãžã«ããã°ã®ããšã«ã€ããŠè§ŠããããŠããããšããããŸããã ããã°ã«ãã£ãŠããã®äººã¯ããããããšãã§ããŠãããããããšã«èå³ããããã ãªãšåãããŸãã
äŒç€Ÿç
äŒç€Ÿã®ããã¯ããã°ãæžããããäŒç€Ÿã§ã®äºäŸããã¿ã«ç»å£ããããšã¯äŒç€Ÿã®æ¡çšã«ç¹ãããšæããŸãã çµç¹ãšããŠæè¡çãã£ã¬ã³ãžã«åãçµãã§ããããšãäŒããããšãã§ããŸãã ãŸããã©ããªäººãåããŠããã®ããäŒããããšãã§ããŸãã
ãã ãä»äºãšããŠæè¡åºå ±ãããå Žåã§ãã£ãããå€éšçºä¿¡ãè©äŸ¡ããŠãããããå Žåã«å®éçææšãå®ãã«ãããªãšæããŸããã åã¯æè¡åºå ±ã®ãããªæŽ»åã«ã¯èå³ããããŸããããããªãã¯é£ããã®ã§ããŸãã¯èªåäžäººã§ç©æ¥µçã«åããŠãææãåºããŠãä»ã®äººãåããŠããããã«ã«ãã£ãŒã«ãªã£ãŠãããã®ãããªããã ã¢ããã®ãªãŒããŒã·ãããçºæ®ã§ããã°ãªãšæããŸããã
ãããã«
ããã§ã¯ããã°ã®ããšã«ã€ããŠã®ã¢ãŠããããã§ãããããããã㯠LT ãç»å£ãªã©ãç©æ¥µçã«ãã£ã¬ã³ãžã§ããããããªãšæã£ãŠããŸãã 瀟å ã§ã¯ããŠã¿ãŸãããããªã³ã©ã€ã³ LT ã¯ãªããªãé£ããã§ããã
ãŸãããã®èšäºã«æžãããããªããšã¯ãããŸã§ãæ£ã èšãããŠããããšã§ãã ããã§ãããã°ãæžã人ãå€ããªãã®ã¯ãæ§ã ãªããŒãã«ãããããã ãšæããŸãã åã¯ããã°ãæžãããã¢ãŠããããããã®ã¯å¥œããªæ¹ãªã®ã§ãããã¯ããæå³åã®åŒ·ã¿ãªã®ããªãšæããŸããã
ããããã¯æ 2 æ¬ãç®å®ã«ããã°ãæçš¿ããŠãããŸãã
Goã®ãäœæ³ãåŠãã§ã»ã«ãã³ãŒãã¬ãã¥ãŒããŠã¿ã
ã¯ããã«
æ¥å以å€ã§ Go ã§ããŒã«ãäœã£ãããTwitter Bot ãäœã£ããããŠããŸãã ããããã³ãŒãã¬ãã¥ãŒãåããæ©äŒããªãè¯ã Go ã®æžãæ¹ã身ã«ã€ããªãã®ã§ã¯ãšäžå®ã«ãªããŸããã ããã§ãããŸããŸãªèšäºãåèã«ããŠã³ãŒãã®æžãæ¹ãåŠãã§ã¿ãŸããã
Return function calls
æåã« Go ã«è§Šããæã以äžã®ãšã©ãŒåŠçã®ãäœæ³ãæ°é®®ã«æããŸããã
if err != nil { return nil, err }
ãããªã®ã§ãã€ãã€ããªã«ãèããã«ããã䜿ããŸãã£ãŠããŸããŸãã 䜿ããªããŠããããšããã«ãŸã§äœ¿ã£ãŠããŸã£ãŠãããããããŸããã ãããããšã以äžã®ã³ãŒããæžããŠããŸãããšãããã§ãããã
func bar(arg string) (*Example, error) { v, err := foo(arg) if err != nil { return nil, err } return v, nil }
äžã®ã³ãŒãã¯ãé¢æ°ããã®ãŸãŸè¿ãããã§ååã§ãã
func bar(argstring) (*Example, error) { return foo(arg) }
err ã®ã¹ã³ãŒãã if ã«éã蟌ãã
以äžã®ãããšã©ãŒåŠçãæžããŠããŸã£ãŠããŸãããã
err := PostTweet(content) if err != nil { return err }
err
ã®ã¹ã³ãŒããif
ã®äžã«éã蟌ããæ¹ãããã§ãã
çç±ãšããŠãerr1
ãerr2
ãšãã£ãå€æ°ãäœãããã°ãå®ããªãããã§ãã
err1
ãè¿ãã¹ããšããã§err2
ãè¿ããŠããŸã£ããããããšããããããããŸããã
if err := PostTweet(content); err != nil { return err }
err
ã ãã§ãªãè€æ°ã®å€ãè¿ãå Žåã§ãããã®ããã«ããã»ããè¯ãããã§ãã
åºæ¬çã« main é¢æ°ä»¥å€ã§ã¯ error ãäžæµã«è¿ã
以äžã®ããã«panic
ã§ããã°ã©ã ã®éäžã§ä»¥äžçµäºããã®ã¯æšå¥šãããŠããŸããã
if err != nil { panic(err) }
main
ãŸã§ãšã©ãŒãäŒæãããŠãããmain
ã§äžåºŠã ããšã©ãŒåŠçãè¡ãã®ãè¯ãã§ãã
func main() { if err := run(); err != nil { log.Fatal(err) } } func run() error { // çç¥ }
goroutine(䞊ååŠç)ã§ã®ãšã©ãŒã®äŒæ
goroutine ã§ãšã©ãŒãäŒæãããŠãããšãã«å°ããŸããã
func getResponses() ([]*http.Response, error) { var responses []*http.Response mutex := sync.Mutex{} wg := sync.WaitGroup{} for i := 0; i < 10; i++ { wg.Add(1) go func() { res, err := randomResponse() if err != nil { // TODO: ãšã©ãŒãäŒæã§ããªã log.Fatal(err) } mutex.Lock() responses = append(responses, res) mutex.Unlock() wg.Done() }() } wg.Wait() return responses, nil }
以äžã¯getResponse
ã§ãšã©ãŒãçºçããŠããŠãäŒæãããããšãã§ããŠããŸããã
ãšã©ãŒãäŒæãããã«ã¯ãchannel ãäœãå€éšã§åãåããªã©å¥ã§å®è£
ããå¿
èŠããããŸãã
ãŸãã1 ã€ã® goroutine ã§ãšã©ãŒãçºçããå Žåã«ä»ã® goroutine ãçµäºããããã§ãã
ããã¯context
ã䜿ã£ãŠå¥ã§å®è£
ããå¿
èŠããããŸãã
errgroup ããã±ãŒãžã䜿ãããšã§ä»¥äžã®åé¡ã解決ã§ããŸãã
Go
ã¡ãœãããšWait
ã¡ãœããã§å®çŸããŸãã
func getResponsesErrGroups() ([]*http.Response, error) { var responses []*http.Response mutex := sync.Mutex{} eg, ctx := errgroup.WithContext(context.TODO()) for i := 0; i < 10; i++ { eg.Go(func() error { res, err := randomResponseContext(ctx) if err != nil { return err } mutex.Lock() responses = append(responses, res) mutex.Unlock() return nil }) } if err := eg.Wait(); err != nil { return nil, err } return responses, nil }
å éšå®è£ ã¯ãšãŠãã·ã³ãã«ã«ãªã£ãŠããé©ããŸããã
æ§é äœãåæåããæã¯å±æ§åãæå®ããŠãã
ãã®ããã«ã©ã¡ãã®æ¹æ³ã§ã宣èšã§ããŸãã
type Sample struct { Foo string, Bar int, } sample1 := Sample{ "example", 123 } sample2 := Sample{ Foo: "example", Bar: 123 }
以äžã®ããã«ãæ§é äœãå€æŽããŸãã
type Sample struct { Foo string, Bar int, Add string, // ãã®ãã£ãŒã«ããè¿œå }
ãããšãsample1
ã®å®£èšã¯ã³ã³ãã€ã«ãšã©ãŒãçºçããŸããsample2
ã®å®£èšã¯ã³ã³ãã€ã«ãšã©ãŒãçºçããŸããã
å人çã«ã¯ããšã©ãŒãåºãæ¹ãåæåå¿ããé²æ¢ã§ããã®ã§è¯ããšæããŸãããéãããã§ãã äºææ§ãéèŠããšã©ãŒãåºãªãæ¹ãããå±æ§åä»ãã§åæåããã®ãè¯ãããã§ãã
Go 1 and the Future of Go Programs - The Go Programming Language
åè
ISUCON: DBã®ããŒã¿ãã¡ã¢ãªã«èŒããŠé«éåãã
ã¯ããã«
ISUCON ã§ã¯ DB ã®ããŒã¿ãå¯èœãªãã°ãªã³ã¡ã¢ãªã«èŒãããšããå®ç³ããããŸãã
以äžã®ãããªèšäºãããããªã³ã¡ã¢ãªã«ãã ããæŠç¥ã§ãäºéžçªç Žã§ããã»ã©ã®ãã¯ããã¯ã§ãã
ãã®ããæ¹ã«ã€ããŠèšäºã«ããŸããã
ããæ¹
ISUCON9 äºéžã®åé¡ãäŸã«ããŸãã
ã©ã®ããŒã¿ããªã³ã¡ã¢ãªã«èŒããã
INSERT ã UPDATE ãªã©ã®æžã蟌ã¿ããªãããŒãã«ãã¡ã¢ãªã«èŒããŸãã æžã蟌ã¿ãããããŒãã«ãã¡ã¢ãªã«èŒããããšã¯äžå¯èœã§ã¯ãããŸããããæä»å¶åŸ¡ãå¿ èŠã«ãªãè€éã«ãªããŸãã ãŸããDB ã§ã¯ãªã¬ãŒã·ã§ã³ã«ã€ããŠãèããå¿ èŠããããŸãã
ããŒã«ã䜿ã£ãŠãæžã蟌ã¿ããªãããŒãã«ãæ¢ããŸãã äžåäžåèŠãŠãã£ãŠã¯æéãããããŸãããèŠééããçºçããŸãã
$ go get -u github.com/kotaroooo0/isucontools/sqlstr
$ cat main.go | sqlstr
INSERT, UPDATE, DELETE ã®ã¿ãæœåºãæžã蟌ã¿ãããããŒãã«ãåããã®ã§ãåæã«æžã蟌ã¿ããªãããŒãã«ãåãããŸãã
stdin.go:474:3 in postInitialize INSERT INTO `configs` (`name`, `val`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `val` = VALUES(`val`) ============== ç¥ ============== stdin.go:1842:19 in postComplete UPDATE `shippings` SET `status` = ?, `updated_at` = ? WHERE `transaction_evidence_id` = ? stdin.go:1855:19 in postComplete UPDATE `transaction_evidences` SET `status` = ?, `updated_at` = ? WHERE `id` = ? stdin.go:2102:19 in postBump UPDATE `items` SET `created_at`=?, `updated_at`=? WHERE id=? stdin.go:2252:26 in postRegister INSERT INTO `users` (`account_name`, `hashed_password`, `address`) VALUES (?, ?, ?)
ããŒãã« | configs |
users |
items |
transaction_evidences |
shippings |
categories |
---|---|---|---|---|---|---|
æžã蟌ã¿æã | â | â | â | â | â | à |
categories
ã¯ãªã³ã¡ã¢ãªã«èŒãããããã§ãã
ãŸããããã¿ããšconfigs
ã® INSERT ã¯postInitialize
å
ã§è¡ãããŠããã®ã§æåããåŒã³åºããããŸããã
ãªã®ã§ãconfigs
ããªã³ã¡ã¢ãªã«èŒãããããã§ãã
ã©ãå®è£ ããã
Go ã§categories
ããŒãã«ãã¡ã¢ãªã«èŒããŠã¿ãŸãã
1. ã°ããŒãã«ã§å€æ°ã宣èšããŸãã
var ( categoryMap = make(map[int]*Category) )
2. åæååŠç/initialize
ã§ã¡ã¢ãªã«èŒããŸãã
categories := []*Category{} if err := dbx.Select(&categories, "SELECT * FROM categories"); err != nil { log.Print(err) outputErrorMsg(w, http.StatusInternalServerError, "db error") return } for _, c := range categories { categoryMap[c.ID] = c }
3. SQL ãå©ããŠååŸããŠããéšåãã¡ã¢ãªã«èŒãã Map ããååŸããããã«å€ããŸãã
func getCategoryByID(q sqlx.Queryer, categoryID int) (category Category, err error) { // å ã ã®å®è£ // err = sqlx.Get(q, &category, "SELECT * FROM `categories` WHERE `id` = ?", categoryID) // if category.ParentID != 0 { // parentCategory, err := getCategoryByID(q, category.ParentID) // if err != nil { // return category, err // } // category.ParentCategoryName = parentCategory.CategoryName // } category = *categoryMap[categoryID] category.ParentCategoryName = categoryMap[category.ParentID].CategoryName return category, err }
以äžã® PR ã§å®è£ ããŸããã
categories
ããŒãã«
https://github.com/kotaroooo0/isucon9q/pull/1/files
config
ããŒãã«
https://github.com/kotaroooo0/isucon9q/pull/2/files
ãããã«
ä»åã¯æžã蟌ã¿ããªãããŒãã«ã®ãªã³ã¡ã¢ãªåã«ã€ããŠã§ããããæžã蟌ã¿ãããããŒãã«ã®ãªã³ã¡ã¢ãªå㯠Go ãªãsync.Mutex
ãå©çšããããšã§æä»å¶åŸ¡ãå®çŸã§ããŸãã
ã©ã®ãã㪠SQL ãå©ãããããªã©åå³ããªãããçšæ³çšéãå®ã£ãŠãªã³ã¡ã¢ãªåããã®ãè¯ãããã§ãã
ãªã³ã¡ã¢ãªã«ãšã«ããèŒãããšããã®ã¯çŸå®ã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ããŒã¿ã®æ°žç¶åãã§ããªãããã»ãŒè¡ãããŸããã ãŸããå°æå ã®ãã¯ããã¯æã匷ãã§ãã ãã®ããéå¶åŽãããããšæåŸ ãããŠããæ¹åçã§ã¯ãªãããªã³ã¡ã¢ãªåã«ããé«éåãã«ããåé¡ãåºé¡ãããåŸåã«ãããšãªã«ãã®èšäºã§èŠãŸããã