ããã«ã¡ã¯ãã¡ã«ãã¤ã®ããã¯ã¨ã³ãã¨ã³ã¸ãã¢ã® @kazegusuri ã§ãã
2018å¹´10æ4æ¥ã«MTC (Mercari Tech Conf) 2018 ãéå¬ããã¾ããããæ¥å ´ãããçæ§ã楽ããã§ããã ããã§ããããï¼
ä»åã¯çæ§ãæåã«ç®ã«ããã§ãããã«ã³ãã¡ã¬ã³ã¹LPã®è£å´ã«ã¤ãã¦ç´¹ä»ãããã¨æãã¾ãã
å®ã¯ãã®ãã¼ã¸ã¯GitHubä¸ã§Publicãªãªãã¸ããªã¨ãã¦å
¬éããã¦ãã¾ãã
æ°ã¥ãããæ¹ãããã£ãããããããã¾ããããããã¯ã¤ãã³ãå¾ã«å
¬éããããã§ã¯ãªãããªãã¸ããªä½ææãããã£ã¨Publicãªç¶æ
ã§éçºãç¶ãã¦ãã¾ããã
ãã¼ã æ§æ
MTC2018ã§ã¯æåããWebã§ã®å
¬éã ãã§ã¯ãªãã«ã³ãã¡ã¬ã³ã¹ã¢ããªãä½ããã¨ããã®ã決ãã¦ãã¾ããã
ãã®ãã大ããåãã¦webãã¼ã ã¨appãã¼ã ã«åãã¦éçºããããããã¨ã«ãªãã¾ããã
web/appãã¼ã ã¯ã¡ã«ã«ãªã°ã«ã¼ãããæå¿ã§éã¾ã£ã¦æ§æããã¦ãã¾ãã
appãã¼ã ã«ã¤ãã¦ã¯å¾æ¥ããã°ãå
¬éãããã®ãæå¾
ããã¨ãã¦ãããã§ã¯webãã¼ã ã«ã¤ãã¦èª¬æãã¾ãã
webãã¼ã ã¯4åã®ã½ããã¦ã§ã¢ã¨ã³ã¸ãã¢+1åã®ãã¶ã¤ãã¼ã§æ§æããã¦ãã¾ã(å¶ç¶å ¨å¡ãã¡ã«ãã¤!)ã
- @kazegusuri: webãã¼ã ãªã¼ãã¼å ¼ã¤ã³ãã©, éç¨æ å½
- @sawa_zen: ããã³ãã¨ã³ãæ å½
- @vvakame: ããã¯ã¨ã³ãæ å½
- @adwd118: éææ å½
- @akonyakayama: ãã¶ã¤ã³æ å½
ãã®ã¡ã³ãã¼ã§æ¥åã¨ãã¦ã«ã³ãã¡ã¬ã³ã¹LPã®éçºã«åãçµã¿ã¾ããï¼
MTC2018 Webã®ã³ã³ã»ãã
ãããªã«ç´ æ´ãããã½ããã¦ã§ã¢ã¨ã³ã¸ãã¢ã®æ¹ãã¡ãéããã®ããä»åã®Webãä½ãéã®æåã®ã³ã³ã»ããããã¡ãã£ã¨ããLPãæ¬æ°ã§ä½ãããã¨ãããã¨ããã§ããã
ãã®ã³ã³ã»ããããå®éã«ãã¼ã ã¡ã³ãã¼ã®ä¸ã§è°è«ãã¦ãã¡ã«ã«ãªã»ã¡ã«ãã¤ãå®éã«ä½¿ã£ã¦ããæè¡ãç¥ã£ã¦ãããããã¨ãããã¨ã決ãã¾ããã
- æåããPublicãªãã¸ããªã¨ãã¦å ¬é
- Goã¨Node.jsã使ã£ããµã¼ããµã¤ãå®è£
- CircleCI/Spinnakerã«ããCI/CD
- Kubernetes(GKE)ã«ããã³ã³ãã管ç
- ãã¼ã¿ã¹ãã¬ã¼ã¸ã«Cloud Spanner
ãããããä»åã®ããã²ã¨ã¤ã®ã³ã³ã»ããã§ãããé¢ç½ãæè¡ã使ã£ã¦ã¿ããããããwebãã¼ã ã¨ãã¦ã¯ GraphQL ã使ããã¨ã«ãã¦ã¾ããã
GraphQLã§ããã³ãã¨ã³ããã«ã³ãã¡ã¬ã³ã¹ã¢ããªåãã«APIãæä¾ãã¾ãã
æçµçã«ãã®3ã¤ã®ã³ã³ã»ããã§éçºãé²ãã¾ããã
- ã¡ãã£ã¨ããLPãæ¬æ°ã§ä½ãã
- ã¡ã«ã«ãªã»ã¡ã«ãã¤ãå®éã«ä½¿ã£ã¦ããæè¡ãç¥ã£ã¦ãããã
- é¢ç½ãæè¡ã使ã£ã¦ã¿ãã
Goã¨Node.jsã使ã£ãéçºã®è©³ç´°ã«ã¤ãã¦ã¯ @vvakame 㨠@sawa_zen ã«ãããããã¾ããããã¨ãã¦æ®ãã®é¨åã«ã¤ãã¦ç´¹ä»ãããã¨æãã¾ãã
ã«ã³ãã¡ã¬ã³ã¹LPã®æ§æ
åé ã§è¿°ã¹ãã¨ããã½ã¼ã¹ã³ã¼ã㯠mtc2018-web ãªãã¸ããªã§å ¬éããã¦ãã¾ãããã®ãªãã¸ããªã§Node.jsã®å®è£ ã¨Goã®å®è£ ã®ä¸¡æ¹ã管çãã¦ãã¾ãã
https://techconf.mercari.com |- /2017 (MTC2017ã®LP) |- /2018 (MTC2018ã®LP) |- /2018/api (MTC2018ã®API)
MTC2017ã¨MTC2018ã®LPã¯Node.jsã®ãµã¼ãã§ãªã¯ã¨ã¹ããåãã¦ãããMTC2018ã®API(GraphQL)ãGoã®ãµã¼ãã§ãªã¯ã¨ã¹ããåãã¦ãã¾ããã«ã¼ãã£ã³ã°ã¯ GCLB(Google Cloud Load Balancing) ã§è¡ã£ã¦ãã¾ãã
GCLBã®å段ã«ã¯CDNã¨ãã¦Amazon CloudFrontãå©ç¨ãã¦ãã¾ãã
CircleCI/Spinnakerã«ããCI/CD
ã¡ã«ã«ãªã»ã¡ã«ãã¤ã§ã¯ç¾å¨ã¯CircleCIã«ããCIã主æµã§ãã
社å
ã®ãªãã¸ããªã§ã¯CircleCIã® context æ©è½ã使ã£ãå
±éã®ã¹ã¯ãªãããªã©ãæ´åããã¦ãã¾ãããä»åã¯ãããã使ããã«åç´ãªJobãè¤æ°çµã¿åããã¦workflowãä½ã£ã¦ãã¾ãã
mtc2018-web ãªãã¸ããªã§ã¯1ã¤ã®ãªãã¸ããªã§Node.jsã®å®è£
ã¨Goã®å®è£
ãå«ãã§ããã®ã§ãJobãããããã§ããã¦testãlintãªã©ãå®è¡ãã¦ãã¾ãã
ãããã®Jobãæåãããã¨ã«deployã®Job㧠Google Cloud Build ã使ã£ã¦Dockerã¤ã¡ã¼ã¸ã®ãã«ã㨠GCR(Google Container Registry) ã¸ã®ã¤ã¡ã¼ã¸ã®ã¢ãããã¼ããè¡ã£ã¦ãã¾ãã
Dockerã¤ã¡ã¼ã¸ãGCRã«ã¢ãããã¼ããããã¨ã¯CDã¨ãã¦Spinnakerãå©ç¨ãã¦ãã¾ããSpinnakerã¯ãããã¤ãã¤ãã©ã¤ã³ãå®ç¾©ã§ãããã¼ã«ã§ãã
ã¡ã«ã«ãªã»ã¡ã«ãã¤ã§ã¯å
±éã®Spinnakerã¯ã©ã¹ã¿ã使ã£ã¦ãããGCRã¸ã®ã¢ãããã¼ããããªã¬ã¼ã¨ãã¦Kubernetesã¸ã®ãããã¤ãã¦ãã¾ãã
mtc2018-web ãªãã¸ããªã§ã¯developã¿ã°ãã¤ãã¦ããã¤ã¡ã¼ã¸ã¯éçºç°å¢ã¸ãmasterã¿ã°ãã¤ãã¦ããã¤ã¡ã¼ã¸ã¯æ¬çªç°å¢ã¸ãããã¤ããããã«ãã¤ãã©ã¤ã³ãå®ç¾©ãã¦ãã¾ããGitHubä¸ã§ãã¼ã¸ããã ãã§åç°å¢ã¸ã®ãããã¤ãèªååããã¦ãã¾ãã
Kubernetes(GKE)ã«ããã³ã³ãã管ç
ã¡ã«ã«ãªã»ã¡ã«ãã¤ã§ã¯ã¡ã«ã«ãªã® Microservice Platform Team ã管çããKubernetesç°å¢ãå
±éã§å©ç¨ãã¦ãã¾ãã
ä»åã®ã«ã³ãã¡ã¬ã³ã¹LPãå
±éã®ç°å¢ãå©ç¨ãã¦éçºç°å¢ã¨æ¬çªç°å¢ãæä¾ãã¦ãã¾ãã
GCLBã¯GKEã®Ingressã使ã£ã¦æ§ç¯ããã¦ãã¾ãã
ãã¡ãã¯å®éã«é©ç¨ãã¦ããIngressã®è¨å®ãä¸é¨å¤æ´ãããã®ã§ãã
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: mtc2018 namespace: mtc2018 annotations: kubernetes.io/ingress.global-static-ip-name: "mtc2018" kubernetes.io/ingress.class: "gce" spec: tls: - secretName: tls-mtc2018 hosts: - mtc2018.xxx.com rules: - host: mtc2018.xxx.com http: paths: - path: "/2018/api/*" backend: serviceName: mtc2018-api servicePort: 80 - path: "/*" backend: serviceName: mtc2018-web servicePort: 80
- cert-manager ã«ããSSL証ææ¸ã®çºè¡
- external-dns ã«ããDNSã®è¨å®
- pathã«ããAPIã¨LPã®ã¨ã³ããã¤ã³ãã§ã®ã«ã¼ãã£ã³ã°
ããã§åãnamespaceå
ã« mtc2018-api
㨠mtc2018-web
ã¨ãã Serviceãç¨æãã¦ãããããAPIã¨LPã®Podã管çããã¦ãã¾ãã
ãã¼ã¿ã¹ãã¬ã¼ã¸ã«Cloud Spanner
ã¡ã«ãã¤ã§ã¯ã»ã¨ãã©ãã¹ã¦ã®ãã¤ã¯ããµã¼ãã¹ã§Cloud Spannerãã¡ã¤ã³ã®ãã¼ã¿ãã¼ã¹ã¨ãã¦å©ç¨ãã¦ãã¾ãã
ã«ã³ãã¡ã¬ã³ã¹LPã§ãã¨ããããSpannerã使ã£ã¦ä½ãä½ããã¨èãã¦ãã¾ããã
ãããæ®å¿µãªããæéã足ããã«æçµçã«ãªãããããæ©è½ãLikeæ©è½ã§ãã
ã»ãã·ã§ã³æ¯ã«Likeãä½åã§ãæ¼ãã¦ãä»äººã®Likeããªã¢ã«ã¿ã¤ã ã«èªåã®ç»é¢ã«åæ ããããããªä¼ç»ãèãã¦ãã¾ããã
ããã¯ã¨ã³ãå´ã¯ã»ã¨ãã©æ©è½çã«ã¯å®æãã¦ããããã®å®è£
ã§Spannerãå©ç¨ãã¦ãã¾ãã
ããã§ã¯Spannerã使ã£ãLikeæ©è½ã®å®è£
ã«ã¤ãã¦è©³ç´°ã«ç´¹ä»ãããã¨æãã¾ãã
Likeæ©è½
Likeæ©è½ã®ä»æ§ã¨ãã¦ã¯ä»¥ä¸ã®éãã§ãã
- ç¹å®ã®ã»ãã·ã§ã³ã«å¯¾ãã¦Likeã§ãã
- Likeã¯ä½åã§ãã§ãã
- ãã¨ããéè¨ã§ããããã«Likeã¯ãã¹ã¦ä¿åãã
- ãã°ã¤ã³ããªãã®ã§ã¦ã¼ã¶ã¼ã®ã¦ãã¼ã¯æ§ã¯ã¯ã©ã¤ã¢ã³ãå´ã§ãªãã¨ããã
- ä»ã®ã¦ã¼ã¶ã¼ãæ¼ããLikeããªã¢ã«ã¿ã¤ã ãåãåããã¨ãã§ãã
大ãããããã¨æ©è½çã«ã¯ãä¿åé¨åã¨ããã«å¿ããPub/Subé¨åã«ããããã¨ãã§ãã¾ãã
ä¿åé¨å
åºæ¬çã«ãã¼ã¿ãã¼ã¹ã«Insertããã ããªã®ã§é£ããã¯ãªãã®ã§ããã
Likeãã¦ã¼ã¶ã¼ã®æ°åã«å¿ãã¦æãã£ããé£æã§ããããã«ãããã£ãã®ã§ã¹ã±ã¼ã©ããªãã£ãã©ãã¾ã§èãããã課é¡ã¨ãªãã¾ãã
ä»åã¯çµå±ç¹ã«ç®æ¨å¤ãäºåã«æ±ºãããã¯ããªãã£ãã®ã§ãããã§ããéããããããã®å®è£
ãä½ã£ã¦ããã§æºè¶³ããã¨ããæ¹åæ§ã«ãã¾ããã
Likeã¯ãã¹ã¦ä¿åããå¿ è¦ãããã¨ããè¦ä»¶ãããæå»ãªã©ã®é åºæ§ããããã®ãPrimary Keyã«ãããã¨ã¯Spannerã®ç¹æ§ä¸é¿ãããã£ãã®ã§ãåç´ã«UUIDããã¼ã¨ãã¦ä¿åããã¨ããã¹ãã¼ãã«ãã¾ããããªã¢ã«ã¿ã¤ã ã®åç §ã®è¦ä»¶ããªãã£ãã®ã§ãéè¨ç¨éã ããªãGoogle BigQueryã«ããããè¯ãã¨èããããã§ãã
CREATE TABLE Likes ( Uuid STRING(64) NOT NULL, SessionId INT64 NOT NULL, UserUUID STRING(64) NOT NULL, CreatedAt TIMESTAMP NOT NULL, ) PRIMARY KEY(Uuid);
Spannerã®æ¸ãè¾¼ã¿ã¯GCE(Google Compute Engine)ãããªã¯ã¨ã¹ãããåã«ã¯ååæ©ã(~100ms)ã®ã¨UUIDãPrimary Keyã«ãããã¨ã§ååã«ã¹ã±ã¼ã«ããã®ã§åç´ã«Likeã®ãªã¯ã¨ã¹ãæ¯ã«ä¿åãã¦ãåé¡ãªãæ°ããã¾ãããæ°ã¥ããããã®æ¸ãè¾¼ã¿é¨åãæé©åãã¦ãã¾ãããæ¸ãè¾¼ã¿ãéåæã«ãã¦ãããå¦ççã«æ¸ãè¾¼ã¿ãè¡ãã¨ããã¢ã¤ãã¢ã¯åããããã£ãã®ã¨ pvpool ã®ãã¨ãç¥ã£ã¦ããã®ã§ãä¼¼ããããªå®è£ æ¹éã§é²ãã¾ããã
- Likeã®ãªã¯ã¨ã¹ãã§ã¯æ§é ä½ãã¤ã³ã¡ã¢ãªã®é åã«å ¥ããã ãã§ã¬ã¹ãã³ã¹ãè¿ã
- goroutineã§å®æçã«é åã®ä¸èº«ãSpannerã«ä¿åãã
åè ã¯ç¹ã«é£ãããªãã®ã§å²æãã¾ãããå¾è ã®å®è£ ã¯ãããªæãã§ãã
func (s *storer) Run() { ticker := time.NewTicker(time.Second) defer ticker.Stop() done := false for { select { case <-s.done: done = true break case <-ticker.C: } if done { break } go s.flushLikes() // 1ç§ã«1ågoroutineã§æ¸ãè¾¼ã¿å¦ç } } func (s *storer) flushLikes() { // é åã®ããã¯ãåã£ã¦ã³ãã¼ãã s.likesMu.Lock() likes := make([]domains.Like, len(s.likes)) copy(likes, s.likes) s.likes = s.likes[:0] s.likesMu.Unlock() // æ¸ãè¾¼ã¿å¦çå ¨ä½ã®ã¿ã¤ã ã¢ã¦ã parentCtx, cancel := context.WithTimeout(context.Background(), flushHardTimeout) defer cancel() for { select { case <-parentCtx.Done(): return default: } err := func() error { // æ¸ãè¾¼ã¿ã¿ã¤ã ã¢ã¦ã ctx, cancel := context.WithTimeout(parentCtx, flushTimeout) defer cancel() // LikeãSpannerã«ä¿å _, err := s.likeRepo.BulkInsert(ctx, likes) return err }() if err == nil { return } } }
ç´°ããã¨ãããèããã¨èª²é¡ã¯æ®ã£ã¦ãã¾ããæèããã¨ããã¨ãã¦ã¯
- flushLikes() èªä½ãgoroutineã«ãã¦å¾ç¶å¦çãè©°ã¾ããªãããã«ãã
- Spannerã«åé¡ããã£ãã¨ãã«goroutineãç¡éã«å¢ããªãããã« flushLikes() å ¨ä½ã«ã¿ã¤ã ã¢ã¦ããã¤ãã
- Spannerã®æ¥ç¶ã«ãã¾ãã¾åé¡ããã£ãã¨ãã«ãªãã©ã¤ã§ããããã«æ¸ãè¾¼ã¿å¦çåä½ã«ãã¿ã¤ã ã¢ã¦ããã¤ãã
Pub/Subé¨å
Pub/Subãã©ããã£ã¦å®ç¾ããããä¸çªé£ããåé¡ã§ããRedisãããã°æ¥½ãªã®ã§ãã ç¨æããã®ãé¢å Spannerã§ãªãã¨ãã¦ããããã¨ããå¼·ãæ°æã¡ã§é å¼µããã¨ã«ãã¾ããã
Spannerèªä½ã«æ¸ãè¾¼ã¿ãã¤ãã³ãã¨ãã¦åãåããããªæ©è½ã¯ãªãã®ã§èªåã§ä½ããã¨ã«ãã¾ãããåºæ¬ã®ã¢ã¤ãã¢ã¨ãã¦ã¯åãµã¼ãã¼ã§goroutineãåããã¦ããã¦ãå®æçã«ãã¼ãã«ãè¦ã¦æ´æ°ããã£ããéç¥ããã¨ãããã®ã§ãã
Likesã®ä¿åã§ãã¨ãã¨éåæã§æ¸ãè¾¼ã¿å¦çãè¡ãé¨åãã§ãã¦ããã®ã§ãPub/Subå¦çã3ã¤ã®å¦çã«åãããã¨ã«ãã¾ããã
- storer: Likeã®ä¿åã¨Likeã¤ãã³ãç¨ãã¼ã¿ã®ä¿å
- observer: Likeã¤ãã³ãç¨ãã¼ã¿ã®æ°è¦æ¸ãè¾¼ã¿ã®æ¤ç¥
- listener: subscriptionãã¦ããã¦ã¼ã¶ã¼ã¸ã®éç¥
Likeã®ä¿åç¨ãã¼ãã«ã¯UUIDãPrimary Keyã«ãã¦ãã¾ã£ããã¨ã¨æ¸ãè¾¼ã¿é »åº¦ãå¤ãã¦åç´ã«ä¿åæå»ã«ã¤ã³ããã¯ã¹ãè²¼ããã¨ã¯ã§ããªããã¨ããããã¨ã§observerãLikeã®æ¸ãè¾¼ã¿ãæ¤ç¥ããç®çã«ã¯å©ç¨ã§ãã¾ããã
ãã£ã¦ãLikeã®ä¿åã¨ã¯å¥ã«ã¤ãã³ãç¨ãã¼ã¿ãä½ã£ã¦ãããobserverãæ¤ç¥ããæ¹éã«ãã¾ããã
ããããéç¥ã®ãªã¢ã«ã¿ã¤ã æ§ãã©ãã¾ã§æ±ãããã¨ããè¦ä»¶æ¬¡ç¬¬ã§è¨è¨ãå¤ãã£ã¦ãã¾ãã
ä»åã¯ãã£ããã¨1,2ç§ããããªãè¯ãã ããã¨ãããã¨ãåæã«æ±ºãã¦ã1ç§æ¯ã®Likeæ°ãéç¥ãããã¨ã«ãã¾ããã
Likeæ°ååå¥ã«éç¥ãããã¨ãã§ãã¾ããããããããã©ãã£ãã¯çã«ãç¡é§ãå¤ãããªã®ã§ãæ°ã渡ãã¦ããã³ãã¨ã³ãå´ã§é å¼µã£ã¦ãã ããã¨ãããã¨ã«ãã¾ããã
ãããè¦ä»¶ããã¤ãã³ãç¨ãã¼ã¿ã®ä¿åã®æ¹éã¯
- 1ç§æ¯ã«ãã®æéä¸ã®Likeã®ã«ã¦ã³ããä¿åãã
- ã»ãã·ã§ã³æ¯ã«ä¿åãã
- ãµã¼ãæ¯ã«ä¿åãã
ã¤ãã³ãç¨ã®ãã¼ãã«ã¯ãã®ããã«ãªãã¾ããã
CREATE TABLE LikeSummaryServers ( Second INT64 NOT NULL, SessionId INT64 NOT NULL, ServerId STRING(64) NOT NULL, Likes INT64 NOT NULL, CreatedAt TIMESTAMP NOT NULL, ) PRIMARY KEY(Second, SessionId, ServerId);
æå»ãPrimary Keyã«ãã£ã¦ããã¨ããSpannerã«æªãè¨è¨ã§ããã1ç§æ¯ã«ã»ãã·ã§ã³æ°Ããµã¼ãã¼æ°ããæ¸ãè¾¼ã¾ãªããã¼ãã«ãªã®ã§Spannerã«é å¼µã£ã¦æ¬²ããã¨ãããã¨ã§è«¦ãã¾ããã
å®éã®ã¨ããã¯observerã®ã¯ã¨ãªãé å¼µãã°ã¤ã³ããã¯ã¹ã®é çªãå¤ãããã¾ãã
observerã¯ãã®ãã¼ãã«ããç¹å®ã®æå»(Second)ãæå®ãã¦Likesã®SUMãã¨ãã°ãã¹ã¦ã®ãµã¼ãã®Likeã®åè¨å¤ãåå¾ã§ãã¾ãã
ãã¦ããããããã®å®è£
æ¹éã® å°ç 課é¡ã®å§ã¾ãã§ãã
storerã¯1ç§ãã¨ã«èªèº«ã®ServerIdã«å¯¾å¿ããã¬ã³ã¼ããä¿åããã®ã§ããããã£ã¡ãæééãã«ã¬ã³ã¼ããä¿åãããä¿è¨¼ããªãã®ãåé¡ã§ãã
å
¨ã¦ã®ãµã¼ãããã£ã¡ã000msããæ¸ãè¾¼ã¿å¦çãéå§ãã¦ããã¦ã999msã¾ã§ã«æ¸ãè¾¼ã¿ãå®äºãã¦ããããè¯ãã®ã§ããã以ä¸ã®çç±ã§é£ããã§ãã
- æå»ã®å¶å¾¡ããã£ã¡ãè¡ãã®ã¯é£ãã
- Spannerã®æ¸ãè¾¼ã¿ã«æéãããå¯è½æ§ããã
- ãããããµã¼ãéã®æå»ãå®å ¨ã«åæããã¦ããããã§ã¯ãªã
ã¤ã¾ã該å½æé(Second)ã®ã¤ãã³ããã¼ã¿ã®æ¸ãè¾¼ã¿ãæ°ç§å¾ã«ç¾ããå¯è½æ§ãããã¾ãã
ãªã®ã§observerã¯åç´ã«ç´åã®æé(Second)ã ãã®ãã¼ã¿ãè¦ãã¨å®éã®åè¨æ°ã¨å¤§ãããããå¯è½æ§ãã§ã¦ãã¾ãã
observerã®æ¹éãå°ãå¤ãã¦ãç´è¿nç§éã®æéæ¯ã®SUMãåã£ã¦å¤åãè¦ãã¨ãããã¨ã«ãã¾ããã
ãããå
·ä½çãªä¾ã§è§£èª¬ããã¨
Time --------------------------> 1003 1004 1005 1006 Second 1005: 1 1004: 2 2 1003: 1 5 5 1002: 0 2 3 x 1001: 2 2 x x 1000: 1 x x x Increase: +3 +3 +7 +1
ããã¯ç´è¿3ç§éã§è¦ãå ´åã§ããã1003ç§ã®æç¹ã§1000,1001,1002ã®SUMã¯ãããã1,2,0ã ã¨ããã¨ã次ã®1004ç§ã®æç¹ã§è¦ã1003,1002,1001ã2,2,1ãªã®ã§ããããã®æéãã¨ã®å¢å ã¯0,2,1ã¨ãªãåè¨ã§+3ã¨ãªãã¾ãããããobserverã観測ãã1004ç§ã«ãããLikeæ°ã®åè¨å¤ã¨ãã¾ãã
listenerã¯GraphQLã®Subscriptionãè¡ã£ã¦ããã¯ã©ã¤ã¢ã³ãã®ç®¡çããã¦ãã¦ãã¾ãã
observerã観測ããLikeæ°ã®å¤åãchannelã§åãåã£ã¦ãåã¯ã©ã¤ã¢ã³ãã«Publishããã®ã責åã§ãã
ãã®ãããã¯ããã»ã©è¤éãªãã¨ããã¦ããªã(observerã¨æ¯è¼ãã¦)ã®ã§å²æãã¾ãã
ãããã®storer, observer, listenerã®å®è£
㯠ãã¡ã ã«ããã¦ããã¾ãã
2,3æ¥ã§ãããã¨ä½ã£ã¦ãã¡ããã¨ããæ¤è¨¼ãã§ãã¦ããããã§ã¯ãªãã®ã§å¤§å°ãã°ãæ®ã£ã¦ãã¾ããã ãããæå³éãåãã¦ãã¾ãã
Yo
Yoã¯ã¡ã«ã«ãªç¤¾å
ã§è©¦è¡é¯èª¤ä¸ã®Spannerç¨ã©ã¤ãã©ãªã§ããã¡ã«ãã¤ã®ããã¸ã§ã¯ãã®å¤ããYoã使ã£ã¦éçºããã¦ãã¾ãã
ã¤ãã³ãå½æ¥ã¾ã§ã«ã¯OSSã«ãããã¨ããææ°è¾¼ã¿ã§ãããªãã¯ã«ä½¿ãå§ããã®ã§ããã¾ã æ´åä¸ã§ããä¹ããæå¾
ãã ããï¼
ãããã«
ã¾ã ã¾ã OpenCensus ã使ã£ãã¢ãã¿ãªã³ã°ã®è¨å®ãªã©ç´°ããã¨ããã§è©¦ãã¦ã¿ããã¨ãããã¾ããããæ¬æ°ã§LPãä½ããã«ã¯è¶³ãã¦ããªãã¨ãããå¤ãæ®ã£ãã¾ã¾ã¨ãªãã¾ããã
æè¿ã¯ã«ã³ãã¡ã¬ã³ã¹ãµã¤ããä½ãã®ã好ããªäººã¨ããè¬ã®ç§°å·ãæã«å
¥ãã¾ãããã次åã¯ãã£ã¨æ¬æ°ã§ææ¦ãããã¨æãã¾ãï¼
ã¡ã«ã«ãªã»ã¡ã«ãã¤ã§ã¯æ¥åã¨ãã¦ã«ã³ãã¡ã¬ã³ã¹éå¶ãæä¼ã£ã¦ãã¾ãã次åã«åãã¦ã«ã³ãã¡ã¬ã³ã¹ãµã¤ãããæ¬æ°ã§ãä½ãããæ¹ãåéãã¦ãã¾ãï¼
次å㯠@vvakame ã API ã§å©ç¨ãã GraphQL é¨åã«ã¤ãã¦è§£èª¬ãã¦ãããã¨æå¾ ï¼