MySQL:実行は許されない





ウェブサイトとオンラインストア「Eldorado」は毎日約4万件の購入があります。これが会社の事業にとって何を意味するのかを説明する必要はおそらくないでしょう。



歴史的に、ストアは大量のカスタムコードとアドオンを備えたBitrixエンジンで実行されます。ストレージは、4つのマスターサーバーを備えたMySQLクラスターです。



かなりの数の企業がモノリシックアプリケーションを使用しており、多くの企業がそれらと連携する必要があります。モノリスに対処する方法はたくさんありますが、残念ながら、成功したものについて書く人はほとんどいません。私たちがモノリスをどのように支えているか(私たちがそれを見るまで)についての話があなたの興味を引くことを願っています。



大規模なアーキテクチャは多くの問題を引き起こす可能性があることを私たちはよく知っています。しかし、それを破壊するのは簡単です。単純な強い意志の決定によって、それは不可能です。販売は進んでおり、サイトは機能しなければならず、ユーザーの変更は急進的であってはなりません。したがって、モノリスから一連のマイクロサービスへの移行には時間がかかります。これは、システムが動作可能であり、ストレスに対する耐性を確保するために、我慢する必要があります。



なにが問題だったの



非常に長い間、eldorado.ru Webサイトのデータベースクラスターは次のスキームに従って構築されてい





ました。このスキームのすべてのマスターは同時に動作し、すべてがアクティブモードであり、レプリケーションストリームを順番に再生します... M1-> M2- > M3-> M4-> M1-> M2-> M3-> M4-> M1-> M2 ...



私たちのセットアップでは、この構成は唯一のプラスを与えました-それはシステムが動作し、その負荷を維持することを可能にしました。事実、一貫性を確保するための更新後、アプリケーション要求バランサーは読み取りストリーム全体をこのマスターに切り替え、1つのマスターでは読み取りストリーム全体を保持するのに十分ではありませんでした。



しかし、そのようなスキームは、信頼性も作業速度も提供できませんでした。シンプルに見えますが、いくつかの欠点がありました。彼女はクラスター内のデータを更新するのに非常に時間がかかりました。最悪の場合、最大5つのレプリケーションアームがありました(変更が最初に開始されたマスターによって異なります)。これらの遅延により、サイトの運営とオンラインストアでの注文の両方で多くの問題が発生しました。



このスキームの短所



  • アクティブマスターから最も遠いゾーンのスレーブは、最悪の場合、トランザクション実行時間の4倍後にのみデータ更新を受信し、時には熱狂的なレプリケーション遅延が発生しました。
  • いずれかのマスターで障害が発生すると、それが解消されるまで、クラスター全体でデータの不整合が発生します。
  • (- — );
  • ;
  • , ( , , );
  • UPDATE/DELETE SELECT ;
  • , slave_status seconds_behind_master.


スレーブで1〜2秒の人工レプリケーション遅延を有効にすることで、テスト環境でこの動作をエミュレートできます(これは私たちが行いました)。これは、MASTER_DELAY = Nオプションを使用してこのような分散アーキテクチャの準備ができているかどうかアプリケーションをテストするための優れた方法です。 。



システムがあまりにも大規模かつ非常に備えて、それがMySQLの使用に結びついているにしても、その内部クエリオプティマイザのニュアンスにあるのでそして最後に、私たちの場合、別のデータベースへの移行は、オプションではありません。



どうやって解決したか



自分でスキーマを変更したくなかったので(これは危険な操作です)、新しいアーキテクチャを提案して展開できるコンサルティング会社を探すことから始めました。サイトにアクセスしやすく、切り替えが目立たないようにするためです。これらの企業の中には、最大のインテグレーターとソフトウェア開発者がいました。



一部の企業は単に私たちに答えなかった(そしてこれは正常である)一方で、他の企業はそのような仕事を引き受ける準備ができていないと書いた。同時に、プロジェクトの可能なコストの問題も発生しませんでした。

大規模なインテグレーターがタスクに関与したくない場合は、それを自分で解決することが二重に興味深いものになっています。優れた機器を自由に使用でき、安定性とフォールトトレランスの問題が2番目に優先され、当初はデータ転送を何らかの方法で高速化したいと考えていました。 MySQLバージョン5.6および5.7に登場したいくつかのオプションがこれにうまく機能しました。



確かに、ドキュメントは、それらを単純に有効にすることは不可能であることを透過的に示唆しています、tk。リングには間違いなく小さいバージョンのスレーブがありますが、ここでは次のようになります。

5.7マスターは、アップグレード前に書き込まれた古いバイナリログを読み取り、それらを5.7スレーブに送信できます。スレーブは古いフォーマットを認識し、適切に処理します。



アップグレード後にマスターによって作成されたバイナリログは5.7形式です。これらも5.7スレーブによって認識されます。



つまり、MySQL 5.7にアップグレードする場合、マスターを5.7にアップグレードする前に、スレーブはMySQL5.7である必要があります。


テストの場合、たとえばmysqld_multiを使用してテストリングを上げ、その上で一般的なクエリを実行するだけで十分でした(同じホスト上でも、オフセットセットが異なる異なるポート上の4つのインスタンスでも可能です)。



mysql -h127.0.0.1 -P 3302 -e "RESET SLAVE; RESET MASTER; SHOW MASTER STATUS\G;"
mysql -h127.0.0.1 -P 3302 -e "CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3301, MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='master1-binlog.000001', MASTER_LOG_POS = 107;START SLAVE;"
mysql -h127.0.0.1 -P 3303 -e "RESET SLAVE; RESET MASTER; SHOW MASTER STATUS\G;"
mysql -h127.0.0.1 -P 3303 -e "CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3302, MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='master2-binlog.000001', MASTER_LOG_POS = 107;START SLAVE;"
mysql -h127.0.0.1 -P 3304 -e "RESET SLAVE; RESET MASTER; SHOW MASTER STATUS\G;"
mysql -h127.0.0.1 -P 3304 -e "CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3303, MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='master3-binlog.000001', MASTER_LOG_POS = 107;START SLAVE;"
mysql -h127.0.0.1 -P 3301 -e "RESET SLAVE; RESET MASTER; SHOW MASTER STATUS\G;"
mysql -h127.0.0.1 -P 3301 -e "CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=3304, MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='master4-binlog.000001', MASTER_LOG_POS = 107;START SLAVE;"
      
      





その後、その隣に配置された別のバイナリを使用して目的のポートで構成を実行し、データ/システムテーブルのmysql_upgradeを作成することで、任意のインスタンスのバージョンを変更できます。



販売中、期間限定で、すべてのトラフィックを1つのマスターのみに送信し、この時点で別のマスターを更新してから、それに切り替えて他のすべてのマスターを再更新することができました。ただし、このためには、バージョン間のbinlog形式の互換性を確保して、すべてのトランザクションが正常に失われるようにする必要がありました。



私たちのケースに役立つもう少しドキュメント:

非互換性を回避するには、MySQL5.6マスターで次の変数を設定します。



binlog_checksum=NONE
binlog_row_image=FULL
binlog_rows_query_log_events=OFF
log_bin_use_v1_row_events=1 (NDB Cluster only) 
      
      





このフラグは必須であることが判明しましたが、NDBを使用しないと、サーバー5.6〜5.5間でレプリケーションが終了し、mysqlbinlogはこのオプションなしでエラーエラー:Log_eventのエラー:: read_log_event()でログを読み取ります。 : '健全性チェックに失敗しました'、data_len:8203、event_type:30、有効にすると、すべてが開始され、機能します。

GTIDは含めませんでした。すべての古いツールとの互換性の要件に加えて、客観的には、移行に十分な利点は見られません。



gtid_mode=OFF
      
      





レプリケーションの正確さを確認する最も簡単なテストは、5.5のサーバーと5.6のサーバーに順番にダンプをアップロードし、すべてが正常かどうかを確認することです。



残念ながら、予想通り、テストは失敗しました。



Last_Error: Column 18 of table 'eldorado2.b_adv_banner' cannot be converted from type '<unknown type>' to type 'datetime'
      
      





5.6の日時は特別で、マイクロ秒が追加されるため、5.6では新しい日時があります。5.5



バージョン5.6では不明 です。同時にフィールドが作成されない場合は、5.5と並行してリング内のクラスターで機能できます。新しいタイプのフィールドを使用してレプリケーションを実行するテーブルのいずれか。 (datetime 5.6!= datetime 5.5、time、timestampと同様に、データベースには240を超えるそのようなフィールドがあります)。



これらのフィールドにDDLがないことを完全に保証することはできず、クラスター全体のパフォーマンスを危険にさらしたくありませんでした。しかし、より安全なプランBがありました。



これは、操作用の追加のハードウェアが存在し、近くのクラスターの完全なコピーを作成することを意味しました。幸い、そのようなハードウェアがありました。そして、そのような可能性があるので、「通常の」クラスターを一度に作成する必要がありました。



ただし、同時に、現在のすべての監視、デバッグ、およびビンログ分析ツールの操作性を維持し、現在のアーキテクチャの既存の欠点を可能な限り排除する必要があります。



マルチチャネルレプリケーション



サイトを無傷に保ち、管理者に情報を提供するには、銀の弾丸が必要です。これはマルチチャネルレプリケーションです。私たちは先験的に新しい機会を信頼せず、技術について確信が持てず、そのような情報や事例をどこにも見つけることができず、大規模な生産での公的な経験はほとんどありません。



したがって、私たちはすべてを自分たちで考えました。計画は次のとおりでした。



  • : 5.7, ;
  • ;
  • , — , , .








— , , , . , , ? . , « »! , - !

( « »)


ターゲットスキームでは、4つのマスターは各スレーブの4つの独立した記録ストリームであり、独立して処理されます。



すべてのマスターで、log_slave_updatesをオフにすることが可能になりました-どこにも何も中継する必要はなく、メインストリームですべての変更を送信します(=>マスターの負荷はさらに低くなります)。



同時に、最小のbinlog形式と、途中でのトランザクションの並列処理を有効にすることもできます(条件付きで、正しく理解する必要があります)。



slave_parallel_workers=5
slave_parallel_type=LOGICAL_CLOCK
binlog_row_image=minimal
      
      





この設定では、いつでも負荷を新しいクラスターに切り替えることができますが、このルートは一方向であり、ロールバックを提供しません。



古いクラスターへの接続の存続期間中、新しいクラスターへの1つのマスターエントリポイントのlog_slave_updatesオプションは引き続き存在するため、接続から「古い」クラスターへのすべての変更は、新しいクラスターに完全に配信され、その直後にこのオプションは無効になっており、現時点までのアプリケーションは他の3つのマスターを調べ、データストリームはまったく交差していませんでした。



その結果、次のような利点が得られました。



  • 長いリクエストが何かをブロックしている場合、これは4つのレプリケーションスレッドのうち1つにのみ影響し、他のスレッドにはまったく影響しません。
  • 以前はMySQLバージョンのために不可能だった新しいbinlog形式は、現在、占有するスペースが数分の1になり、したがって、トラフィックは、これにより、クラスター全体ではるかに多くの変更を渡すことができます。
  • これで、他のすべてに影響を与えることなく、マスターを完全に痛みを伴わずにオフにすることができます。
  • マスターの事故はそれほど恐ろしいものではなくなりました。理解できない状況で1分以内にサーバーのクローンを作成し、server_idを再生成し、スレーブアクセスのクレジットを作成すると、新しいマスターの準備が整います。


「マイナス」もあります:



  • 各マスターにははるかに多くのスレーブがあり、チャネルにぶつかりやすくなっています(実際、これはトラフィックの増加ではなく、時間と空間の再分配です)。


新しいスキームは何を与えましたか



新しいスキームへの移行は成功したことが判明し、2020年8月28日に1日で実行しました。新しいアーキテクチャを使用した経験から、レプリケーションの問題の数が3〜4倍減少したことが示されています(完全に取り除くことは不可能です)。システムの安定性が向上しました。そして主な結果は、システムの最大スループットの増加でした。以前の開発者がレプリケーションに関する理解できない問題を非難することができたとしても、今ではそれは彼らにとってはうまくいきません。



レプリケーションの遅延によって引き起こされるクライアントの問題の数は数分の1に減少しました。これは、クライアントの苦痛が少なくとも少し少なくなったことを意味します。これで、マスターサーバーで作業を実行するために、いつでもマスターサーバーの電源を切ることができます。これは、クラスター全体に影響を与えたり、レプリケーションプロセスを停止したりすることはありません。



このクラスターは、メインサイト「Eldorado」にサービスを提供します。ほとんどの場合、製品カード、個人アカウント、バスケット、注文処理、コールセンターなどを備えた古いモノリシックアプリケーションです。この記事の執筆時点では、クラスター(スレーブのみ)の合計読み取り負荷は40k rpsであり、データベースサーバーあたり約5k rpsです。ただし、個々のテクニカルスレーブの技術的負荷は、ピーク時に大幅に高くなります。それほど多くはないように思われるかもしれませんが、これらのクエリの性質と複雑さを考慮に入れる必要があります。



私たちの経験が誰かに役立つことを心から願っています。マルチチャネルレプリケーションに加えて、ブラックホールやフェデレーションテーブルなど、多くの興味深いものも使用します。これらの機能を使用すると、多くの頭痛の種を取り除くことができます(また、必要な理由がわからない場合は少し追加できます)。 MySQLに関するニュアンスやその他の質問に興味があります-コメントでようこそ。



半年間の商用運用では、マルチチャネルに関連する問題はまだ発生していません。十分なフォールトトレラントで信頼性の高いセットアップをお勧めします。



モノリス自体は現在、いくつかの個別の独立したサービスに分割する過程にあり、そのうちのいくつかを分割して、私たちの経験についてお話しします。ご期待ください。



私の優秀なチームに特に感謝します。彼女がいなければ、これはできなかったでしょう。



PSちなみに、 私たちはまだ本当に才能のあるプログラマーを必要としていますそんな方は 是非、おもしろいでしょう。



All Articles