{"action":"created","comment":{"url":"https://api.github.com/repos/golangtokyo/shoten6/pulls/comments/272854872","pull_request_review_id":223604443,"id":272854872,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDI3Mjg1NDg3Mg==","diff_hunk":"@@ -0,0 +1,651 @@\n+={syossan27_title} GoとKafkaを用いた分散メッセージシステム入門\n+\n+== はじめに\n+株式会社ミクシィでエンジニアをしているsyossan27@<fn>{syossan27}です。\n+Goのシンプルな思想に惚れ込み、Goあんこ@<fn>{gounco}という勉強会の主催をやっています。\n+\n+//footnote[syossan27][@<href>{https://twitter.com/syossan27}]\n+//footnote[gounco][@<href>{https://gounconference.connpass.com/}]\n+\n+本章では、分散メッセージングミドルウェアであるKafkaをGoを通して学んでいきます。\n+簡単なKafkaの説明から始め、KafkaとGoを用いて簡単なシステムを作ってみるところまでをゴールとします。\n+\n+== Kafkaとは\n+\n+Kafkaとは、LinkedInで開発された分散メッセージングミドルウェアです。\n+背景として、LinkedIn上での大量のアクティビティデータを機械学習やフィード画面に表示するためのデータパイプラインとして、\n+\n+ * 高スループットによるリアルタイムストリーミング\n+ * パフォーマンスを損なわないメッセージストア\n+ * 耐障害性を保つための分散型システム\n+ * メッセージロストの防止\n+\n+を目的として開発されました。\n+開発以前に、ActiveMQを使った本番環境での運用を試してみたようなのですが、メッセージキューがメモリ容量を超えると急激なパフォーマンス低下を起こしたり、負荷分散のアプローチが多数の問題により頓挫したりとかなりの苦労があったようです。\n+\n+=== Kafkaの基礎知識\n+\n+Kafkaには分散メッセージングの仕組みとしてBroker、Topic、Partition、Offsetという要素があります。それぞれ詳しく見ていきましょう。\n+\n+==== Broker\n+\n+Brokerは１つのサーバにつき１つ存在する要素で、メッセージの受信・配信を担います。これらを複数でクラスタリングすることでメッセージングシステムの可用性を上げることが出来ます。実際に本番運用する際には必ずクラスタリングを行うようにしましょう。\n+\n+==== Topic\n+\n+Topicはメッセージを種別する要素で、例えばlog.createdという名前であればログの生成に関するメッセージを格納するTopicとして扱います。TopicはBrokerを構成する要素で、Broker内に１つから複数Topicまで存在します。メッセージの受信、配信先としてBrokerと併せて指定されます。\n+\n+==== Partition\n+\n+PartitionはTopicを更に分割する要素で、１つのTopicに対する膨大なメッセージのやり取りを分散させることで効率的に受信・配信することができます。\n+\n+==== Offset\n+\n+OffsetはPartitionに内包される要素で、Partitionで受信したメッセージにはそれぞれ連番となるOffset番号と呼ばれるものが割り当てられており、それをそれぞれのPartitionで位置情報として管理しています。\n+Offsetには３種類存在し\n+\n+ * Log End Offset : Partitionの末尾を表す\n+ * Current Offset : Consumerによって読み込まれた場所を表す\n+ * Commit Offset : メッセージがCommitされた場所を表す\n+\n+というものがそれぞれあります。ここでCommit Offsetだけが分かりにくい概念かと思いますが、「ここまでは確実に読み込まれましたよ」ということを確定しているOffsetになります。\n+\n+ここまでのイメージをまとめると以下のようになります。\n+\n+//image[syossan27-kafka-detail][イメージ図]{\n+//}\n+\n+=== Kafkaで何が出来るのか？\n+\n+このように既存のメッセージングミドルウェアが実現出来なかった機能を持ち合わせているKafkaですが、一体Kafkaを使って何が出来るのでしょうか？  \n+Kafkaの公式ページで紹介されているユースケースをもとに幾つか紹介していきます。@<fn>{Kafka-usecase}\n+\n+==== メッセージング\n+\n+ActiveMQやRabbitMQのようにオーソドックスなメッセージキューイングのブローカーとして使うことが出来ます。\n+他のミドルウェアと比べ、Kafkaは高スループットかつ耐障害性に勝るため、秒間のメッセージ量が多い大企業では好んで使われます。\n+ただし、耐障害性を高めるための各ノードへ向けたメッセージ複製という機構やブローカーを持つため、どうしてもそれを持たないミドルウェアにはスループットが敵わない面を持ちます。\n+ですので、障害時にメッセージをある程度ロストしても構わない、かつ大量のメッセージを捌くスループットが欲しいという場合にはレプリケーション機構を持たないNATS@<fn>{nats}や、ブローカーレスであるnanomsg@<fn>{nanomsg}、ZeroMQ@<fn>{zeromq}に軍配が上がります。\n+\n+==== アクティビティトラッキング\n+\n+元々LinkedInでアクティビティトラッキングのために開発されたため、勿論ですがアクティビティトラッキングに用いられることも多々あります。\n+アクティビティトラッキングはユーザー数やトラッキング種別数にも依りますが、多量のデータを捌く必要性があるため高スループットが求められます。\n+今まで述べた通り、Kafkaは高スループットを旨としておりLinkedInでは2012年の段階でピーク時に秒間17万メッセージをも捌いている実績があります。\n+現在のバージョンではさらなるパフォーマンス改善が施されているため、もっとメッセージを捌くことが出来ることでしょう。\n+\n+また、メッセージをHadoopなどデータウェアハウスへロードするためのconnectorが用意されているのも、好んで使われる一因だと思います。\n+\n+==== ストリーム処理\n+\n+ストリーム処理とは、増大し続けるデータを永続的に処理し続けることを指し、主に幾つかの処理ステップをそれぞれトピックに分け、処理を行い次のトピックへ送信といった形で順々にデータ加工をしていく流れを取ります。\n+また、Kafkaのv0.10からKafka Streamsというライブラリが同梱され、これを用いることで上記の処理の流れをアプリケーションで簡単に実現できるようになりました。\n+\n+==== イベントソーシング\n+\n+イベントソーシングとは、イベントを永続化させ必要に応じてリプレイすることで状態を作り出すアーキテクチャで、永続させるイベントストアとしてKafkaを用いる事ができます。  \n+注意点として、リプレイに必要なデータを保持するtopicの永続化に伴う適切なLog Compaction設定や、イベントをconsumeするtopic・リプライの中間データ用topicの適切な分割・設定などがあります。\n+\n+//footnote[nats][@<href>{https://nats.io/}]\n+//footnote[nanomsg][@<href>{https://github.com/nanomsg/nanomsg}]\n+//footnote[zeromq][@<href>{http://zeromq.org/}]\n+//footnote[Kafka-usecase][@<href>{https://Kafka.apache.org/uses}]\n+\n+== Go × Kafka\n+\n+さて、ここからは実際にKafkaとGoを組み合わせていきましょう。  \n+まず最初に読者の方が気になるのは「KafkaとGoの親和性ってどうなの？」というところだと思います。  \n+筆者は実際にKafkaとGoを使ったシステムを構築する中で、かなり親和性は高いのでは？と考えております。  \n+勿論、ベターな選択肢としてはJavaやScalaなどのJVM言語を使うのが賢明であると思いますが（clientが公式でサポートされているため）、Goに関しては非公式ライブラリであってもKafkaのバージョンアップについていけないということも無く、また言語特性として並列処理に長けているという点も多重Consumerでの処理の書きやすさに繋がっていると感じます。\n+\n+そんなGoとKafkaを使い、簡単なメッセージングシステムを組みながら分散メッセージの世界に入っていきましょう。\n+\n+=== 作成するシステムについて \n+\n+今回は以下のようなイメージのシステムを構築していきたいと思います。\n+\n+//image[syossan27-system-image][イメージ図]{\n+//}\n+\n+APIサーバ兼Producerの役割を持つアプリケーションを前段に置き、リクエストを受けたエンドポイント毎に対応したKafka BrokerのTopicへメッセージを送信します。そしてTopicからメッセージを受け取るConsumerを作成し、ログにメッセージを受け取ったことを出力するところまで作っていきましょう。\n+\n+=== ライブラリ選定\n+\n+GoでKafkaを扱うライブラリは幾つか存在します。\n+現在も活発に更新されている代表的なライブラリは以下の３つです。\n+\n+ * Shopify/sarama\n+ * confluentinc/confluent-kafka-go\n+ * segmentio/kafka-go\n+\n+Shopify/saramaはこの３つの中では一番Star数が多く、またポピュラーに使われているライブラリです。筆者もShopify/saramaを用いてシステム開発を行いましたが、特に問題もなく動いてくれました。またShopify, IBM, Herokuなど大手が使っていることからも信頼性が伺えます。","path":"articles/syossan27.re","position":121,"original_position":121,"commit_id":"f9616ca31bed41f674414b337700ae714eb16591","original_commit_id":"f9616ca31bed41f674414b337700ae714eb16591","user":{"login":"skanehira","id":7888591,"node_id":"MDQ6VXNlcjc4ODg1OTE=","avatar_url":"https://avatars2.githubusercontent.com/u/7888591?v=4","gravatar_id":"","url":"https://api.github.com/users/skanehira","html_url":"https://github.com/skanehira","followers_url":"https://api.github.com/users/skanehira/followers","following_url":"https://api.github.com/users/skanehira/following{/other_user}","gists_url":"https://api.github.com/users/skanehira/gists{/gist_id}","starred_url":"https://api.github.com/users/skanehira/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/skanehira/subscriptions","organizations_url":"https://api.github.com/users/skanehira/orgs","repos_url":"https://api.github.com/users/skanehira/repos","events_url":"https://api.github.com/users/skanehira/events{/privacy}","received_events_url":"https://api.github.com/users/skanehira/received_events","type":"User","site_admin":false},"body":"「くれた」は使わない方が良いそうなので、普通に「動きました」で良いかなと思います","created_at":"2019-04-07T22:27:24Z","updated_at":"2019-04-07T22:59:11Z","html_url":"https://github.com/golangtokyo/shoten6/pull/5#discussion_r272854872","pull_request_url":"https://api.github.com/repos/golangtokyo/shoten6/pulls/5","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/golangtokyo/shoten6/pulls/comments/272854872"},"html":{"href":"https://github.com/golangtokyo/shoten6/pull/5#discussion_r272854872"},"pull_request":{"href":"https://api.github.com/repos/golangtokyo/shoten6/pulls/5"}},"in_reply_to_id":272851625},"pull_request":{"url":"https://api.github.com/repos/golangtokyo/shoten6/pulls/5","id":268126896,"node_id":"MDExOlB1bGxSZXF1ZXN0MjY4MTI2ODk2","html_url":"https://github.com/golangtokyo/shoten6/pull/5","diff_url":"https://github.com/golangtokyo/shoten6/pull/5.diff","patch_url":"https://github.com/golangtokyo/shoten6/pull/5.patch","issue_url":"https://api.github.com/repos/golangtokyo/shoten6/issues/5","number":5,"state":"open","locked":false,"title":"GoとKafkaを用いた分散メッセージシステム入門","user":{"login":"syossan27","id":910446,"node_id":"MDQ6VXNlcjkxMDQ0Ng==","avatar_url":"https://avatars3.githubusercontent.com/u/910446?v=4","gravatar_id":"","url":"https://api.github.com/users/syossan27","html_url":"https://github.com/syossan27","followers_url":"https://api.github.com/users/syossan27/followers","following_url":"https://api.github.com/users/syossan27/following{/other_user}","gists_url":"https://api.github.com/users/syossan27/gists{/gist_id}","starred_url":"https://api.github.com/users/syossan27/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/syossan27/subscriptions","organizations_url":"https://api.github.com/users/syossan27/orgs","repos_url":"https://api.github.com/users/syossan27/repos","events_url":"https://api.github.com/users/syossan27/events{/privacy}","received_events_url":"https://api.github.com/users/syossan27/received_events","type":"User","site_admin":false},"body":"","created_at":"2019-04-07T18:23:21Z","updated_at":"2019-04-07T22:59:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7586765b54ea6e16ece696010547ec3708483514","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/golangtokyo/shoten6/pulls/5/commits","review_comments_url":"https://api.github.com/repos/golangtokyo/shoten6/pulls/5/comments","review_comment_url":"https://api.github.com/repos/golangtokyo/shoten6/pulls/comments{/number}","comments_url":"https://api.github.com/repos/golangtokyo/shoten6/issues/5/comments","statuses_url":"https://api.github.com/repos/golangtokyo/shoten6/statuses/f9616ca31bed41f674414b337700ae714eb16591","head":{"label":"syossan27:syossan27","ref":"syossan27","sha":"f9616ca31bed41f674414b337700ae714eb16591","user":{"login":"syossan27","id":910446,"node_id":"MDQ6VXNlcjkxMDQ0Ng==","avatar_url":"https://avatars3.githubusercontent.com/u/910446?v=4","gravatar_id":"","url":"https://api.github.com/users/syossan27","html_url":"https://github.com/syossan27","followers_url":"https://api.github.com/users/syossan27/followers","following_url":"https://api.github.com/users/syossan27/following{/other_user}","gists_url":"https://api.github.com/users/syossan27/gists{/gist_id}","starred_url":"https://api.github.com/users/syossan27/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/syossan27/subscriptions","organizations_url":"https://api.github.com/users/syossan27/orgs","repos_url":"https://api.github.com/users/syossan27/repos","events_url":"https://api.github.com/users/syossan27/events{/privacy}","received_events_url":"https://api.github.com/users/syossan27/received_events","type":"User","site_admin":false},"repo":{"id":180004875,"node_id":"MDEwOlJlcG9zaXRvcnkxODAwMDQ4NzU=","name":"shoten6","full_name":"syossan27/shoten6","private":false,"owner":{"login":"syossan27","id":910446,"node_id":"MDQ6VXNlcjkxMDQ0Ng==","avatar_url":"https://avatars3.githubusercontent.com/u/910446?v=4","gravatar_id":"","url":"https://api.github.com/users/syossan27","html_url":"https://github.com/syossan27","followers_url":"https://api.github.com/users/syossan27/followers","following_url":"https://api.github.com/users/syossan27/following{/other_user}","gists_url":"https://api.github.com/users/syossan27/gists{/gist_id}","starred_url":"https://api.github.com/users/syossan27/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/syossan27/subscriptions","organizations_url":"https://api.github.com/users/syossan27/orgs","repos_url":"https://api.github.com/users/syossan27/repos","events_url":"https://api.github.com/users/syossan27/events{/privacy}","received_events_url":"https://api.github.com/users/syossan27/received_events","type":"User","site_admin":false},"html_url":"https://github.com/syossan27/shoten6","description":"技術書典6に出す原稿","fork":true,"url":"https://api.github.com/repos/syossan27/shoten6","forks_url":"https://api.github.com/repos/syossan27/shoten6/forks","keys_url":"https://api.github.com/repos/syossan27/shoten6/keys{/key_id}","collaborators_url":"https://api.github.com/repos/syossan27/shoten6/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/syossan27/shoten6/teams","hooks_url":"https://api.github.com/repos/syossan27/shoten6/hooks","issue_events_url":"https://api.github.com/repos/syossan27/shoten6/issues/events{/number}","events_url":"https://api.github.com/repos/syossan27/shoten6/events","assignees_url":"https://api.github.com/repos/syossan27/shoten6/assignees{/user}","branches_url":"https://api.github.com/repos/syossan27/shoten6/branches{/branch}","tags_url":"https://api.github.com/repos/syossan27/shoten6/tags","blobs_url":"https://api.github.com/repos/syossan27/shoten6/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/syossan27/shoten6/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/syossan27/shoten6/git/refs{/sha}","trees_url":"https://api.github.com/repos/syossan27/shoten6/git/trees{/sha}","statuses_url":"https://api.github.com/repos/syossan27/shoten6/statuses/{sha}","languages_url":"https://api.github.com/repos/syossan27/shoten6/languages","stargazers_url":"https://api.github.com/repos/syossan27/shoten6/stargazers","contributors_url":"https://api.github.com/repos/syossan27/shoten6/contributors","subscribers_url":"https://api.github.com/repos/syossan27/shoten6/subscribers","subscription_url":"https://api.github.com/repos/syossan27/shoten6/subscription","commits_url":"https://api.github.com/repos/syossan27/shoten6/commits{/sha}","git_commits_url":"https://api.github.com/repos/syossan27/shoten6/git/commits{/sha}","comments_url":"https://api.github.com/repos/syossan27/shoten6/comments{/number}","issue_comment_url":"https://api.github.com/repos/syossan27/shoten6/issues/comments{/number}","contents_url":"https://api.github.com/repos/syossan27/shoten6/contents/{+path}","compare_url":"https://api.github.com/repos/syossan27/shoten6/compare/{base}...{head}","merges_url":"https://api.github.com/repos/syossan27/shoten6/merges","archive_url":"https://api.github.com/repos/syossan27/shoten6/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/syossan27/shoten6/downloads","issues_url":"https://api.github.com/repos/syossan27/shoten6/issues{/number}","pulls_url":"https://api.github.com/repos/syossan27/shoten6/pulls{/number}","milestones_url":"https://api.github.com/repos/syossan27/shoten6/milestones{/number}","notifications_url":"https://api.github.com/repos/syossan27/shoten6/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/syossan27/shoten6/labels{/name}","releases_url":"https://api.github.com/repos/syossan27/shoten6/releases{/id}","deployments_url":"https://api.github.com/repos/syossan27/shoten6/deployments","created_at":"2019-04-07T18:16:07Z","updated_at":"2019-04-07T18:16:09Z","pushed_at":"2019-04-07T18:22:33Z","git_url":"git://github.com/syossan27/shoten6.git","ssh_url":"git@github.com:syossan27/shoten6.git","clone_url":"https://github.com/syossan27/shoten6.git","svn_url":"https://github.com/syossan27/shoten6","homepage":null,"size":158,"stargazers_count":0,"watchers_count":0,"language":"TeX","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"golangtokyo:master","ref":"master","sha":"e5134b0ff0180ee579ba7ddc978186b2dcd598dc","user":{"login":"golangtokyo","id":30496683,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMwNDk2Njgz","avatar_url":"https://avatars1.githubusercontent.com/u/30496683?v=4","gravatar_id":"","url":"https://api.github.com/users/golangtokyo","html_url":"https://github.com/golangtokyo","followers_url":"https://api.github.com/users/golangtokyo/followers","following_url":"https://api.github.com/users/golangtokyo/following{/other_user}","gists_url":"https://api.github.com/users/golangtokyo/gists{/gist_id}","starred_url":"https://api.github.com/users/golangtokyo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/golangtokyo/subscriptions","organizations_url":"https://api.github.com/users/golangtokyo/orgs","repos_url":"https://api.github.com/users/golangtokyo/repos","events_url":"https://api.github.com/users/golangtokyo/events{/privacy}","received_events_url":"https://api.github.com/users/golangtokyo/received_events","type":"Organization","site_admin":false},"repo":{"id":171076175,"node_id":"MDEwOlJlcG9zaXRvcnkxNzEwNzYxNzU=","name":"shoten6","full_name":"golangtokyo/shoten6","private":false,"owner":{"login":"golangtokyo","id":30496683,"node_id":"MDEyOk9yZ2FuaXphdGlvbjMwNDk2Njgz","avatar_url":"https://avatars1.githubusercontent.com/u/30496683?v=4","gravatar_id":"","url":"https://api.github.com/users/golangtokyo","html_url":"https://github.com/golangtokyo","followers_url":"https://api.github.com/users/golangtokyo/followers","following_url":"https://api.github.com/users/golangtokyo/following{/other_user}","gists_url":"https://api.github.com/users/golangtokyo/gists{/gist_id}","starred_url":"https://api.github.com/users/golangtokyo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/golangtokyo/subscriptions","organizations_url":"https://api.github.com/users/golangtokyo/orgs","repos_url":"https://api.github.com/users/golangtokyo/repos","events_url":"https://api.github.com/users/golangtokyo/events{/privacy}","received_events_url":"https://api.github.com/users/golangtokyo/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/golangtokyo/shoten6","description":"技術書典6に出す原稿","fork":false,"url":"https://api.github.com/repos/golangtokyo/shoten6","forks_url":"https://api.github.com/repos/golangtokyo/shoten6/forks","keys_url":"https://api.github.com/repos/golangtokyo/shoten6/keys{/key_id}","collaborators_url":"https://api.github.com/repos/golangtokyo/shoten6/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/golangtokyo/shoten6/teams","hooks_url":"https://api.github.com/repos/golangtokyo/shoten6/hooks","issue_events_url":"https://api.github.com/repos/golangtokyo/shoten6/issues/events{/number}","events_url":"https://api.github.com/repos/golangtokyo/shoten6/events","assignees_url":"https://api.github.com/repos/golangtokyo/shoten6/assignees{/user}","branches_url":"https://api.github.com/repos/golangtokyo/shoten6/branches{/branch}","tags_url":"https://api.github.com/repos/golangtokyo/shoten6/tags","blobs_url":"https://api.github.com/repos/golangtokyo/shoten6/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/golangtokyo/shoten6/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/golangtokyo/shoten6/git/refs{/sha}","trees_url":"https://api.github.com/repos/golangtokyo/shoten6/git/trees{/sha}","statuses_url":"https://api.github.com/repos/golangtokyo/shoten6/statuses/{sha}","languages_url":"https://api.github.com/repos/golangtokyo/shoten6/languages","stargazers_url":"https://api.github.com/repos/golangtokyo/shoten6/stargazers","contributors_url":"https://api.github.com/repos/golangtokyo/shoten6/contributors","subscribers_url":"https://api.github.com/repos/golangtokyo/shoten6/subscribers","subscription_url":"https://api.github.com/repos/golangtokyo/shoten6/subscription","commits_url":"https://api.github.com/repos/golangtokyo/shoten6/commits{/sha}","git_commits_url":"https://api.github.com/repos/golangtokyo/shoten6/git/commits{/sha}","comments_url":"https://api.github.com/repos/golangtokyo/shoten6/comments{/number}","issue_comment_url":"https://api.github.com/repos/golangtokyo/shoten6/issues/comments{/number}","contents_url":"https://api.github.com/repos/golangtokyo/shoten6/contents/{+path}","compare_url":"https://api.github.com/repos/golangtokyo/shoten6/compare/{base}...{head}","merges_url":"https://api.github.com/repos/golangtokyo/shoten6/merges","archive_url":"https://api.github.com/repos/golangtokyo/shoten6/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/golangtokyo/shoten6/downloads","issues_url":"https://api.github.com/repos/golangtokyo/shoten6/issues{/number}","pulls_url":"https://api.github.com/repos/golangtokyo/shoten6/pulls{/number}","milestones_url":"https://api.github.com/repos/golangtokyo/shoten6/milestones{/number}","notifications_url":"https://api.github.com/repos/golangtokyo/shoten6/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/golangtokyo/shoten6/labels{/name}","releases_url":"https://api.github.com/repos/golangtokyo/shoten6/releases{/id}","deployments_url":"https://api.github.com/repos/golangtokyo/shoten6/deployments","created_at":"2019-02-17T03:05:21Z","updated_at":"2019-04-05T20:05:16Z","pushed_at":"2019-04-07T22:41:48Z","git_url":"git://github.com/golangtokyo/shoten6.git","ssh_url":"git@github.com:golangtokyo/shoten6.git","clone_url":"https://github.com/golangtokyo/shoten6.git","svn_url":"https://github.com/golangtokyo/shoten6","homepage":null,"size":68,"stargazers_count":5,"watchers_count":5,"language":"TeX","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":4,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":5,"license":null,"forks":4,"open_issues":5,"watchers":5,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/golangtokyo/shoten6/pulls/5"},"html":{"href":"https://github.com/golangtokyo/shoten6/pull/5"},"issue":{"href":"https://api.github.com/repos/golangtokyo/shoten6/issues/5"},"comments":{"href":"https://api.github.com/repos/golangtokyo/shoten6/issues/5/comments"},"review_comments":{"href":"https://api.github.com/repos/golangtokyo/shoten6/pulls/5/comments"},"review_comment":{"href":"https://api.github.com/repos/golangtokyo/shoten6/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/golangtokyo/shoten6/pulls/5/commits"},"statuses":{"href":"https://api.github.com/repos/golangtokyo/shoten6/statuses/f9616ca31bed41f674414b337700ae714eb16591"}},"author_association":"NONE"}}
{"actor":{"display_login":"skanehira"}}