Mysqlnd: Asynchronous Queries and More...
Mysqlnd: Asynchronous Queries and More...
1
mysqlnd: Asynchronous
Queries and more ...
Ulf Wendel
Senior Software Engineer
Sun Microsystems
2
The MySQL PHP “Connectors”
Andrey Hristov (Development - mysqlnd),
Johannes Schlüter (Development),
Ulf Wendel (QA) and Georg Richter (everything, somehow...)
3
How PHP connects to MySQL
PHP API for PHP applications
PHP
MySQL
Library:
native
implements
driver for
MySQL
PHP Client-Server
/ MySQL ClientProtocol
Library
MySQL Server
4
The “MySQL native driver for PHP“
• Native?
> Integrated tightly into PHP!
> NOT written in PHP, written in C
• Driver?
> A library that implements the
communication protocol
> NOT a new API for PHP users!
• For PHP?
> Optimized for nothing but PHP!
> Easier to maintain: part of PHP, works
with every MySQL 5
Inside PHP (on the C level!)
PHP
Zend Engine SAPI Extensions
PDO_MYSQL PDO_XYZ
6
PHP and the MySQL Client Library
PHP
Memory: emalloc,
PHP* Infrastructure
IO: PHP Streams
ext/mysql ext/mysqli PDO_MYSQL
MySQL Server
Memory: malloc,Operating
* System
IO: read, write, ...
7
PHP and mysqlnd
PHP
Memory: emalloc,
PHP
* InfrastruktorIO: PHP Streams
ext/mysql ext/mysqli PDO_MYSQL
MySQL Server
8
Which API would you like?
ext/mysql ext/mysqli PDO_MYSQL
Maintained byMySQL yes yes yes
Futureadditions fromMySQL no yes yes
Comes with PHP 4 yes no no
Comes with PHP 5 yes yes yes
Comes with PHP 6 yes yes yes
Supportof MySQL <4.1 yes no yes
Supportof MySQL >=4.1 incomplete yes incomplete
MySQL ClientLibrary yes yes yes
MySQL nativedriver for PHP yes yes yes
9
Mixed Salad
PHP
ext/mysql ext/mysqli PDO_MYSQL
MySQL Server
./configure –-with-mysql=/path/to/mysql_config \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd
10
Advantage mysqlnd!
• 0% to 5% faster
• Microbenchmarks: -5% to +1200%
faster
• 0% to 40% lower memory usage
• 120+ performance statistics –
mysqli_select_varchar_buffered.php
phpinfo()
180
160
140
120
Percent
100 Libmysql
mysqlnd
80
60
40
20
0
127 255 512 1024 2048 4096 8192 16384 32768 65000
11
Read-Only Variablen (Copy on Write)
<?php $row = mysqli_fetch_assoc($res); ?>
1M
z.B. ext/mysqli z.B. ext/mysqli
“zval” $row using copy
mysqlnd
“zval” $row using pointerMySQL Client Library
Row 1 Row 2 Row 3 Row 1 Row 2 Row 3
1M 1M
MySQL Server
12
Cheers – mysqlnd rocks!
13
Sharding – split and distribute
• Problem
> CPU bound: too much work for one
DB system
> Disk bound: too large entities for
one DB system
• Solution
> Split schema and distribute data
> Use 1, 2, 4, 8, 16, 32, 64, 128, ...
16384 blades
14
How to split and distribute?
Single DB Users Postings Categories
16
Where to split and distribute?
• Application, DAO, ...
> New shard? Expensive
programming to follow
• Framework, SOA, ...
> Ask Rasmus...
• Driver
> Which PHP driver can do it?
mysqlnd?
• (Transparent) Proxy
> For example, MySQL Proxy, HSCALE
17
“Transparent” Proxy with mysqlnd?
bzr clone lp:~johannes-s/php-
mysqlnd/mysqli-to-stream
$mysqli = mysqli_connect("host", "user", "pw", "db");
$stream = mysqli_conn_to_stream($mysqli);
stream_filter_register("rewrite", "rewrite_filter");
stream_filter_append($stream, "rewrite");
var_dump($row);
array(1) { ["_one"]=> string(1) "2" }
18
Query Rewriting with mysqlnd
100% experimental – no packet
decoders exported to PHP
class rewrite_filter extends php_user_filter {
$bucket->data = str_replace(
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
return PSFS_PASS_ON;
}
19
Sharding - a forum example
• Distribution logic
> Implemented inside the PHP
application
> “Users click on categories to read
postings”
• ER-Model, 3 shards
> Split postings by categories.id
Shard 1 Users Categories
> Denormalize postings: add
users.nickname
Shard
Postings
2 with users.nickname, category_id % 2 =
Shard
Postings
3 with users.nickname, category_id % 2 =
20
Your new problems...
• Show all postings of a user
> Union operation over shard 2 and
shard 3
> Fetch user information from shard 1
• Calculate the total number of
postings
Shard 1 Users Categories
> Aggregation on shard 2 and shard 3
Shard
Postings
2 with users.nickname, category_id % 2 =
Shard
Postings
3 with users.nickname, category_id % 2 =
21
Show all postings of a user
$shard3 = mysqli_connect('shard3',...);
$res = $shard3->query('SELECT ... FROM postings WHERE ...');
display_postings($res); 22
The basic idea
PHP MySQL Server
SELECT ...
PHP
MySQL Server
PHP
23
New asynchronous API
boolean mysqli_query(
string query,
MYSQLI_ASYNC)
int mysqli_poll(
array $connections,
array $except,
array $rejected,
int $tv_sec
[, int tv_usec])
24
Asynchronous “Show all ...” - I
$shard1 = mysqli_connect('shard1', ...);
25
Asynchronous “Show all ...” - II
$all_links = array($shard1, $shard2, $shard3);
$processed = 0;
do {
continue;
if ($res = mysqli_reap_async_query($link)) {
mysqli_free_result($res);
$processed++;
} 26
Synchronous vs. asynchronous
1000ms 500ms 600ms
1000ms
500ms
600ms
$m1
> = mysqli_connect('host',
sapi/cli/php 'user', 'password', 'schema');
mysqli_poll2.php
$m2 = mysqli_connect('host',
Query : 0.00s 'user', 'password', 'schema');
mysqli_query($m1,
Poll : 0.05s 'SELECT SLEEP(0.10)', MYSQLI_ASYNC);
mysqli_query($m2,
Fetch 1 : 0.11s 'SELECT SLEEP(0.25)', MYSQLI_ASYNC);
printf("Query
Poll : 0.11s : %2.2fs\n", microtime(true) - $start);
while ($processed
Poll : 0.15s < 2) {
$links:=0.21s
Poll array($m1, $m2);
if (mysqli_poll($links,
Fetch 2 : 0.26s array(), array(), 0, 50000)) {
if ($res = mysqli_reap_async_query($link)) {
mysqli_free_result($res);
}
28
Mixing SELECT and INSERT
$m1 = mysqli_connect('host',
> sapi/cli/php 'user', 'passwd', 'database');
mysqli_poll2.php
$m2 = mysqli_connect('host',
Query : 0.00s 'user', 'passwd', 'database');
mysqli_query($m1,
Poll : 0.05s 'SELECT SLEEP(0.10)', MYSQLI_ASYNC);
mysqli_query($m2,
Fetch 1 : 0.11s 'INSERT INTO users(id) VALUES (100)', MYSQLI_ASYNC);
Poll : 0.11s
while
Poll ($processed
: 0.15s < 2) {
$links
Poll = array($m1, $m2);
: 0.21s
if 2
Fetch (mysqli_poll($links,
: 0.26s array(), array(), 0, 50000)) {
Poll foreach
: 0.26s ($links as $link)
if (is_object($res = mysqli_reap_async_query($link))) {
$processed++;
mysqli_free_result($res);
} else {
$processed++; 29
Handling Server errors
$m1 = mysqli_connect('localhost',
> sapi/cli/php 'user', 'password', 'schema');
mysqli_poll_error.php
$m2 = mysqli_connect("localhost",
array(1) { "user", "password", "schema");
mysqli_query($m1,
[1]=> 'SELECT NIXNUTZ FOR PREDISENT', MYSQLI_ASYNC);
mysqli_query($m2,
string(1) "1" "SELECT 1", MYSQLI_ASYNC | MYSQLI_USE_RESULT);
while
} ($processed < 2) {
$links
[1064] = array($m1,
You $m2);
have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near
if (mysqli_poll($links, array(), array(), 0, 50000))
'PREDISENT' at line 1
foreach ($links as $k => $link) {
if (is_object($res = mysqli_reap_async_query($link))) {
var_dump(mysqli_fetch_assoc($res)); mysqli_free_result($res);
} else if (mysqli_errno($link))
else
printf("Connection %d: no
Connection 206: SELECT 1 query\n", mysqli_thread_id($m1));
mysqli_query($m2, 'SELECT 1',
Connection 205: rejected MYSQLI_ASYNC | MYSQLI_USE_RESULT);
continue;
$processed += count($rejected);
mysqli_reap_async_query($link);
'Parallel' INSERT (2 shards, 1000 rows) 1.98s
if rows
2000 (mysqli_errno($link))
deleted
die(mysqli_error($link));
$all_links[mysqli_thread_id($link)]['inserted']++;
$i++;
else
die(mysqli_error($link)); 32
Andrey suffers from Insomnia
> sapi/cli/php mysqli_poll_bulk_insert.php
Hi Ulf,
Sequential INSERT (2 shards, 1000 rows) 4.22s
I did a small
2000 rows deleted modification to mysqlnd, locally,
33
Andrey suffers from Insomnia II
> sapi/cli/php mysqli_poll_bulk_insert.php
100%
Sequentialexperimental!
INSERT (2 shards, 1000 rows) 4.22s
Don't trust
2000 rows the performance figures!
deleted
34
Where to get mysqlnd with async?
If still possible to commit into 5.3 tree:
PHP 5.3+ CVS
// the super secret Launchpad repository with all raw-bin ideas
cd php5/ext
cp -R /path/to/bzr_clone/trunk/mysqlnd mysqlnd
cp -R /path/to/bzr_clone/trunk/php5/ext/mysqli mysqli
cd ..
35
./buildconf –-force ; ./configure -–with-mysqli=mysqlnd
The End
Feedback: [email protected]
The End
Feedback: [email protected]
36