From 443b0f1771176584193d05a4b93ffb6b07b2111e Mon Sep 17 00:00:00 2001 From: Takahiro Fujita Date: Wed, 19 Aug 2020 21:59:46 +0900 Subject: [PATCH] avoid master/slave terminology --- Dockerfile | 6 +- README.md | 2 +- composer.json | 11 ++- docker-compose.yaml | 27 ++++-- src/ConfigManipulator.php | 50 +++++----- src/RedisManager.php | 28 +++--- src/RedisManagerException.php | 6 +- tests/Medium/RedisTest.php | 93 +++++++++--------- tests/Small/ConfigManipulatorTest.php | 134 +++++++++++++------------- 9 files changed, 188 insertions(+), 169 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7333ebb..c5763c3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,5 @@ -# syntax = docker/dockerfile:experimental ARG PHP_VERSION=7.3.10 -ARG COMPOSER_VERSION=1.9.0 +ARG COMPOSER_VERSION=1.10.10 # PHPの土台をつくるステージ FROM php:${PHP_VERSION}-cli AS base @@ -14,9 +13,6 @@ RUN docker-php-source extract \ && docker-php-ext-enable redis xdebug \ && docker-php-source delete -# composerの準備をするステージ -FROM base as composer - RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ git \ ssh \ diff --git a/README.md b/README.md index ca52c3f..be8b1af 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ $manager->getSlave()->get("key"); // master-host, use master ## Test ```php -docker-compose up -d --scale redis-slave1=4 redis-slave1 +docker-compose up -d --scale redis-replica1=4 redis-replica1 docker-compose run --rm phpunit-full ``` diff --git a/composer.json b/composer.json index b64fbaf..f2e384c 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "wfs/master-slave-redis", + "name": "wfs/primary-replica-redis", "version": "1.0.0", "description": "", "type": "library", @@ -22,8 +22,13 @@ }, "autoload": { "psr-4": { - "Wfs\\MasterSlaveRedis\\": "src/", - "Wfs\\MasterSlaveRedis\\Tests\\": "tests/" + "Wfs\\PrimaryReplicaRedis\\": "src/", + "Wfs\\PrimaryReplicaRedis\\Tests\\": "tests/" } + }, + "scripts": { + "phpcs": "phpcs --standard=PSR12 src", + "phpcbf": "phpcbf --standard=PSR12 src", + "phan": "phan" } } diff --git a/docker-compose.yaml b/docker-compose.yaml index 6e7c969..41093b4 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,27 +1,27 @@ version: '3.4' services: - redis-master: + redis-primary: image: redis:5.0.6-alpine - redis-slave1: + redis-replica1: image: redis:5.0.6-alpine depends_on: - - redis-master - command: redis-server --slaveof redis-master 6379 - redis-slave2: + - redis-primary + command: redis-server --replicaof redis-primary 6379 + redis-replica2: image: redis:5.0.6-alpine depends_on: - - redis-master - command: redis-server --slaveof redis-master 6379 + - redis-primary + command: redis-server --replicaof redis-primary 6379 phpunit-full: image: phpunit build: . volumes: - .:/var/www/html depends_on: - - redis-master - - redis-slave1 - - redis-slave2 + - redis-primary + - redis-replica1 + - redis-replica2 command: ./vendor/bin/phpunit --testsuite Medium --coverage-text phpunit: image: phpunit @@ -29,3 +29,10 @@ services: volumes: - .:/var/www/html command: ./vendor/bin/phpunit --testsuite Small --coverage-text + composer: + image: phpunit + build: . + volumes: + - .:/var/www/html + entrypoint: composer + diff --git a/src/ConfigManipulator.php b/src/ConfigManipulator.php index 450dcdc..141b37b 100644 --- a/src/ConfigManipulator.php +++ b/src/ConfigManipulator.php @@ -1,9 +1,13 @@ - [ + * "primary" => [ * "host" => "host-name", * "port" => 6379, * "timeout" => 3, * ], - * "slave" => [ + * "replica" => [ * [ * "host" => "host-name", * "port" => 6379, @@ -51,20 +55,20 @@ private static function fillHostDefaultValue(array $assocHostConfig): array * "timeout" => 3, * ] */ - public static function pickupMasterConfig(array $assocConfig): array + public static function pickupPrimaryConfig(array $assocConfig): array { self::throwIfInvalidConfig($assocConfig); - return self::fillHostDefaultValue($assocConfig['master']); + return self::fillHostDefaultValue($assocConfig[self::PRIMARY_KEY]); } /** * @param array $assocConfig = [ - * "master" => [ + * "primary" => [ * "host" => "host-name", * "port" => 6379, * "timeout" => 3, * ], - * "slave" => [ + * "replica" => [ * [ * "host" => "host-name", * "port" => 6379, @@ -78,18 +82,18 @@ public static function pickupMasterConfig(array $assocConfig): array * "timeout" => 3, * ] */ - public static function pickupSlaveConfig(array $assocConfig): array + public static function pickupReplicaConfig(array $assocConfig): array { self::throwIfInvalidConfig($assocConfig); - // 空ならmasterを使う - if (! isset($assocConfig['slave']) || count($assocConfig['slave']) === 0) { - return self::pickupMasterConfig($assocConfig); + // 空ならprimaryを使う + if (! isset($assocConfig[self::REPLICA_KEY]) || count($assocConfig[self::REPLICA_KEY]) === 0) { + return self::pickupPrimaryConfig($assocConfig); } // 乱択 - $index = array_rand($assocConfig['slave']); - return self::fillHostDefaultValue($assocConfig['slave'][$index]); + $index = array_rand($assocConfig[self::REPLICA_KEY]); + return self::fillHostDefaultValue($assocConfig[self::REPLICA_KEY][$index]); } private static function isValidHostConfig(array $assocHostConfig, bool $checkOptionalKeys = false): bool @@ -127,25 +131,25 @@ private static function isValidHostConfig(array $assocHostConfig, bool $checkOpt private static function isValidConfig(array $assocConfig, bool $checkOptionalKeys = false): bool { - // masterは必須。中身も正しく - if (! array_key_exists('master', $assocConfig)) { + // primaryは必須。中身も正しく + if (! array_key_exists(self::PRIMARY_KEY, $assocConfig)) { return false; } - if (! self::isValidHostConfig($assocConfig['master'], $checkOptionalKeys)) { + if (! self::isValidHostConfig($assocConfig[self::PRIMARY_KEY], $checkOptionalKeys)) { return false; } - // slaveも必須だが、空でもよい - if (! array_key_exists('slave', $assocConfig)) { + // replicaも必須だが、空でもよい + if (! array_key_exists(self::REPLICA_KEY, $assocConfig)) { return false; } - if (! is_iterable($assocConfig['slave'])) { + if (! is_iterable($assocConfig[self::REPLICA_KEY])) { return false; } - // 存在しているslave設定は正しくなければならない - foreach ($assocConfig['slave'] as $assocSlaveConfig) { - if (! self::isValidHostConfig($assocSlaveConfig, $checkOptionalKeys)) { + // 存在しているreplica設定は正しくなければならない + foreach ($assocConfig[self::REPLICA_KEY] as $assocReplicaConfig) { + if (! self::isValidHostConfig($assocReplicaConfig, $checkOptionalKeys)) { return false; } } diff --git a/src/RedisManager.php b/src/RedisManager.php index dd3533e..dcf1bce 100644 --- a/src/RedisManager.php +++ b/src/RedisManager.php @@ -1,6 +1,8 @@ -config); - return $this->connect($master, $retry, $retry_interval); + public function getPrimary( + int $retry = self::DEFAULT_RETRY_NUM, + int $retry_interval = self::DEFAULT_RETRY_INTERVAL + ): \Redis { + $primary = ConfigManipulator::pickupPrimaryConfig($this->config); + return $this->connect($primary, $retry, $retry_interval); } /** @@ -70,10 +73,11 @@ public function getMaster(int $retry = self::DEFAULT_RETRY_NUM, * @return \Redis * @throws RedisManagerException */ - public function getSlave(int $retry = self::DEFAULT_RETRY_NUM, - int $retry_interval = self::DEFAULT_RETRY_INTERVAL): \Redis - { - $slave = ConfigManipulator::pickupSlaveConfig($this->config); - return $this->connect($slave, $retry, $retry_interval); + public function getReplica( + int $retry = self::DEFAULT_RETRY_NUM, + int $retry_interval = self::DEFAULT_RETRY_INTERVAL + ): \Redis { + $replica = ConfigManipulator::pickupReplicaConfig($this->config); + return $this->connect($replica, $retry, $retry_interval); } } diff --git a/src/RedisManagerException.php b/src/RedisManagerException.php index 6edd984..8a17388 100644 --- a/src/RedisManagerException.php +++ b/src/RedisManagerException.php @@ -1,6 +1,8 @@ - [ - 'host' => 'redis-master', + 'primary' => [ + 'host' => 'redis-primary', ], - 'slave' => [ + 'replica' => [ [ - 'host' => 'redis-slave1', + 'host' => 'redis-replica1', ] ] ]); $expected = sprintf("%d", (new \DateTime())->getTimestamp()); - $manager->getMaster()->del("key1"); - $actual = $manager->getSlave()->get("key1"); + $manager->getPrimary()->del("key1"); + $actual = $manager->getReplica()->get("key1"); $this->assertFalse($actual); - $manager->getMaster()->set("key1", $expected); - $actual = $manager->getSlave()->get("key1"); + $manager->getPrimary()->set("key1", $expected); + $actual = $manager->getReplica()->get("key1"); $this->assertSame($expected, $actual); } - public function testWriteSlave() + public function testWriteReplica() { $manager = new RedisManager([ - 'master' => [ - 'host' => 'redis-master', + 'primary' => [ + 'host' => 'redis-primary', ], - 'slave' => [ + 'replica' => [ [ - 'host' => 'redis-slave1', + 'host' => 'redis-replica1', ] ] ]); $this->expectException(\RedisException::class); $this->expectDeprecationMessage("READONLY You can't write against a read only replica."); - $manager->getSlave()->del("key1"); + $manager->getReplica()->del("key1"); } public function testConnectionError() { $manager = new RedisManager([ - 'master' => [ - 'host' => 'redis-master', + 'primary' => [ + 'host' => 'redis-primary', 'port' => 1234, ], - 'slave' => [ + 'replica' => [ [ - 'host' => 'redis-slave1', + 'host' => 'redis-replica1', ] ] ]); $this->expectException(RedisManagerException::class); - $manager->getMaster()->info(); + $manager->getPrimary()->info(); } public function testPersistent() { $manager = new RedisManager([ - 'master' => [ - 'host' => 'redis-master', + 'primary' => [ + 'host' => 'redis-primary', ], - 'slave' => [ + 'replica' => [ [ - 'host' => 'redis-slave1', + 'host' => 'redis-replica1', ] ] ]); // total_connections_received: 累積接続コネクション数 - $ret = $manager->getMaster()->info(); + $ret = $manager->getPrimary()->info(); $startConnections = $ret['total_connections_received']; - $ret = $manager->getMaster()->info(); - $ret = $manager->getMaster()->info(); - $ret = $manager->getMaster()->info(); - $ret = $manager->getMaster()->info(); - $ret = $manager->getMaster()->info(); - // getMaster(pconnect)を繰り返してもコネクション接続回数が増えない + $ret = $manager->getPrimary()->info(); + $ret = $manager->getPrimary()->info(); + $ret = $manager->getPrimary()->info(); + $ret = $manager->getPrimary()->info(); + $ret = $manager->getPrimary()->info(); + // getPrimary(pconnect)を繰り返してもコネクション接続回数が増えない $this->assertSame($startConnections, $ret['total_connections_received']); - $manager->getMaster()->close(); - $ret = $manager->getMaster()->info(); + $manager->getPrimary()->close(); + $ret = $manager->getPrimary()->info(); // closeの後は1回増える $this->assertSame($startConnections + 1, $ret['total_connections_received']); } @@ -97,28 +97,28 @@ public function testPersistent() public function testDnsRoundRobin() { $manager = new RedisManager([ - 'master' => [ - 'host' => 'redis-master', + 'primary' => [ + 'host' => 'redis-primary', ], - 'slave' => [ + 'replica' => [ [ - 'host' => 'redis-slave1', + 'host' => 'redis-replica1', ] ] ]); // total_connections_received: 累積接続コネクション数 - $addressList = gethostbynamel('redis-slave1'); + $addressList = gethostbynamel('redis-replica1'); $this->assertCount(4, $addressList, <<< EOT You must run this test with the following command: -docker-compose up -d --scale redis-slave1=4 redis-slave1 +docker-compose up -d --scale redis-replica1=4 redis-replica1 docker-compose run --rm phpunit-full EOT ); $runIds = []; for ($i = 0; $i < 100; $i++) { - $ret = $manager->getSlave()->info(); + $ret = $manager->getReplica()->info(); $runIds[] = $ret['run_id']; } $uniqueRunIds = array_unique($runIds); @@ -130,18 +130,19 @@ public function testDnsRoundRobinWithPureRedisObject() { $redis = new Redis(); // total_connections_received: 累積接続コネクション数 - $addressList = gethostbynamel('redis-slave1'); + $addressList = gethostbynamel('redis-replica1'); $this->assertCount(4, $addressList, <<< EOT You must run this test with the following command: -docker-compose up -d --scale redis-slave1=4 redis-slave1 +docker-compose up -d --scale redis-replica1=4 redis-replica1 docker-compose run --rm phpunit-full EOT ); $runIds = []; for ($i = 0; $i < 100; $i++) { - $ret = $redis->pconnect('redis-slave1'); + $redis->pconnect('redis-replica1'); + $ret = $redis->info(); $runIds[] = $ret['run_id']; } $uniqueRunIds = array_unique($runIds); diff --git a/tests/Small/ConfigManipulatorTest.php b/tests/Small/ConfigManipulatorTest.php index 34b69ce..adbf257 100644 --- a/tests/Small/ConfigManipulatorTest.php +++ b/tests/Small/ConfigManipulatorTest.php @@ -1,9 +1,9 @@ $validHostConfig, + 'primary' => $validHostConfig, ], false, false], [[ - 'master' => $validHostConfig, - 'slave' => 'string', + 'primary' => $validHostConfig, + 'replica' => 'string', ], false, false], [[ - 'master' => $validHostConfig, - 'slave' => [], + 'primary' => $validHostConfig, + 'replica' => [], ], false, true], [[ - 'master' => $validHostConfigOnlyNecessaryKeys, - 'slave' => [], + 'primary' => $validHostConfigOnlyNecessaryKeys, + 'replica' => [], ], false, true], [[ - 'master' => $invalidHostConfig, - 'slave' => [], + 'primary' => $invalidHostConfig, + 'replica' => [], ], false, false], [[ - 'master' => $validHostConfig, - 'slave' => [], + 'primary' => $validHostConfig, + 'replica' => [], ], false, true], [[ - 'master' => $validHostConfig, - 'slave' => [ + 'primary' => $validHostConfig, + 'replica' => [ $validHostConfig, ], ], false, true], [[ - 'master' => $validHostConfig, - 'slave' => [ + 'primary' => $validHostConfig, + 'replica' => [ $validHostConfigOnlyNecessaryKeys, ], ], false, true], [[ - 'master' => $validHostConfig, - 'slave' => [ + 'primary' => $validHostConfig, + 'replica' => [ $invalidHostConfig, ], ], false, false], [[ - 'master' => $validHostConfig, - 'slave' => [ + 'primary' => $validHostConfig, + 'replica' => [ $validHostConfig, $validHostConfigOnlyNecessaryKeys, ], ], false, true], [[ - 'master' => $validHostConfig, - 'slave' => [ + 'primary' => $validHostConfig, + 'replica' => [ $validHostConfig, $invalidHostConfig, ], @@ -197,52 +197,52 @@ public function isValidConfigDataProvider() [[], true, false], [[ - 'master' => $validHostConfig, + 'primary' => $validHostConfig, ], true, false], [[ - 'master' => $validHostConfig, - 'slave' => [], + 'primary' => $validHostConfig, + 'replica' => [], ], true, true], [[ - 'master' => $validHostConfigOnlyNecessaryKeys, - 'slave' => [], + 'primary' => $validHostConfigOnlyNecessaryKeys, + 'replica' => [], ], true, false], [[ - 'master' => $invalidHostConfig, - 'slave' => [], + 'primary' => $invalidHostConfig, + 'replica' => [], ], true, false], [[ - 'master' => $validHostConfig, - 'slave' => [], + 'primary' => $validHostConfig, + 'replica' => [], ], true, true], [[ - 'master' => $validHostConfig, - 'slave' => [ + 'primary' => $validHostConfig, + 'replica' => [ $validHostConfig, ], ], true, true], [[ - 'master' => $validHostConfig, - 'slave' => [ + 'primary' => $validHostConfig, + 'replica' => [ $validHostConfigOnlyNecessaryKeys, ], ], true, false], [[ - 'master' => $validHostConfig, - 'slave' => [ + 'primary' => $validHostConfig, + 'replica' => [ $invalidHostConfig, ], ], true, false], [[ - 'master' => $validHostConfig, - 'slave' => [ + 'primary' => $validHostConfig, + 'replica' => [ $validHostConfig, $validHostConfigOnlyNecessaryKeys, ], ], true, false], [[ - 'master' => $validHostConfig, - 'slave' => [ + 'primary' => $validHostConfig, + 'replica' => [ $validHostConfig, $invalidHostConfig, ], @@ -267,11 +267,11 @@ public function testIsValidConfig($assocConfig, $checkOptionalKeys, $exceptedRes public function testIsValidConfigOptionalArgs() { Closure::bind(function () { - $actual = ConfigManipulator::isValidConfig(['master' => ['host' => 'host-name'], 'slave' => []], false); + $actual = ConfigManipulator::isValidConfig(['primary' => ['host' => 'host-name'], 'replica' => []], false); $this->assertTrue($actual); - $actual = ConfigManipulator::isValidConfig(['master' => ['host' => 'host-name'], 'slave' => []], true); + $actual = ConfigManipulator::isValidConfig(['primary' => ['host' => 'host-name'], 'replica' => []], true); $this->assertFalse($actual); - $actual = ConfigManipulator::isValidConfig(['master' => ['host' => 'host-name'], 'slave' => []]); + $actual = ConfigManipulator::isValidConfig(['primary' => ['host' => 'host-name'], 'replica' => []]); $this->assertTrue($actual); }, $this, ConfigManipulator::class)->__invoke(); } @@ -342,25 +342,25 @@ public function testFillHostDefaultValue($inputAssocConfig, $expectedAssocConfig }, $this, ConfigManipulator::class)->__invoke(); } - public function testPickupMasterConfigWithoutInvalidConfig() + public function testPickupPrimaryConfigWithoutInvalidConfig() { $this->expectException(\InvalidArgumentException::class); - ConfigManipulator::pickupMasterConfig([]); + ConfigManipulator::pickupPrimaryConfig([]); } - public function testPickupMasterConfig() + public function testPickupPrimaryConfig() { - $actual = ConfigManipulator::pickupMasterConfig([ - 'master' => [ - 'host' => 'master-host', + $actual = ConfigManipulator::pickupPrimaryConfig([ + 'primary' => [ + 'host' => 'primary-host', ], - 'slave' => [ + 'replica' => [ [ - 'host' => 'slave-host', + 'host' => 'replica-host', ] ] ]); $expected = [ - 'host' => 'master-host', + 'host' => 'primary-host', 'port' => ConfigManipulator::DEFAULT_PORT, 'timeout' => ConfigManipulator::DEFAULT_TIMEOUT, ]; @@ -369,20 +369,20 @@ public function testPickupMasterConfig() $this->assertSame($expected, $actual); } - public function testPickupSlaveConfigWithSlave() + public function testPickupReplicaConfigWithReplica() { - $actual = ConfigManipulator::pickupSlaveConfig([ - 'master' => [ - 'host' => 'master-host', + $actual = ConfigManipulator::pickupReplicaConfig([ + 'primary' => [ + 'host' => 'primary-host', ], - 'slave' => [ + 'replica' => [ [ - 'host' => 'slave-host', + 'host' => 'replica-host', ] ] ]); $expected = [ - 'host' => 'slave-host', + 'host' => 'replica-host', 'port' => ConfigManipulator::DEFAULT_PORT, 'timeout' => ConfigManipulator::DEFAULT_TIMEOUT, ]; @@ -392,17 +392,17 @@ public function testPickupSlaveConfigWithSlave() } - public function testPickupSlaveConfigWithoutSlave() + public function testPickupReplicaConfigWithoutReplica() { - $actual = ConfigManipulator::pickupSlaveConfig([ - 'master' => [ - 'host' => 'master-host', + $actual = ConfigManipulator::pickupReplicaConfig([ + 'primary' => [ + 'host' => 'primary-host', ], - 'slave' => [ + 'replica' => [ ] ]); $expected = [ - 'host' => 'master-host', + 'host' => 'primary-host', 'port' => ConfigManipulator::DEFAULT_PORT, 'timeout' => ConfigManipulator::DEFAULT_TIMEOUT, ];