インターネット時代において、データは企業の最も重要な資産の 1 つになりました。データのストレージと処理に対する需要が増大し続けるにつれ、データベースの拡張は多くの企業にとって避けられない選択となっています。単一のデータベースでは企業のニーズを満たせない場合、データベース シャーディングが効果的な拡張ソリューションになります。
データベース シャーディングとは、データベースを複数の独立したライブラリに水平に分割し、それぞれのライブラリにデータの一部を格納することで、単一ライブラリの負荷を軽減し、システム パフォーマンスを向上させることを指します。実際の応用シーンでは、データベースのシャーディングは垂直シャーディングと水平シャーディングの2つの方式に大別されますが、本記事では主にPHPで実装されている水平シャーディングの拡張方式を紹介します。
まず、データを特定のルールに従って異なるシャードに分割する必要があります。ビジネス ニーズに応じて特定のパーティショニング ルールを作成できます。一般的に使用されるルールは次のとおりです:
シャードを分割した後、データが配置されているシャードに応じて、アクセスする対応するデータベースを選択できるように接続レイヤーを変更する必要があります。具体的には、接続層は、フラグメント容量、フラグメント開始値、フラグメント終了値などの各フラグメントの関連情報を記録し、ビジネス層が使用するインターフェイスを公開する必要があります。
最後に、ビジネス層は、パーティション化ルールに従って、データベースの読み取りおよび書き込みリクエストを対応するシャードに送信する必要があります。ビジネス層でのデータベース操作は実際には接続層のカプセル化であり、CRUD 操作を実行するにはシャーディング ルールに従って対応するデータベースを選択する必要があります。
PHP では、PDO を使用して MySQL データベースのシャーディング拡張を実現できます。具体的には、次の手順に従う必要があります。
2.1 PDO 接続の作成
PDO 接続を作成するときは、いくつかの詳細に注意する必要があります。まず、PDO 接続では、メイン ライブラリの関連構成情報とシャード ライブラリのリストを指定する必要があります。次に、PDO 例外をキャプチャして処理できるように、PDO::ATTR_ERRMODE 属性を PDO::ERRMODE_EXCEPTION に設定する必要があります。最後に、実際の前処理を実現できるように、PDO::ATTR_EMULATE_PREPARES 属性を false に設定する必要があります。
サンプル コードは次のとおりです。
// 主库配置信息 $masterConfig = [ 'dsn' => 'mysql:host=127.0.0.1;port=3306;dbname=test', 'username' => 'root', 'password' => 'root', ]; // 分片库列表 $shardConfigList = [ [ 'dsn' => 'mysql:host=127.0.0.1;port=3306;dbname=test_shard_0', 'username' => 'root', 'password' => 'root', ], [ 'dsn' => 'mysql:host=127.0.0.1;port=3306;dbname=test_shard_1', 'username' => 'root', 'password' => 'root', ], ]; // 创建PDO连接 $pdo = new PDO($masterConfig['dsn'], $masterConfig['username'], $masterConfig['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false, ]);
2.2 シャード クエリの実行
アプリケーションでデータベース操作を実行する場合、次に従ってデータを対応するシャードに割り当てる必要があります。パーティショニングルール。通常、シャード ライブラリのセット内の構造は同じで、データのみが異なります。したがって、シャード クエリを実行するときは、まずメイン ライブラリからシャード情報を取得し、シャード情報に基づいてクエリ リクエストを対応するシャード ライブラリに転送できます。
サンプル コードは次のとおりです。
// 获取分片信息 $sql = 'SELECT * FROM `shard_info` WHERE shard_id = ?'; $stmt = $pdo->prepare($sql); $stmt->execute([$shardId]); $info = $stmt->fetch(PDO::FETCH_ASSOC); if (!$info) { throw new RuntimeException('Shard not found'); } // 创建分片PDO连接 $pdoShard = new PDO($info['dsn'], $info['username'], $info['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false, ]); // 执行查询 $sql = 'SELECT * FROM `table` WHERE `key` = ?'; $stmt = $pdoShard->prepare($sql); $stmt->execute([$key]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
2.3 シャード トランザクションの実行
分散トランザクションを実行する場合、関係する複数のシャードの操作を全体として扱う必要があります。具体的には、2 フェーズ コミット プロトコルを利用して、分散トランザクションの一貫性を実現できます。
このうち、最初のフェーズ_Prepare フェーズでは、関連するすべてのシャードに Prepare リクエストを送信して、対応するトランザクション ID を取得する必要があります。すべてのシャードが正常な応答を返した後、トランザクションをコミットまたはロールバックするためにコミット/中止リクエストをすべてのシャードに送信する必要があります。
サンプル コードは次のとおりです。
// 开始分布式事务 $pdo->beginTransaction(); try { // 准备分片事务 $xid = uniqid(); $prepares = []; foreach ($shardConfigList as $shardConfig) { $pdoShard = new PDO($shardConfig['dsn'], $shardConfig['username'], $shardConfig['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false, ]); $pdoShard->beginTransaction(); $stmt = $pdoShard->prepare('INSERT INTO `table` (`key`, `value`) VALUES (?, ?)'); $stmt->execute([$key, $value]); $prepares[] = [$pdoShard, $xid]; } // 提交分片事务 foreach ($prepares as [$pdoShard, $xid]) { $stmt = $pdoShard->prepare('PREPARE TRANSACTION ?'); $stmt->execute([$xid]); } foreach ($prepares as [$pdoShard, $xid]) { $stmt = $pdoShard->prepare('COMMIT PREPARED ?'); $stmt->execute([$xid]); } // 提交整个事务 $pdo->commit(); } catch (Exception $ex) { // 回滚分片事务 foreach ($prepares as [$pdoShard, $xid]) { $stmt = $pdoShard->prepare('ROLLBACK PREPARED ?'); $stmt->execute([$xid]); } // 回滚整个事务 $pdo->rollback(); }
データベース シャーディングは、データベースの過剰な負荷の問題の解決に役立つ効果的な拡張ソリューションです。単一のデータベースに関する質問です。 PHP では、PDO を使用して MySQL データベースのシャード拡張を実現できます。具体的な操作プロセスには、PDO 接続の作成、シャード クエリの実行、シャード トランザクションの実行が含まれます。実際のアプリケーションでは、分散トランザクションの一貫性だけでなく、データの分割ルールや接続層の変更にも注意を払う必要があります。
以上がデータベースシャーディング拡張を実装するための PHP メソッドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。