Professional Documents
Culture Documents
MySQL Replication
Master: writes, Slaves: reads Various topologies supported Other use cases: backup, HA, OLTP/warehousing
Client
Writes
Master Slave
Reads
Slave Slave
MySQL Cluster
Tasks:
Choose servers to execute statement Load balance within candidates Maintain connection pool Automatic (client) fail over for High Availability
Client
MySQL Server 1
MySQL Server 2
MySQL Server n
mysql, mysqli, PDO_MYSQL mysqlnd PECL/mysqlnd_ms plugin Statement Redirection Balancing Failover Connection Pooling
MySQL Server 1
MySQL Server 2
MySQL Server n
class DBRepl { private static $master_list = array(...); private static $master = NULL; private static $slave_list = array(...); private static $slave = NULL; public static function WriteConn() { if (self::$master) return self::$master; /* pick and initialize ...*/ } public static function ReadConn() { if (self::$slave) return self::$slave; /* pick and initialize ...*/ } }
PECL/mysqlnd_ms 1.4
Anything missing?
All PHP MySQL APIs, semi-transparent, drop-in Read write splitting, transaction aware Load balancing, fail over (optional: automatic) Service levels: consistency, slave lag limit, trottling Optional, automatic caching of read results User can control all automatic actions 75+ pages documentation: hands on and reference Stable, more test code than C code Some 10 bug reports since 1.0
Read/Write splitting
Default: mysqlnd_ms.disable_rw_split = 0
read-only: statement begins with SELECT read-only: statement begins with slave SQL hint custom: callback picks slave for statement
Client
Writes
Master
$mysqli = new mysqli("myapp", "username", "password", "database"); /* Disable autocommit, master used, no server switch allowed */ $mysqli->autocommit(FALSE); /* ... */ if (!$mysqli->commit()) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error)); } /* Transaction has ended, load balancing begins again */ $mysqli->autocommit(TRUE);
$mysqli = DBRel::ReadConn(); /* ... */ $mysqli = DBRepl::WriteConn() $mysqli->autocommit(FALSE); /* ... */ if (!$mysqli->commit()) { die(sprintf("[%d] %s\n", $mysqli->errno, $mysqli->error)); } /* ... */ $mysqli->autocommit(TRUE); $mysqli = DBRepl::ReadConn();
Load Balancing
Writes
Master Weight = 1
Writes
Master
Reads
Slave Slave Slave
Writes
Master Slave
Reads
Slave Slave
Quality of service
Eventual consistency
MySQL Node
MySQL Node
MySQL Node
GET X, X = 0
GET X, NULL
$mysqli = new mysqli("myapp", "username", "password", "database"); /* read-write splitting: master used */ $mysqli->query("INSERT INTO orders(item) VALUES ('elePHPant')"); /* Request session consistency: read your writes */ mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_SESSION); /* Plugin picks a node which has the changes, here: master */ $res = $mysqli->query("SELECT item FROM orders WHERE order_id = 1"); var_dump($res->fetch_assoc()); /* Back to eventual consistency: stale data allowed */ mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL); /* Plugin picks any slave, stale data is allowed */ $res = $mysqli->query("SELECT item, price FROM specials");
MySQL Master Log 7, Pos 34, GTID M:1: UPDATE x=1 Log 7, Pos 35, GTID M:2: UPDATE x=9
MySQL Slave 1 , GTID M:1: UPDATE x=1 , GTID M:2: UPDATE x=9
Client B GET X, X = 1
MySQL Slave
MySQL Slave
GET X, X = 9
MySQL Slave 1 , GTID M:1: UPDATE x=1 , GTID M:2: UPDATE x=9
SET X = 9
MySQL Master
GET X, X = 8
1st GET X, X = 8
2nd GET X, X = 8
Cache
Transparent caching
$mysqli = new mysqli("myapp", "username", "password", "database"); /* no caching */ $res = $mysqli->query("SELECT headline FROM latest_news"); var_dump($res->fetch_all(MYSQLI_ASSOC)); /* use cache, if slave lag allows */ mysqlnd_ms_set_qos($mysqli, MYSQLND_MS_QOS_CONSISTENCY_EVENTUAL, MYSQLND_MS_QOS_OPTION_CACHE, 60)); $res = $mysqli->query("SELECT headline FROM old_news"); var_dump($res->fetch_all(MYSQLI_ASSOC));
THE END
MySQL Node
MySQL Node
MySQL Node
MySQL Node
MySQL Node
MySQL Node
Additional component
Complex architecture, can be single point of failure C and Lua are no natural match for PHP lovers Adds latency: from client to proxy to node
MySQL Node
MySQL Node
MySQL Node
MySQL Node
MySQL Node
MySQL Node
MySQL Node
MySQL Node
MySQL Node
MySQL Node
MySQL Node
MySQL Node