├── README.md ├── composer.json └── src ├── Exceptions └── ShardingException.php ├── Facades └── ShardManager.php ├── IdGenerators ├── IdGeneratorInterface.php └── RedisSequence.php ├── MapManager.php ├── ShardChoosers ├── ModuleDivision.php ├── RedisCentralTable.php ├── ServerRanges.php └── ShardChooserInterface.php ├── ShardManager.php ├── ShardingServiceProvider.php └── config └── config.php /README.md: -------------------------------------------------------------------------------- 1 | # laravel-sharding 2 | 3 | ################################################ 4 | # **LEGACY!!!** # 5 | # CLOSED AND NOT SUPPORTED # 6 | ################################################ 7 | 8 | ## Installation 9 | 10 | #### Download package 11 | `composer require enfil/sharding` 12 | 13 | #### Add to Providers 14 | Add `Enfil\Sharding\ShardingServiceProvider::class,` to the `providers` array in `/config/app.php`. 15 | 16 | #### Add to Aliases 17 | Add `'ShardManager' => \Enfil\Sharding\Facades\ShardManager::class,` to the `alias` list in `/config/app.php`. 18 | 19 | #### Publish config 20 | `php artisan vendor:publish --provider="Enfil\Sharding\ShardingServiceProvider" --tag="config" --force` 21 | 22 | ## Configuration 23 | 24 | You can configurate sharding for all your services in the `sharding.php` config file located in the `config` directory. 25 | 26 | ## Usage 27 | 28 | First of all you should set your service: 29 | 30 | `\ShardManager::setService('auth');` 31 | 32 | #### Adding data 33 | When you're inserting any element into your database you should generate unique ID for it. 34 | You can get next id using: 35 | 36 | `$id = \ShardManager::getNextId();` 37 | 38 | Than you can choose shard (database connection) using: 39 | 40 | `$shard = \ShardManager::getShardById($id);` 41 | 42 | Now you can insert your data to current shard: 43 | 44 | ``` 45 | \DB::connection($shard)->table('t')->insert( 46 | [...] 47 | ); 48 | ``` 49 | 50 | After inserting you should increment id-generator: 51 | 52 | `\ShardManager::increment();` 53 | 54 | #### Selecting data 55 | To select your data by id you should get a shard: 56 | 57 | `$shard = \ShardManager::getShardById($id);` 58 | 59 | Than you can get data from current shard: 60 | 61 | `DB::connection($shard)->table('t')->select(...);` 62 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "enfil/sharding", 3 | "description": "Laravel 5.1 sharding", 4 | "authors": [ 5 | { 6 | "name": "enfil", 7 | "email": "enfilg@gmail.com" 8 | } 9 | ], 10 | "minimum-stability": "dev", 11 | "require": { 12 | "php": ">=5.4.0", 13 | "illuminate/support": "~5.0" 14 | }, 15 | "autoload": { 16 | "psr-4": { 17 | "Enfil\\Sharding\\": "src" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Exceptions/ShardingException.php: -------------------------------------------------------------------------------- 1 | sequenceKey = $sequenceKey; 12 | } 13 | 14 | public function getNextId() 15 | { 16 | return (int)\Redis::get($this->sequenceKey) + 1; 17 | } 18 | 19 | public function getLastId() 20 | { 21 | return (int)\Redis::get($this->sequenceKey); 22 | } 23 | 24 | public function setLastId($id) 25 | { 26 | return \Redis::set($this->sequenceKey, $id); 27 | } 28 | 29 | public function increment() 30 | { 31 | return \Redis::incr($this->sequenceKey); 32 | } 33 | } -------------------------------------------------------------------------------- /src/MapManager.php: -------------------------------------------------------------------------------- 1 | [ 29 | * 'shard_chooser' => 'Enfil\Sharding\ShardChoosers\ModuleDivision', 30 | * 'id_generator' => 'Enfil\Sharding\IdGenerators\RedisSequence' 31 | * ], 32 | * ] 33 | * @var array $container 34 | */ 35 | private $container = []; 36 | /** 37 | * Current service name 38 | * @var string $name 39 | */ 40 | private $name; 41 | 42 | /** 43 | * MapManager constructor. 44 | * @param $map - config 45 | */ 46 | public function __construct($map) 47 | { 48 | $this->map = $map; 49 | } 50 | 51 | public function setService($name) 52 | { 53 | $this->name = $name; 54 | if (!isset($this->map[$name]['connections'])) { 55 | throw new ShardingException('Connections are not configured for ' . $name . ' service'); 56 | } 57 | $this->currentConnections = $this->map[$name]['connections']; 58 | 59 | if (!isset($this->map[$name]['shard_chooser'])) { 60 | throw new ShardingException('Shard chooser are not configured for ' . $name . ' service'); 61 | } 62 | 63 | $chooserClass = $this->map[$name]['shard_chooser']; 64 | $relationKey = (isset($this->map[$name]['relation_key']) ? $this->map[$name]['relation_key'] : null); 65 | $chooser = new $chooserClass($this->currentConnections, $relationKey); 66 | if (!$chooser instanceof ShardChooserInterface) { 67 | throw new ShardingException('Shard chooser must be instanceof ShardChooserInterface'); 68 | } 69 | 70 | if (!isset($this->container[$name]['shard_chooser'])) { 71 | $this->container[$name]['shard_chooser'] = $chooser; 72 | } 73 | 74 | if (!isset($this->map[$name]['id_generator'])) { 75 | throw new ShardingException('Id generator are not configured for ' . $name . ' service'); 76 | } 77 | 78 | $generatorClass = $this->map[$name]['id_generator']; 79 | $sequenceKey = $this->map[$name]['sequence_key']; 80 | $generator = new $generatorClass($sequenceKey); 81 | if (!$generator instanceof IdGeneratorInterface) { 82 | throw new ShardingException('Id generator must be instanceof IdGeneratorInterface'); 83 | } 84 | if (!isset($this->container[$name]['id_generator'])) { 85 | $this->container[$name]['id_generator'] = $generator; 86 | } 87 | } 88 | 89 | public function getShardChooser() 90 | { 91 | return $this->container[$this->name]['shard_chooser']; 92 | } 93 | 94 | public function getIdGenerator() 95 | { 96 | return $this->container[$this->name]['id_generator']; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/ShardChoosers/ModuleDivision.php: -------------------------------------------------------------------------------- 1 | connections = $connections; 12 | } 13 | 14 | public function getShardById($id) 15 | { 16 | return $this->connections[$id % count($this->connections)]; 17 | } 18 | 19 | public function chooseShard($id) 20 | { 21 | return $this->getShardById($id); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/ShardChoosers/RedisCentralTable.php: -------------------------------------------------------------------------------- 1 | connections = $connections; 14 | if (!$relationKey) { 15 | throw new ShardingException('You should set "relation_key" param in config to use "Central Table" sharding'); 16 | } 17 | $this->relationKey = $relationKey; 18 | } 19 | 20 | public function getShardById($id) 21 | { 22 | return \Redis::get("$this->relationKey:$id"); 23 | } 24 | 25 | public function chooseShard($id) 26 | { 27 | return $this->connections[$id % count($this->connections)]; 28 | } 29 | 30 | public function setRelation($id, $shard) 31 | { 32 | return \Redis::set("$this->relationKey:$id", $shard); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ShardChoosers/ServerRanges.php: -------------------------------------------------------------------------------- 1 | connections = $connections; 13 | } 14 | 15 | public function getShardById($id) 16 | { 17 | foreach ($this->connections as $shard => $range) { 18 | if ($id >= $range[0] && $id <= $range[1]) { 19 | return $shard; 20 | } 21 | } 22 | throw new ShardingException('Your must to set up range for this id!'); 23 | } 24 | 25 | public function chooseShard($id) 26 | { 27 | return $this->getShardById($id); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/ShardChoosers/ShardChooserInterface.php: -------------------------------------------------------------------------------- 1 | mapManager = $mapManager; 20 | } 21 | 22 | public function setService($name) 23 | { 24 | $this->mapManager->setService($name); 25 | $this->shardChooser = $this->mapManager->getShardChooser(); 26 | $this->idGenerator = $this->mapManager->getidGenerator(); 27 | } 28 | 29 | public function getShardById($id) 30 | { 31 | return $this->shardChooser->getShardById($id); 32 | } 33 | 34 | public function getIdsFromShard($firstId, $lastId, $shard) 35 | { 36 | return $this->shardChooser->getIdsFromShard($firstId, $lastId, $shard); 37 | } 38 | 39 | public function getLastId() 40 | { 41 | return $this->idGenerator->getLastId(); 42 | } 43 | 44 | public function getNextId() 45 | { 46 | return $this->idGenerator->getNextId(); 47 | } 48 | 49 | public function increment() 50 | { 51 | return $this->idGenerator->increment(); 52 | } 53 | 54 | public function chooseShard($id) 55 | { 56 | return $this->shardChooser->chooseShard($id); 57 | } 58 | 59 | public function setRelation($id, $shard) 60 | { 61 | return $this->shardChooser->setRelation($id, $shard); 62 | } 63 | } -------------------------------------------------------------------------------- /src/ShardingServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadViewsFrom(__DIR__.'/views', 'sharding'); 19 | $this->publishes([ 20 | __DIR__.'/config/config.php' => config_path('sharding.php') 21 | ], 'config'); 22 | } 23 | /** 24 | * Register the application services. 25 | * 26 | * @return void 27 | */ 28 | public function register() 29 | { 30 | $this->registerConnectionManager(); 31 | $this->app->bind('enfil.shardmanager', function () { 32 | return new ShardManager( 33 | $this->app['enfil.map_manager'] 34 | ); 35 | }); 36 | 37 | } 38 | /** 39 | * Register the bindings for the ConnectionManager 40 | */ 41 | protected function registerConnectionManager() 42 | { 43 | $this->app->bind('enfil.map_manager', function ($app) { 44 | $map = config('sharding.map'); 45 | return new MapManager($map); 46 | }); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/config/config.php: -------------------------------------------------------------------------------- 1 | [ 10 | 11 | /* 12 | |-------------------------------------------------------------------------- 13 | | Service Name 14 | |-------------------------------------------------------------------------- 15 | */ 16 | 'auth' => [ 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Database Connections List 21 | |-------------------------------------------------------------------------- 22 | | 1. For "ModuleDivision" and "CentralTable" ShardChoosers 23 | |-------------------------------------------------------------------------- 24 | | If you're using "ModuleDivision" or "CentralTable" as a ShardChooser 25 | | you should set "connections" array like this: 26 | | 'connections' => [ 27 | | 'auth-1', 28 | | 'auth-2', 29 | | 'auth-3' 30 | | ], 31 | | Where each array value is a connection name (from your config/database.php) 32 | |-------------------------------------------------------------------------- 33 | | 2. For "ServersRange" ShardChooser 34 | |-------------------------------------------------------------------------- 35 | | If you're using "ServersRange" as a ShardChooser 36 | | you should set "connections" array like this: 37 | | 'connections' => [ 38 | 'auth-1' => [1, 10], 39 | 'auth-2' => [11, 20], 40 | 'auth-3' => [21, 30] 41 | | ], 42 | | Where each array key is a connection name (from your config/database.php), 43 | | and each value is array of id-ranges. 44 | | 45 | */ 46 | 'connections' => [ 47 | 'auth-1' => [1, 10], 48 | 'auth-2' => [11, 20], 49 | 'auth-3' => [21, 30] 50 | ], 51 | 52 | /* 53 | |-------------------------------------------------------------------------- 54 | | Shard Chooser class 55 | |-------------------------------------------------------------------------- 56 | | 57 | */ 58 | 'shard_chooser' => 'Enfil\Sharding\ShardChoosers\ServerRanges', 59 | 60 | /* 61 | |-------------------------------------------------------------------------- 62 | | Unique id generator class 63 | |-------------------------------------------------------------------------- 64 | | Generators you can use to generate ids or emulate sequence: 65 | |-------------------------------------------------------------------------- 66 | | 1. Enfil\Sharding\IdGenerators\RedisSequence - to store in Redis 67 | |-------------------------------------------------------------------------- 68 | | 2. Enfil\Sharding\IdGenerators\MysqlSequence - to store in MySQL 69 | | 70 | | You can use your own Id generator (must be an Instance of Enfil\Sharding\IdGenerators\IdGeneratorInterface) 71 | | 72 | */ 73 | 'id_generator' => 'Enfil\Sharding\IdGenerators\RedisSequence', 74 | 75 | /* 76 | |-------------------------------------------------------------------------- 77 | | Name of sequence table for sequence Id generators (like RedisSequence, MysqlSequence) 78 | |-------------------------------------------------------------------------- 79 | | 80 | */ 81 | 'sequence_key' => 'sharding:last-id', 82 | 83 | 'relation_key' => 'sharding:user' 84 | ], 85 | 86 | 87 | 88 | ], 89 | ]; 90 | --------------------------------------------------------------------------------