jrsaunders / shard-matrix
适用于 MYSQL 和/或 Postgres 的完整数据库分片系统。使用 Laravel 查询构建器轻松扩展您的应用程序。通过一个 YAML 配置文件配置整个解决方案。
Requires
- php: ^7.4
- ext-zlib: *
- doctrine/dbal: ^2.10
- laravel/framework: 7.13
- predis/predis: ^1.1
- ramsey/uuid: ^4.0
- symfony/yaml: ^5.0
Requires (Dev)
- phpunit/phpunit: ^7
- dev-master
- 1.4.2
- 1.4.1
- 1.4.0
- 1.3.9
- 1.3.8
- 1.3.7
- 1.3.6
- 1.3.5
- 1.3.4
- 1.3.3
- 1.3.2
- 1.3.1
- v1.3.0
- v1.2.9
- v1.2.8
- v1.2.7
- v1.2.6
- v1.2.5
- v1.2.4
- v1.2.3
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.0
- v1.0.1
- v1.0.0
- dev-dependabot/composer/symfony/http-kernel-5.4.20
- dev-dependabot/composer/laravel/framework-7.30.4
- dev-dependabot/composer/league/flysystem-1.1.4
This package is auto-updated.
Last update: 2024-09-30 00:43:53 UTC
README
ShardMatrix for PHP
MySQL 和 Postgres 的数据库分片系统
-
需求
- PHP 7.4^
-
支持
- 一个单一的 YAML 配置文件
- 多个节点(数据库服务器)
- Mysql
- Postgres
- MySQL 和 Postgres 可以一起使用 并进行热交换
- 多个地理区域
- UUIDs 集成了表及其所属节点的所有相关数据
- Docker
- Kubernetes
- 快速异步数据库查询(使用专门构建的 GoThreaded 服务 https://github.com/jrsaunders/go-threaded | https://hub.docker.com/r/jrsaunders/gothreaded 或 PHP 分叉用于 crons 或开发工作)
- 文件或 Redis 或 MemcacheD 缓存
- 节点间唯一的表列
- 表分组以确保数据存储在正确的分片中,以便可以进行连接
- 使用 Laravel 的流行 ORM(尽管您的项目不一定要在 Laravel 中)https://laravel.net.cn/docs/7.x
- 查询构建是数据库无关的
- 使用缓存在节点间进行高效分页
- 原始 SQL 查询
快速使用
一旦您按照下面的 安装 部分中的说明启动它 - 这里有一些快速使用示例。
如果您熟悉 Laravel 中的 ORM - 这只是其扩展。
创建表
- 在所有适当的节点(MySQL 和 PostgreSQL)上创建表。这遵循您在 YAML 配置文件中提供的指导,说明哪些表属于哪些节点
use ShardMatrix\DB\Builder\Schema; # Creates Table across all appropriate Nodes (Mysql and Postgres simultaneously). # This follows the guidance you have given in your Yaml Config file as to what tables # belong on what nodes Schema::create( 'users', function ( \Illuminate\Database\Schema\Blueprint $table ) { $table->string( 'uuid', 50 )->primary(); $table->string('username',255)->unique(); $table->string('email',255)->unique(); $table->integer('something'); $table->dateTime( 'created' ); } );
插入记录
- 插入数据 - 系统将选择适当的分片节点并为其创建一个 UUID,该 UUID 将分配给适当的节点
use ShardMatrix\DB\Builder\DB; # Insert Data - the system will choose an appropriate shard node and create a UUID for it that will be attributed to an appropriate node $uuid = DB::table( 'users' )->insert( [ 'username' => 'jack-malone', 'password' => 'poootpooty', 'created' => (new \DateTime())->format('Y-m-d H:i:s'), 'something' => 5, 'email' => 'jack.malone@yatti.com', ] ); echo $uuid->toString(); # outputs 06a00233-1ea8af83-9b6f-6104-b465-444230303037 echo $uuid->getNode()->getName(); # outputs DB0007 echo $uuid->getTable()->getName(); # outputs users
插入的数据
uuid 06a00233-1ea8af83-9b6f-6104-b465-444230303037
username jack-malone
password poootpooty
email jack.malone@yatti.com
created 2020-04-30 15:35:31.000000
something 5
- 在此 PHP 进程中进行的任何其他插入都将插入到同一分片中,如果它位于正确的表组中
通过 UUID 获取记录并更新记录
- 直接从正确的节点(分片)获取记录
- 操作记录
- 更新记录
use ShardMatrix\DB\Builder\DB; use ShardMatrix\DB\Interfaces\DBDataRowTransactionsInterface; # Get the record directly from the correct node (shard) $record = DB::getByUuid( '06a00233-1ea8af83-9b6f-6104-b465-444230303037' ); # Manipulate the record if ( $record && $record instanceof DBDataRowTransactionsInterface) { # As above you could run an additional check for the instance of the record returned, but it should always follow this interface through the query builder echo $record->username; # outputs jack-malone echo $record->email; # outputs jack.malone@yatti.com # overwrite the email attribute $record->email = 'anotheremail@yatti.com'; # Update the record $record->save(); }
查询数据并条件删除记录
- 查询所有相关节点中的数据
- 数据返回为可以迭代的集合
- 有条件地使用数据
- 操作记录并提交更改
use ShardMatrix\DB\Builder\DB; use ShardMatrix\DB\Interfaces\DBDataRowTransactionsInterface; # Query all relevant nodes for the data $collection = DB::allNodesTable( 'users')->where('email','like','%yatti%')->limit(50)->get(); # Data returns as a Collection that can be iterated through $collection->each( function(DBDataRowTransactionsInterface $record){ # Use data conditionally if($record->username == 'a-bad-user'){ # Manipulate the record and commit changes $record->delete(); } });
分页
所有分片的数据分页
use ShardMatrix\DB\Builder\DB; use ShardMatrix\DB\Interfaces\DBDataRowTransactionsInterface; $pagination = DB::allNodesTable( 'users' ) ->orderBy( 'created', 'desc' ) ->paginate(); $pagination->each( function ( DBDataRowTransactionsInterface $record) { echo $record->username; echo $record->getUuid(); }); echo $pagination->total(); echo $pagination->perPage(); echo $pagination->nextPageUrl(); echo $pagination->previousPageUrl();
通过 UUID 位置定义的单个分片的数据分页
use ShardMatrix\DB\Builder\DB; use ShardMatrix\DB\Interfaces\DBDataRowTransactionsInterface; $uuidFromCurrentUser = "06a00233-1ea8af83-d514-6a76-83ae-444230303037"; $pagination = DB::table( 'users' ) ->uuidAsNodeReference($uuidFromCurrentUser) ->orderBy( 'created', 'desc' ) ->paginate(); $pagination->each( function ( DBDataRowTransactionsInterface $record) { echo $record->username; echo $record->getUuid(); }); echo $pagination->total(); echo $pagination->perPage(); echo $pagination->nextPageUrl(); echo $pagination->previousPageUrl();
安装
安装 PHP 的 ShardMatrix
使用 Composer 安装 ShardMatrix,或从 GitHub 拉取存储库。
composer require jrsaunders/shard-matrix
准备 YAML 配置文件
ShardMatrix 需要知道您的表、列和数据库如何交互,因此此配置文件将使用简单的 YAML 文件定义这些内容。
- 您需要数据库的凭证和访问权限设置。 参考 Yaml 文件
示例
这是一个配置文件应该如何看起来完整示例。
version: 1 table_groups: user: - users - payments - offers tracking: - visitors - sign_ups published: - published_offers unique_columns: users: - email - username nodes: DB0001: dsn: mysql:dbname=shard;host=localhost:3301;user=root;password=password docker_network: DB0001:3306 geo: UK table_groups: - user - published DB0002: dsn: mysql:dbname=shard;host=localhost:3302;user=root;password=password docker_network: DB0002:3306 geo: UK table_groups: - user - published DB0003: dsn: mysql:dbname=shard;host=localhost:3303;user=root;password=password docker_network: DB0003:3306 geo: UK table_groups: - user - published DB0004: dsn: mysql:dbname=shard;host=localhost:3304;user=root;password=password docker_network: DB0004:3306 geo: UK table_groups: - published DB0005: dsn: mysql:dbname=shard;host=localhost:3305;user=root;password=password docker_network: DB0005:3306 table_groups: - tracking DB0006: dsn: mysql:dbname=shard;host=localhost:3306;user=root;password=password docker_network: DB0006:3306 geo: UK insert_data: false table_groups: - tracking DB0007: dsn: pgsql:dbname=shard;host=localhost:5407;user=postgres;password=password docker_network: DB0007:5432 geo: UK table_groups: - user - tracking
配置文件结构
版本
定义版本。最新版本是 1。
version: 1
表组
定义表组。您向应用程序添加表时,需要在此处显式添加它们。
组名仅在 ShardMatrix 中使用。
表名归因于组。一个表一次只能属于一个组,并且一旦写入数据库,最好不要更改分配给组的任何表。
- 表示配置文件中的表组部分
- 表示表组的名称
- 表示表名
# Denotes the table groups section on config table_groups: # Denotes the name of a group of tables user: # Denotes the table name - users
此部分可能的外观。
table_groups: user: - users - payments - offers tracking: - visitors - sign_ups published: - published_offers
表中的唯一列
可以在此处定义唯一列。因此,在 users
表中,email
和 username
必须在所有节点(分片数据库)中唯一。
unique_columns: users: - email - username facebook_users: - fb_id
节点
这是您定义数据库连接、凭证以及节点可能使用的表组和地理的地方。
节点可以根据需要进行扩展和添加。
节点名称必须保持不变,以及它们对应的表组。
节点部分的解剖结构。
- 表示节点定义的位置
- 节点名称
- 连接到数据库的 DSN
- 可选 Docker 服务名称和端口号
- 可选地理 - 如果指定了地理,则应用程序插入数据将使用此选择写入此节点的节点
- 可选停止在此处写入新数据,除非连接到此节点的现有 UUID
- 使用此节点的表组必须在此处定义
- 表组用户(包括用户、产品、支付表)
# Denotes the where the nodes are defined nodes: # Node Name DBUK01: # DSN for connection to DB dsn: mysql:dbname=shard;host=localhost:3301;user=root;password=password # *optional docker service name and port number docker_network: DBUK:3306 # *optional Geo - if a geo is stated the application inserting data will use this to choose this node to write new inserts to it geo: UK # *optional Stop new data being written here, unless connected to an existing UUID from this node insert_data: false # Table groups that use this node must be defined here table_groups: # Table group user (that consists of the users, offers, payments tables) - user - published
节点部分在配置 yaml 中的外观。
nodes: DBUK01: dsn: mysql:dbname=shard;host=localhost:3301;user=root;password=password docker_network: DBUK:3306 geo: UK table_groups: - user - published postg1: dsn: pgsql:dbname=shard;host=localhost:5407;user=postgres;password=password docker_network: postg1_db:5432 table_groups: - tracking DB0001: dsn: mysql:dbname=shard;host=localhost:3304;user=root;password=password docker_network: DB0001:3306 insert_data: false table_groups: - user - published
一旦 Yaml 配置文件完成
将 文件 保存到应用程序所在的目录,无论是受保护的目录还是外部无法访问的目录。
或者它可以被制作成 Kubernetes Secret 并以这种方式提供给您的应用程序。
在 PHP 中启动
在这些示例中,我们已经将配置文件保存为 shard_matrix.yaml
并将其放置在我们的应用程序的 index php 目录中。
仅使用 PHP 和 Web 服务器资源进行基本设置
- 我们的配置文件
- 指定需要写入 db 数据的本地目录
use ShardMatrix\ShardMatrix; # Our config file ShardMatrix::initFromYaml( __DIR__ . '/shard_matrix.yaml' ); # Specifying a local directory to write db data to when it needs to ShardMatrix::setPdoCachePath( __DIR__ . '/shard_matrix_cache' );
仅使用 GoThreaded 和 Redis 进行设置
- 我们的配置文件
- 将服务从 PHP 分叉异步查询更改为 GoThreaded
- 当我们必须查询所有相关分片时,使用 GoThreaded 进行异步 DB 调用
- 这覆盖了使用写入文件的方法的 PdoCache 服务,现在它使用 Redis 缓存
use ShardMatrix\ShardMatrix; # Our config file ShardMatrix::initFromYaml( __DIR__ . '/shard_matrix.yaml' ); # Changes the service from PHP forking for asynchronous queries to GoThreaded ShardMatrix::useGoThreadedForAsyncQueries(); # Uses GoThreaded for asynchronous DB calls when we have to query all relevant shards ShardMatrix::setGoThreadedService( function () { return new \ShardMatrix\GoThreaded\Client( '127.0.0.1', 1534, 'gothreaded', 'password' ); } ); # This overwrites the PdoCache Service that was used to write to file, and now instead uses Redis caching ShardMatrix::setPdoCacheService( function () { return new \ShardMatrix\PdoCacheRedis( new \Predis\Client( 'tcp://127.0.0.1:6379' ) ); } );