versiongRPCという言葉はすっかり有名になり、日本でも「社内でgRPCを導入した」「gRPCサーバーを構築する方法」といったような記事が溢れかえるようになりました。これにより、gRPCの導入ハードルは下がり、比較的簡単にプロダクションレディなgRPCサーバーを作ることが出来るようになりました。そもそもどういった背景でgRPCが誕生したのでしょうか。Blogには、以下のように記載されています。GoogleはstubbyというRPCインフラストラクチャ持っており、10年以上Googleのデータセンター内のマイクロサービスを接続してきた。統一されたクロスプラットフォームのRPCインフラストラクチャを持つことで、全体の効率、セキュリティ、信頼性の改善の展開を可能にし、その期間の信じられないほどの成長を支えた。stubbyには多くの素晴らしい機能があるが、社内のインフラに密接に結びつきすぎて一般公開には適していなかった。Stubbyをもっと汎用的に作り直して、モバイル、IoT、クラウド等のユースケースに適用させるべき時期が来たことが明らかになった。Blogには、以下のように記載されています。高度にスケーラブルで疎結合のシステムを構築することは、常に困難だった。モバイル機器やIoT機器の普及、データ量の急増、顧客の期待の高まりに伴い、インターネット規模で効率的かつ確実にシステムを開発して運用することが重要である。この種の環境では、開発者は複数の言語、フレームワーク、テクノロジー、複数の第一および第三者サービスを扱うことがある。これにより、サービス契約を定義して実施したり、認証や承認、ヘルスチェック、ロードバランシング、ロギングと監視、トレースなどの横断的な機能を全体にわたって一貫性を持たせることが難しくなる。今日のクラウドネイティブの世界では、新しいサービスをすばやく追加する必要があり、各サービスの期待は柔軟で弾力性があり、可用性が高く、構成可能であることが特に課題となる。過去15年間、Googleはこれらの問題を内部的にStubbyというRPCフレームワークで解決した。このRPCフレームワークは、数十億回のリクエストをインターネット規模で処理できるコアRPCレイヤーで構成されている。今この技術は、gRPCと呼ばれるオープンソースプロジェクトの一環として、誰でも利用可能である。これは、私たちがGoogleで楽しむのと同じスケーラビリティ、パフォーマンス、機能をコミュニティ全体に提供することを目的としている。GitHub間違い等ありましたら、コメントやtwitter等でご指摘頂けると嬉しいです。15:27gRPCは何故誕生したのかTweet広告を非表示にするもっと読むコメントを書く2018-09-17ISUCON8予選は学生枠6位で本戦出場が決まりましたGoisucon.netISUCON8の予選に、メルカリで一緒だった@zaq1tomoと@inatonixとzin-gonicというチーム名で出場しました。結果は学生枠6位だったので、やったこととかまとめます。二度のisucon合宿を行った(どちらも環境構築で頓挫)何回か集まってisucon7の過去問練習ishoconという株式会社scoutyさん主催のコンテストで練習したhidakkathonという株式会社会社サイバーエージェントさん主催のコンテストで練習した前日に当日と同じ要領でhidakkathonの問題をみんなでやったとまあ初出場ということもあり結構ちゃんと準備して、何も言い訳できない状況だったのでとりあえず通過できてよかったですやったことチューニング対象は、イベントの座席予約アプリでした。言語は、3人の技術スタック的にGo一択でした。序盤@nakabonnessh公開鍵登録dotfileをcloneベンチ走らせてhtopでリソース確認リスタートスクリプトの準備スロークエリログを仕込む再起動に備え、自動起動設定をするプロファイルングツールalpを仕込むログローテートスクリプトを仕込むalpに渡すためにh2oのアクセスログをLTSV形式にするリバースプロキシは完全にnginxのつもりでいたので、h2oアクセスログをalpがパースできる形式で出力するのに結構時間かかってしまって、大迷惑かけてしまいました。本戦では爆速でやりたいです。ちなみに今回はnginxに差し替えてる方が結構いたので、インフラ担当としてその辺のトレードオフも見積もれるようになりたいです。@zaq1tomoマニュアル読むひたすらコード読むpprofを仕込んでボトルネック探すスロークエリログ見ながらボトルネック探す方針決めリソース弱者の戦い方として、無理に複数台構成はしないと最初から決めていたため、ゴリゴリインメモリキャッシュを使おうと話していました。実行時にCPU使用率が100%に張り付くので、なるべくredis等の別プロセスは立ち上げたくないと感じたので、キャッシュするならGoプロセス管轄内のメモリに乗せようとなりました。mariadbが大分CPU食っているのでdbだけ別インスタンスに移したい気持ちはありました。スロークエリreservationsテーブルから全座席ごとにselectしてるクエリが37万回呼ばれていて、これを解消しない限り次に進まないことがすぐに分かりました。今回はボトルネックが明白だったため、学生でも迷わずに進める良問でした。先程の重いクエリが流れていたため、平均9秒かかっていました。その他レスポンスタイム上位のエンドポイントはほとんど同じクエリがボトルになっていました。NULLにマルチカラムインデックス張るのが正解だったっぽいです。単体テーブルへのクエリならまだいいのですが、内部結合となると実行計画が全く理解できず死亡しました。クエリ変えてクエリ数減らす僕のアクセスログ解析が遅れたせいもあり、全くスコアが上がらず完全にお通夜モードになっていた15時頃(だったかな)に、@zaq1timoのN+1修正が火を吹き1000点→10000点と10倍になりました。/api/users/:idの平均レスポンスタイムも9秒→1秒まで解消していました。終盤@zaq1tomoが合計料金をSUMするクエリをチューニングしてくれてちょっとスコアが上がり、諸々のログを吐かないようにしたら13000点を超えるようになりました。ランダムにfailしたりしてハラハラしていました。競技30分前に再起動し最終的に14000点を超えたところでコードフリーズし、お片付けを始めました。感想1392名参加している大会で、障害等を何も起こさなかった運営の方々がかっこよすぎました。今回は各チームごとにベンチマークを用意してくれた(構成的にするしかなかった)Conohaさんにも感謝の念が溢れます。speakerdeck.comクリーンアーキテクチャとは以下を実現することで、関心の分離をするアーキテクチャパターンです。ドメインロジックを独立させるフレームワークを独立させるUIを独立させるDB含む外部の全てを独立させるドメインロジックをテストしやすくする詳しくは様々な記事で説明されているので、今エントリでは割愛し実装パターンに絞って紹介します。POSTすることでユーザー登録するだけのapiです。基本はmanuelkiessling/go-cleanarchitectureやhirotakan/go-cleanarchitecture-sampleを参考にしていますがこれらはDBアクセスに直接sqlドライバーを使用しているため、今回はORMを使用した実装パターンを作ってみました。ORMライブラリはgormを使用しています。何層に分けるかは自由なのですが、閉鎖性共通の原則(CCP)に則って分けます。同じ理由で変更するコンポーネントはまとめます。今回は原文に従って4層に分けました。この時、外側から内側に向かって単一方向に依存することを徹底します。interfaces各ディレクトリは、それぞれ以下の層の役割をしています。rules依存関係の徹底(重要)実装の説明に入る前に、大事なルールを一つ説明します。前述したとおり、依存関係は外側から内側へ単一方向へ保つ必要があります。どんなプログラムにも入力と出力があり、内側で処理した結果を外側へ出力するということが頻繁に起こります。内側から外側へ依存したい場面が必ず現れます。その矛盾を依存関係逆転の原則を用いて解決することが、クリーンアーキテクチャをクリーンに保つための鍵となります。依存関係逆転の原則(DIP)とは簡単に言うと、内側は外側に依存するのではなく、抽象に依存するべきであるという原則です。わからないと思うので、実際にコードを見てみましょう。この層の外側から渡されたユーザデータを、外側にあるDBに保存しようとしています。ここでやってしまいがちなのが、そのまま外側の層にアクセスしてしまうことです。外側に直接アクセスしてしまうと依存関係が内→外に向いてしまうので避けたいところです。そこで依存関係逆転の原則を使います。Goではこれをinterfaceを定義することで実現します。error)}同じ層にrepositoryインターフェースを定義し、このインターフェースに依存するようにします。具象は外側で定義しておき、実行時に外側から渡してあげることで外→内の依存関係を保つことができます。これが依存関係逆転の原則です。ここを見ると分かりやすいかと思います。サンプルコードでは、抽象に依存するためのinterfaceを各層のinterfacesディレクトリにまとめてあります。内側の2層はプロジェクトによって結構変わってくると思うので、ここでは外側の2層に絞って説明していきます。DriversDBアクセス以下のようなDB接続等の外部との仲介実装はこの層で完結するようにします。db.Close()}ルーティングhttp通信処理もこの層で完結します。今回はWAFにginを使用していますが、この層が独立しているので差し替えが容易になっています。DBのコネクションやlogger等の具象型もここで内側の層に渡すようにしています。することで、前述した依存関係逆転の原則を実現しています。AdaptersORMのマッパーもここで定義します。ここでは、DB用に最適化された型をドメインロジック用に最適化された型に変換することで、インピーダンス・ミスマッチを解決することに徹しています。adapter層は抽象に依存しているとはいえ、この層で定義するinterfaceは外側のライブラリにある程度依存してしまいます。「抽象」は実装の詳細に依存してはならないとされていますが、この層は変換が目的なので、ある程度どちらのことも知っているのが自然かと思います。ここに関してもっと良い実装パターンをご存知の方がいらしたらご教授願いたいです。nil}まとめ見ての通り、user登録するだけのapiでもこんな大きなプロジェクトになってしまいます。抽象化することで関心を分離することができますが、そこまでして分離する必要があるかはよく考える必要がありそうです。基本的に抽象化するとコードは複雑化し、直感的ではなくなるので、アプリケーションの規模が小さい場合は効力を発揮しない場合が多いと思います。何か間違いがあればご指摘頂けると大変助かります。Architectureのサンプル実装Tweet広告を非表示にするもっと読むコメントを書く2018-05-29csvをGoの構造体にマッピングするGoGoでcsvを扱う際は、標準パッケージのendording/csvで対応できますが、いちいちスライスを扱うのは少しつらいものがあります。場合構造体にマッピングした方が扱いやすいため、その方法を紹介していこうと思います。csvマッピングライブラリはjszwec/csvutilやgocarina/gocsvがありますが、今回は前者を使っていきます。`csv:"name"`}以下のuser.csvを読み込みます。18:47csvをGoの構造体にマッピングするTweet広告を非表示にするもっと読むコメントを書く2018-05-20【Go】エディタ操作用簡易ライブラリを作ったGoはじめにしっかりエディタでファイルオープンするとなると意外に煩雑になることに気づきました。そこでedindというライブラリに切り出したので、今回はその紹介をしたいと思います。github.com使い方クイックスタートFactoryを生成し、エンドユーザーのシェルで実行可能なエディタを検出します。メソッドを使用します。15:22【Go】エディタ操作用簡易ライブラリを作ったTweet広告を非表示にするもっと読むコメントを書く2018-03-245分でElasticsearch+Kibanaの環境を作るelasticsearch動機とりあえずローカルで一刻も早く動かしたい場合にサクッと構築する手順をまとめます。http://localhost:5601にブラウザでアクセスし、kibanaの画面にアクセス補足xpackというパッケージの機能を全てオフにすることで、認証なしでリクエストを送ることが出来るようになります。ローカルで試したい場合はこれらを外すことでスムーズに行なえます。xpackとは何でしょうか。公式ガイドには以下のように書かれています。Stackの拡張機能です。elasticsearchクライアントライブラリの選定elastic/go-elasticsearch(公式)olivere/elastic以上の2つが候補としてあげられます。どちらかというとGoらしく書ける印象だった2つ目のolivere/elasticを今回は使用します。クライアントの生成olivere/elasticは使用しているelasticsearchのバージョンごとにライブラリのブランチも切られています。今回はelasticsearchバージョン5を使用しているので、gopkg.in/olivere/elastic.v5をimportして使用します。error)を呼び出すことによってクライアントを生成します。ClientOptionFunc型の値を引数に与えることによってクライアントの設定を行います。Serviceを使用します。そのため、NewClient時にHTTPクライアントをurlfetch.Clientに差し替える必要があります。先程生成したクライアントを使用してelasticsearchのデータを操作していきます。詳しくはwikiを参照して下さい。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。