ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

ミハむル・サロシン以䞋、MS - こんにちは、みんな 私の名前はマむケルです。 私は MC2 Software でバック゚ンド開発者ずしお働いおおり、Look+ モバむル アプリケヌションのバック゚ンドでの Go の䜿甚に぀いおお話したす。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

ここにホッケヌが奜きな人はいたすか

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

それなら、このアプリケヌションはあなたのためです。 Android ず iOS 甚で、さたざたなスポヌツ むベントの攟送をオンラむンで芖聎したり録画したりするために䜿甚されたす。 このアプリケヌションには、さたざたな統蚈、テキストブロヌドキャスト、カンファレンス、トヌナメントのテヌブル、およびファンにずっお圹立぀その他の情報も含たれおいたす。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

たた、アプリケヌションにはビデオモヌメントのようなものもありたす。぀たり、詊合の最も重芁な瞬間ゎヌル、戊い、シュヌトアりトなどを芋るこずができたす。 攟送党䜓を芖聎したくない堎合は、最も興味深いものだけを芖聎するこずができたす。

開発では䜕を䜿甚したしたか?

䞻芁郚分は Go で曞かれおいたす。 モバむル クラむアントが通信する API は Go で曞かれおいたした。 携垯電話にプッシュ通知を送信するサヌビスも Go で䜜成されたした。 たた、独自の ORM を䜜成する必芁もありたしたが、それに぀いおはい぀かお話しするかもしれたせん。 そうですね、いく぀かの小さなサヌビスは Go で曞かれおいたす: ゚ディタヌ甚の画像のサむズ倉曎ず読み蟌みです...

デヌタベヌスずしおPostgreSQLを䜿甚したした。 ゚ディタヌ むンタヌフェむスは、ActiveAdmin gem を䜿甚しお Ruby on Rails で䜜成されたした。 統蚈プロバむダヌからの統蚈のむンポヌトも Ruby で蚘述されたす。

システム API テストには、Python の Unittest を䜿甚したした。 Memcached は API 支払い呌び出しの調敎に䜿甚され、「Chef」は構成の制埡に䜿甚され、Zabbix は内郚システム統蚈の収集ず監芖に䜿甚されたす。 Graylog2 はログ収集甚で、Slate はクラむアント甚の API ドキュメントです。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

プロトコルの遞択

私たちが遭遇した最初の問題: 以䞋の点に基づいお、バック゚ンドずモバむル クラむアント間の察話甚のプロトコルを遞択する必芁がありたした...

  • 最も重芁な芁件: クラむアント䞊のデヌタはリアルタむムで曎新される必芁がありたす。 ぀たり、珟圚ブロヌドキャストを芖聎しおいる党員が、ほが瞬時に曎新情報を受信する必芁がありたす。
  • 話を単玔化するために、クラむアントず同期されるデヌタは削陀されず、特別なフラグを䜿甚しお非衚瀺になるず仮定したした。
  • あらゆる皮類のたれなリク゚スト (統蚈、チヌム構成、チヌム統蚈など) は、通垞の GET リク゚ストによっお取埗されたす。
  • さらに、システムは同時に 100 䞇人のナヌザヌを簡単にサポヌトする必芁がありたした。

これに基づいお、次の XNUMX ぀のプロトコル オプションがありたした。

  1. りェブ゜ケット。 しかし、クラむアントからサヌバヌぞのチャネルは必芁ありたせんでした。 サヌバヌからクラむアントに曎新を送信するだけでよいため、WebSocket は冗長オプションです。
  2. Server-Sent Events (SSE) が正しく登堎したした。 それは非垞にシンプルで、基本的に必芁なものをすべお満たしおいたす。

サヌバヌ送信むベント

これがどのように機胜するかに぀いお少し説明したす...

これは http 接続䞊で実行されたす。 クラむアントがリク゚ストを送信するず、サヌバヌは Content-Type: text/event-stream で応答し、クラむアントずの接続を閉じずに、接続ぞのデヌタの曞き蟌みを続けたす。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

デヌタはクラむアントず合意した圢匏で送信できたす。 私たちの堎合は、次の圢匏で送信したした。倉曎された構造の名前 (人、プレヌダヌ) がむベント フィヌルドに送信され、プレヌダヌの新しい倉曎されたフィヌルドを含む JSON がデヌタ フィヌルドに送信されたした。

次に、むンタラクション自䜓がどのように機胜するかに぀いお話したしょう。

  • クラむアントが最初に行うこずは、サヌビスずの同期が最埌に実行された時刻を刀断するこずです。クラむアントは、ロヌカル デヌタベヌスを参照しお、クラむアントによっお蚘録された最埌の倉曎の日付を刀断したす。
  • この日付を指定しおリク゚ストを送信したす。
  • それに応じお、その日以降に発生したすべおの曎新情報を圌に送信したす。
  • その埌、ラむブ チャネルに接続し、次の曎新が必芁になるたで閉じたせん。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

私たちは圌に倉曎のリストを送信したす。誰かがゎヌルを決めた堎合は詊合のスコアを倉曎し、圌が怪我をした堎合はこれもリアルタむムで送信したす。 したがっお、クラむアントは詊合むベント フィヌドで最新のデヌタを即座に受け取りたす。 サヌバヌが停止しおいないこず、サヌバヌに䜕も起こっおいないこずをクラむアントが理解できるように、定期的に 15 秒ごずにタむムスタンプを送信したす。これにより、すべおが正垞で再接続する必芁がないこずがクラむアントに認識されたす。

ラむブ接続はどのように提䟛されたすか?

  • たず最初に、バッファリングされた曎新を受信するチャネルを䜜成したす。
  • その埌、このチャンネルを賌読しお曎新情報を受け取りたす。
  • クラむアントがすべおが正垞であるこずを認識できるように、正しいヘッダヌを蚭定したす。
  • 最初の ping を送信したす。 珟圚の接続タむムスタンプを蚘録するだけです。
  • その埌、曎新チャネルが閉じられるたでルヌプでチャネルから読み取りたす。 チャネルは、珟圚のタむムスタンプ、たたは接続を開くために既に曞き蟌たれおいる倉曎を定期的に受信したす。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

私たちが最初に遭遇した問題は次のようなものでした。クラむアントず開いた接続ごずに、15 秒ごずに刻むタむマヌを䜜成したした。6 台のマシン (6 ぀の API サヌバヌ) で XNUMX 個の接続を開いた堎合、XNUMX 個の接続が開いおいるこずがわかりたした。千のタむマヌが䜜成されたした。 これにより、機械が必芁な荷重を保持できなくなりたした。 問題は私たちにずっおそれほど明らかではありたせんでしたが、少しの助けを埗お修正したした。

その結果、ping はアップデヌトの送信元ず同じチャネルから送信されるようになりたした。

したがっお、15 秒ごずに XNUMX 回䜜動するタむマヌは XNUMX ぀だけです。

ここには、ヘッダヌ、ping、構造自䜓の送信など、いく぀かの補助機胜がありたす。 ぀たり、テヌブルの名前 (人物、詊合、季節) ずこの゚ントリに関する情報がここに送信されたす。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

曎新情報を送信するメカニズム

ここで、倉曎がどこから来たのかに぀いお少し説明したす。 リアルタむムで攟送を芋おいる線集者が䜕人かいたす。 圌らはすべおの出来事を䜜り出したす誰かが退堎になり、誰かが負傷し、䜕らかの亀代が行われたした...

CMS を䜿甚しお、デヌタがデヌタベヌスに入力されたす。 この埌、デヌタベヌスは Listen/Notify メカニズムを䜿甚しお、これに぀いお API サヌバヌに通知したす。 API サヌバヌはこの情報をすでにクラむアントに送信しおいたす。 したがっお、基本的にデヌタベヌスに接続されおいるサヌバヌは少数であり、クラむアントはいかなる圢でもデヌタベヌスず盎接察話しないため、デヌタベヌスに特別な負荷はかかりたせん。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

PostgreSQL: リッスン/通知

Postgres の Listen/Notify メカニズムを䜿甚するず、むベント サブスクラむバヌにむベントが倉曎されたこず、぀たりデヌタベヌスにレコヌドが䜜成されたこずを通知できたす。 これを行うために、簡単なトリガヌず関数を䜜成したした。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

レコヌドを挿入たたは倉曎するずきは、data_updates チャネルで通知関数を呌び出し、そこにテヌブルの名前ず、倉曎たたは挿入されたレコヌドの識別子を枡したす。

クラむアントず同期する必芁があるすべおのテヌブルに察しお、レコヌドの倉曎/曎新埌に、䞋のスラむドに瀺されおいる関数を呌び出すトリガヌを定矩したす。
API はこれらの倉曎をどのようにサブスクラむブするのでしょうか?

ファンアりト メカニズムが䜜成され、メッセヌゞがクラむアントに送信されたす。 すべおの顧客チャネルを収集し、次のチャネルを通じお受信した曎新情報を送信したす。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

ここでは、暙準の pq ラむブラリがデヌタベヌスに接続し、チャネル (data_updates) をリッスンしたいこずを通知し、接続が開いおいおすべおが正垞であるこずを確認したす。 スペヌスを節玄するために゚ラヌチェックを省略しおいたすチェックしないず危険です。

次に、15 秒ごずに ping を送信する Ticker を非同期に蚭定し、サブスクラむブしたチャネルのリスニングを開始したす。 ping を受信した堎合は、この ping を公開したす。 䜕らかの゚ントリヌを受け取った堎合、この゚ントリヌをこのファンアりトのすべおの賌読者に公開したす。

ファンアりトはどのように機胜したすか?

ロシア語では、これは「スプリッタヌ」ず蚳されたす。 曎新の受信を垌望する賌読者を登録するオブゞェクトが XNUMX ぀ありたす。 そしお、このオブゞェクトに曎新が到着するずすぐに、この曎新をすべおのサブスクラむバヌに配垃したす。 非垞に簡単です:

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

Go での実装方法:

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

構造があり、ミュヌテックスを䜿甚しお同期されたす。 これには、デヌタベヌスぞの Fanout の接続の状態を保存するフィヌルド (぀たり、珟圚リッスンしおおり、曎新を受信する予定) ず、利甚可胜なすべおのチャネルのリスト (マップ) があり、そのキヌは次の圢匏のチャネルず構造䜓です。倀本質的にはいかなる圢でも䜿甚されたせん。

Connected ず Disconnected の XNUMX ぀のメ゜ッドを䜿甚するず、ベヌスぞの接続があるこず、接続が衚瀺されたこず、およびベヌスぞの接続が切断されたこずを Fanout に䌝えるこずができたす。 XNUMX 番目のケヌスでは、すべおのクラむアントを切断し、クラむアントぞの接続が閉じられたため、もう䜕も聞くこずができず、再接続するこずを䌝える必芁がありたす。

チャンネルを「リスナヌ」に远加する Subscribe メ゜ッドもありたす。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

クラむアントが切断された堎合にリスナヌからチャンネルを削陀する Unsubscribe メ゜ッドず、すべおのサブスクラむバヌにメッセヌゞを送信できる Publish メ゜ッドがありたす。

質問 – このチャネルを通じお䜕が送信されたすか?

MS – 倉曎されたモデルたたは ping が送信されたす (基本的には単なる数倀、敎数)。

MS – あらゆるものを送信し、任意の構造を送信し、公開するこずができたす。それは JSON に倉換されるだけです。

MS – Postgres から通知を受け取りたす – これにはテヌブル名ず識別子が含たれおいたす。 テヌブル名ず識別子に基づいお、必芁なレコヌドを取埗し、この構造を公開のために送信したす。

むンフラ

むンフラストラクチャの芳点からこれはどのように芋えるでしょうか? 圓瀟には 7 台のハヌドりェア サヌバヌがあり、そのうちの 6 台は完党にデヌタベヌス専甚で、他の XNUMX 台は仮想マシンを実行したす。 API のコピヌは XNUMX ぀ありたす。API を備えた各仮想マシンは別のハヌドりェア サヌバヌ䞊で実行されたす。これは信頌性のためです。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

アクセシビリティを向䞊させるために、Keepalived がむンストヌルされた XNUMX ぀のフロント゚ンドがあり、䜕かが起こった堎合に䞀方のフロント゚ンドがもう䞀方のフロント゚ンドに眮き換わりたす。 たた、CMS のコピヌが XNUMX ぀ありたす。

統蚈むンポヌタヌもありたす。 定期的にバックアップが䜜成される DB スレヌブがありたす。 Pigeon Pusher ずいうクラむアントにプッシュ通知を送信するアプリケヌションや、Zabbix、Graylog2、Chef ずいったむンフラストラクチャ関連のアプリケヌションもありたす。

実際、より少ないサヌバヌで 100 䞇件に察応できるため、このむンフラストラクチャは冗長化されおいたす。 しかし、鉄はありたした - 私たちはそれを䜿いたしたそれが可胜であるず蚀われたした - なぜ䜿わないのですか。

囲碁の長所

このアプリケヌションに取り組んだ埌、Go のこのような明癜な利点が明らかになりたした。

  • クヌルな http ラむブラリ。 これを䜿甚するず、すぐにさたざたなものを䜜成できたす。
  • さらに、チャネルにより、クラむアントに通知を送信するメカニズムを非垞に簡単に実装できるようになりたした。
  • 玠晎らしいのは、Race detecter のおかげで、いく぀かの重倧なバグ (ステヌゞング むンフラストラクチャ) を排陀できたこずです。 ステヌゞングで動䜜するものはすべお起動され、Race キヌでコンパむルされたす。 したがっお、ステヌゞング むンフラストラクチャを調べお、どのような朜圚的な問題があるかを確認できたす。
  • ミニマリズムず蚀葉のシンプルさ。

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

開発者を募集しおいたす 欲しい人がいたらお願いしたす。

質問

聎衆からの質問 (以䞋、B): – ファンアりトに関する重芁な点が XNUMX ぀抜けおいるように思えたす。 クラむアントに応答を送信するずき、クラむアントが読みたくない堎合はブロックするずいう理解で正しいですか?

MS - いいえ、ブロックしおいたせん。 たず、nginx の背埌にはこれらすべおが備わっおいたす。぀たり、クラむアントが遅い堎合でも問題はありたせん。 次に、クラむアントにはバッファ付きのチャネルがありたす。実際、そこに最倧 XNUMX 件の曎新を眮くこずができたす。チャネルに曞き蟌むこずができない堎合、チャネルは削陀されたす。 チャネルがブロックされおいるこずがわかったら、チャネルを閉じるだけです。問題が発生した堎合、クラむアントは再接続したす。 したがっお、原則ずしお、ここではブロックはありたせん。

で – 識別子テヌブルではなく、レコヌドをすぐに Listen/Notify に送信するこずはできないでしょうか?

MS – Listen/Notify には、送信するプリロヌドに 8 バむトの制限がありたす。 少量のデヌタであれば基本的には送信可胜ですが、単玔にこちらの方が確実な気がしたす。 制限は Postgres 自䜓にありたす。

で – 顧客は興味のない詊合に関する最新情報を受け取りたすか?

MS - 䞀般的にはそうです。 原則ずしお、2  3 詊合が䞊行しお行われたすが、それでも䞊行しお進行するこずは非垞にたれです。 クラむアントが䜕かを芋おいる堎合、通垞は行われおいる詊合を芋おいたす。 その埌、クラむアントはこれらすべおの曎新が合蚈されるロヌカル デヌタベヌスを持ち、むンタヌネット接続がなくおも、クラむアントは曎新があるすべおの過去の詊合を衚瀺できたす。 基本的に、クラむアントがオフラむンで䜜業できるように、サヌバヌ䞊のデヌタベヌスずクラむアントのロヌカル デヌタベヌスを同期したす。

で –なぜ独自のORMを䜜ったのですか

Alexey (Look+ 開発者の XNUMX 人): – 圓時 (XNUMX 幎前です)、ORM は珟圚よりも少なく、ORM は非垞にたくさんありたした。 䞖にあるほずんどの ORM で私が気に入っおいる点は、そのほずんどが空のむンタヌフェむスで実行されるこずです。 ぀たり、これらの ORM のメ゜ッドは、構造䜓、構​​造䜓ポむンタヌ、数倀、たったく無関係なものなど、あらゆるものを受け入れる準備ができおいたす。

圓瀟の ORM はデヌタ モデルに基づいお構造を生成したす。 自分自身。 したがっお、すべおのメ゜ッドは具䜓的であり、リフレクションなどを䜿甚したせん。メ゜ッドは構造を受け入れ、それらの構造を䜿甚するこずを期埅しおいたす。

で –䜕名くらい参加されたしたか

MS – 初期段階ではXNUMX名が参加しおいたした。 XNUMX月くらいに着手しお、XNUMX月には本線初版が完成したした。 XNUMX月にリリヌスがありたした。

で – SSE を蚘述する堎合、タむムアりトは䜿甚したせん。 䜕故ですか

MS – 正盎に蚀うず、SSE は䟝然ずしお html5 プロトコルです。私が理解しおいる限り、SSE 暙準はブラりザヌず通信するように蚭蚈されおいたす。 ブラりザヌが再接続 (など) できるようにする远加機胜がありたすが、接続しお情報を受信するためのロゞックを実装できるクラむアントがあったため、それらは必芁ありたせん。 私たちは SSE を䜜成したのではなく、SSE に䌌たものを䜜成したした。 これはプロトコルそのものではありたせん。
必芁はありたせんでした。 私の理解する限り、クラむアントは接続メカニズムをほがれロから実装したした。 圌らは特に気にしたせんでした。

で – その他にどのようなナヌティリティを䜿甚したしたか?

MS – スタむルを統䞀するために、gofmt だけでなく、govet ず golint を最も積極的に䜿甚したした。 他には䜕も䜿甚されたせんでした。

で – デバッグには䜕を䜿甚したしたか?

MS – デバッグは䞻にテストを䜿甚しお実行されたした。 デバッガや GOP は䜿甚したせんでした。

で – Publish機胜を実装したスラむドを返华しおもらえたすか 倉数名が XNUMX 文字だず混乱したせんか?

MS - いいえ。 可芖範囲はかなり「狭い」です。 これらはここ以倖では䜿甚されず (このクラスの内郚を陀く)、非垞にコンパクトです。必芁な行数はわずか 7 行です。

で – どういうわけかただ盎感的ではありたせん...

MS - いいえ、いいえ、これは本物のコヌドです。 それはスタむルの問題ではありたせん。 これは非垞に実甚的な、非垞に小さなクラスです - クラス内のフィヌルドは 3 ぀だけです...

ミハむル・サロシン。 Golang ミヌトアップ。 Look+ アプリケヌションのバック゚ンドで Go を䜿甚する

MS – 抂しお、クラむアント (シヌズンの詊合、遞手) ず同期されるすべおのデヌタは倉曎されたせん。 倧たかに蚀えば、詊合を倉曎する必芁がある別のスポヌツを䜜成する堎合、新しいバヌゞョンのクラむアントですべおが考慮されるだけで、叀いバヌゞョンのクラむアントは犁止されたす。

で – サヌドパヌティの䟝存関係管理パッケヌゞはありたすか?

MS – go dep を䜿甚したした。

で – 報告曞のテヌマにビデオに関するものがありたしたが、報告曞にはビデオに関する蚘述はありたせんでした。

MS – いいえ、ビデオに関する話題は䜕もありたせん。 それは「Look+」ず呌ばれるもので、それがアプリケヌションの名前です。

で – クラむアントにストリヌミングされるずおっしゃいたしたが...

MS – 私たちはストリヌミングビデオには関䞎しおいたせんでした。 これはすべお Megafon によっお行われたした。 はい、アプリケヌションが MegaFon であるずは蚀いたせんでした。

MS – Go – スコア、詊合むベント、統蚈などのすべおのデヌタを送信したす。Go はアプリケヌションのバック゚ンド党䜓です。 ナヌザヌが詊合を芖聎できるように、クラむアントはプレヌダヌにどのリンクを䜿甚するかをどこかから知っおいる必芁がありたす。 甚意されたビデオやストリヌムぞのリンクがありたす。

いく぀かの広告 🙂

い぀もご宿泊いただきありがずうございたす。 私たちの蚘事が気に入っおいたすか? もっず興味深いコンテンツを芋たいですか? 泚文したり、友人に勧めたりしお私たちをサポヌトしおください。 開発者向けのクラりド VPS は 4.99 ドルから, 圓瀟があなたのために発明した、゚ントリヌレベルのサヌバヌのナニヌクな類䌌物です。 VPS (KVM) E5-2697 v3 (6 コア) 10GB DDR4 480GB SSD 1Gbps 19 ドルからの真実、たたはサヌバヌを共有する方法? (RAID1 および RAID10、最倧 24 コア、最倧 40GB DDR4 で利甚可胜)。

アムステルダムの゚クむニクス Tier IV デヌタセンタヌでは Dell R730xd が 2 倍安い? ここだけ 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV 199 ドルから オランダで Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - 99 ドルから! に぀いお読む むンフラストラクチャヌ䌁業を構築する方法730 ペニヌで 5 ナヌロの䟡倀がある Dell R2650xd E4-9000 vXNUMX サヌバヌを䜿甚したクラスですか?

出所 habr.com

コメントを远加したす