Built-in query caching for all PHP MySQL extensions/APIs

Embed Size (px)

Citation preview

MySQL native driver for PHP:The query cache plugin

mysqlnd_qc:
The query cache plugin

Ulf Wendel, Andrey HristovMySQL Connectors TeamSun Microsystems

Table of Contents

At a glanceKey Features

Basic Usage

ArchitectureMySQLnd Plugins

Cache Architecture

Storage handler

UsageAdvanced Usage

Configuration

Key Features

Transparent: no user API changessupports ext/mysqli

supports PDO_MYSQL

supports ext/mysql

Invalidation: TTL, customPer query TTL (Time to Live)

custom: user callbacks

Storage handler: build-in, customDefault (Hash), APC, Memcache

custom: user callbacks

Possibly asked questions

Can stale data be served?Sure, it is Time to live (TTL) by default! But you can implement your own invalidation strategy.

Which PHP versions are supported?PHP 5.3.3-dev or newer. At the time of writing the query cache is in prototype stage.

Where can I get it?http://forge.mysql.com/wiki/MySQLnd_Query_Cache_Plugin_for_PHP

Only buffered queries can be cached

ext/mysqlimysqli_query()

mysqli_real_query() + mysqli_store_result()

PDO_MYSQLPDO::query() if PDO::ATTR_EMULATE_PREPARES = 1 (this is the default)

ext/mysqlmysql_query()

Uncachable queries

ext/mysqlimysqli_real_query() + mysqli_use_result()

mysqli_query() + MYSQLI_ASYNC

mysqli_stmt_*()

PDO_MYSQLPDO::query() if PDO::ATTR_EMULATE_PREPARES = 0

ext/mysqlmysql_unbuffered_query()

Benchmarks?

Please run your own!Too many variables, sorry... for now ;-)

Chart compares handler no more

f

Basic Usage

$mysqli = new mysqli($host, $user, $passwd, $db, $port, $socket);;

// Cached: SQL hint used$res = $mysqli->query("/*qc=on*/" . "SELECT id, label FROM test");

var_dump($res->fetch_all(MYSQLI_ASSOC));$res->free();

SQL hint /*qc=on*/ to control caching

// Uncached: no SQL hint$res = $mysqli->query("SELECT id, label FROM test");var_dump($res->fetch_all(MYSQLI_ASSOC));$res->free();

Installation

Download sourcehttp://forge.mysql.com/wiki/MySQLnd_Query_Cache_Plugin_for_PHP

Copy extension into PHP 5.3.3+ source treecp -R query_cache my_php/ext/mysqlnd_qc

Enable query cache and build./buildconf --force

./configure --help | grep mysql

./configure --help | grep qc

make clean && make

Compared to MySQL Server Cache

Different location!Less work for the server

Shorter distance to the app (round trip times)

Scale by client

No server overload

Less sophisticated invalidation (stale data!)

Compared to Memcache

Memcache is no cacheMemcache is a storage medium

Often used for storing cached data

We offer a Memcache storage handler

Application vs. driver based cachingalmost no application changes needed

caching of raw data instead of processed data

Table of Contents

At a glanceKey Features

Basic Usage

ArchitectureMySQLnd Plugins

Cache Architecture

Storage handler

UsageCustomization

Configuration

How PHP connects to MySQL

PHPMySQL ServerLibrary: implements MySQL Client-Server Protocol

PHP API for PHP applicationsMySQL native driver for PHP / MySQL Client Library

Inside PHP (on the C level!)

PHPExtensionsZend EnginePDOext/mysqlext/mysqliSAPI

PDO_MYSQLPDO_XYZ

MySQL Client Library (libmysql) orMySQL native driver for PHP (default as of PHP 5.3)

PHP 5.3.2: mysqlnd plugin interface

ext/*mysql*

ext/*mysql*

PluginMySQL native driver for PHPC plugins operate transparently: no user API changes

Object-orientation in mysqlnd

mysqlnd_connection

connection_methodshostuserpassword...connection_methods

query()store_result()use_result()free_result()...

Inside mysqlnd: objects of data and function pointer

connection_methods

query()store_result()use_result()free_result()...

Plugin

query()store_result()use_result()free_result()...

Plugins as Proxies or Decorators

mysqlnd_connection

connection_methodshostuserpassword...Plugins replace or extend internal mysqlnd objects

Plugins can change everything

Connection methodssending queries, fetching results

metadata access

utility calls

Prepared Statement methodssending queries, fetching results

Network callssend and fetch raw MySQL protocol data

C level support for Plugins

API callsPlugin registration

management of function tables

Piggybacking datavia connection object

via result set object

via statistics hash

Query cache: proxy-style plugin

CacheMySQL

ext/*mysql*ext/*mysql*mysqlndmysqlndCache miss: record wire data, cache hit: replay

Query Cache Plugin

Query Cache: Miss

mysqlndorig. mysqlnd_conn objectmysqlnd_qc objectquery()

Should cache? Yes!

Is cached? No!

Activate data recorder

query()

Send query to MySQL

Deactivate recorder

Cache wire data

Decode data

Fetch reply

Query Cache: Hit

mysqlndmysqlnd_qc objectquery()

Should cache? Yes!

Is cached? Yes!

Fetch data from cache

Decode data

Storage handler responsibilities

StorageScope: request, process, machine, multi-machine

Location: distance to cache

Replacement strategy

Slam defense strategy

Decide what to cacheDetect SELECT statements

Parse SQL-Hints

Extended statisticsStorage statistics, traces, timings

Cache storage handler (I)

Default (Hash)Scope: process (single or multiple requests)

Location: same process

User can flush cache

Handler maintains storage statistics

APCScope: machine (multiple requests)

Location: local

User can flush cache

Handler maintains storage statistics

Cache storage handler (II)

MemcacheScope: can be shared between machines

Location: can be local or remote

User cannot flush cache

No handler statistics

NOPNo operation

Internal and not exposed to PHP land

Cache storage handler (III)

SQLiteScope, if using :memory:: process (single or multiple requests)

Scope, if using file: single (multiple) machine

Location: can be local or remote

User can flush cache

Handler maintains storage statistics

Berkeley DBtheoretically usable via the new
SQLite C API compatibility wrapper

Cache storage handler (IV)

User (procedural and object oriented)It is all up to you!

User (class mysqlnd_qc_handler_default)Default handler behaviour

Can be specialized by user

User can specialize one, many or all functions

See also extra presentation!

Cache Architecture Summary

Transparent from a user perspectiveNo user API changes

Works with all user APIs

Stores raw wire dataPro: Simplicity low risk of bugs!

Con: Client always needs to decode

Storage handlerChoice of life-span and scope

Choice of distance to client

Cache Miss

Client 2...100Client 2...100Client 2...100BTW, plan your cache carefully!

What if a shared cache entry expires?

Client 1Client 2...nCache Hit

MySQL

Client 2...100Client 2...100Client 2...100Client 1Client 2...n

MySQL

Cache Miss

Optimize storage for reuse?

Memory consumption versus peak loads

Client 1Client 2MySQL

Client 2...100Client 2...100Client 2...100Client 1Client 2...n

MySQL

Cache Miss

Cache HitClient 3..n

Table of Contents

At a glanceKey Features

Basic Usage

ArchitectureMySQLnd Plugins

Cache Architecture

Storage handler

UsageAdvanced Usage

Configuration

Customization: user handler

Procedural and OOP interfaces

Control which query gets cached

Control where to store cached data

Implement your own invalidation strategy

Maintain your own statistics

Procedural and OOP user handler

mysqlnd_qc_set_user_handlers()procedural

you must implement all storage handler functions

extending class mysqlnd_qc_handler_defaultobject oriented

customize build-in default handler

no need to spezialize all handler functions

implementing interface mysqlnd_qc_handlerobject oriented

you must implement all storage handler functions

Procedural user storage handler

void mysqlnd_qc_set_user_handlers(
string get_hash_key,
string find_query_in_cache,
string return_to_cache,
string add_query_to_cache_if_not_exists,
string query_is_select,
string update_cache_stats,
string clear_cache
)

Yes, this API may be ugly.

BUT: Prototype!
BUT: See extra presentation for vodoo!

mysqlnd_qc_set_user_handlers()

User storage handler interface (I)

function get_hash($host_info, $port, $user, $db, $query) {/* returns string */return $key;}

function find($key) { /* returns boolean */ return $found;}

function return_to_cache($key) { /* void leave empty */}
function add($key, $data, $ttl, $runtime, $store_time, $row_count) { /* returns boolean */ return $added_to_cache;
}

User storage handler interface (II)

function query_is_select($query) {/* returns mixed - boolean false if the query shall not be cached boolean true or double 0 to use mysqlnd_qc.ttl default double >= 0 to set TTL different from mysqlnd_qc.ttl */return $to_cache_or_not;}

function update_stats($key, $run_time, $store_time) { /* void data to update your per query cache statistics *//}

function clear_cache() { /* returns boolean */ return $cache_has_been_flushed;}

Object oriented storage handler

implementing interface mysqlnd_qc_handler

extending mysqlnd_qc_handler_default

See also extra presentation!

API calls

mysqlnd_qc_change_handler()

mysqlnd_qc_clear_cache()

mysqlnd_qc_get_cache_info()

mysqlnd_qc_get_core_stats()

mysqlnd_qc_get_handler()

mysqlnd_qc_get_normalized_query_trace_log()

mysqlnd_qc_get_query_trace_log()

mysqlnd_qc_set_user_handlers()

Changing the storage handler

bool mysqlnd_qc_change_handler(string handler)

Changes the storage handler. Returns false if thecurrent handler cannot be shutdown or the requestedhandler cannot be initialized. Failing to changethe handler should be considered as a fatal errorunless the change fails because the requested handleris unknown.

Procedural user storage handler

void mysqlnd_qc_set_user_handlers(
string get_hash_key,
string find_query_in_cache,
string return_to_cache,
string add_query_to_cache_if_not_exists,
string query_is_select,
string update_cache_stats,
string clear_cache
)

Sets the function names of a user defined storagehandler and puts them into use.

See also extra presentation!

Available handlers

array mysqlnd_qc_get_handlers()

Returns a list of available handler and their versions. The handler default, user, the classmyslqnd_qc_handler_default are always available.apc and memcache will be reported if support forthose handlers has been enabled at compile time.

Flushing the cache

The function is not supported by the Memcache handler!

bool mysqlnd_qc_clear_cache()

Returns true if the handler supports the operation,and has flushed the cache.

Cache info and handler statistics

// Run some queries and generate cache hits$res = $mysqli->query("/*qc=1*/" . "SELECT id, label FROM test");var_dump($res->fetch_all(MYSQLI_ASSOC));

C-based handler cache information and statistics

var_dump(mysqlnd_qc_get_cache_info());

array(4) { ["num_entries"]=> int(%d) ["handler"]=> string(7) "default" ["handler_version"]=> string(5) "1.0.0" ["data"]=> array(%d) { ["%s] => array(2) { [statistics] => array(...), [metadata] => array(...) } [, ...]}

Cache hits, time statistics and more

Remember: handler specific statisticsMemcache: no statistics at all

APC: no metadata

If available:num_entries: number of cache entries

[data][key][statistics] : run/store time statistics

[data][key][statistics] : cache hits

[data][key][metadata]: result set meta data

See also extra presentation!

Core statistics

php.ini setting: mysqlnd_qc_collect_statistics = 1

array mysqlnd_qc_get_core_statistics()

Returns a list 20+ statistics collected by the coreof the query cache plugin, if the PHP configurationsetting mysqlnd_qc_collect_statistics is set to 1.The statistics are provided by the core and thereforeavailable with all storage handlers and whenusing user-defined storage handlers. The statisticscover cache accesses, failures, network traffic as well as aggregated run and store times.

Query back trace

php.ini setting: mysqlnd_qc.query_trace = 1

array mysqlnd_qc_get_query_trace_log()

Returns a query back trace for every query that hasbeen inspected by the query cache regardless if thequery ended up being cached or not. The trace tellsyou where a query has been issues (see alsodebug_backtrace()). Together with the back traceyou get run and store times and information on ifthe query has been cached.

Normalized query back trace

mysqlnd_qc.collect_normalized_query_trace = 1

array mysqlnd_qc_get_normalized_query_trace_log()

Similar to mysqlnd_qc_get_query_trace_log() but withSQL statements normalized and aggregated by thenormalized query string. Normalization refers toreplacing actual parameters, for examplein WHERE a > 1, with questionmarks likeWHERE a > ?. WHERE a > ? will match any valuefor ?, for example 1, 2, 'abc' but not otheridentifiers.

Runtime configuration

Runtime configuration (cont.)

Basics

mysqlnd_qc.ttlTime to live in seconds

Handler can overrule setting for individual queries

mysqlnd_qc.cache_by_defaultCache every query, even those without SQL hint?

Evaluated by the core, handler cannot overrule!

mysqlnd_qc.cache_no_tableCache queries with no table name im their meta data, e.g SELECT SLEEP(1)?

Performance

mysqlnd_qc.use_request_timeUse PHP global request time to avoid gettimeofday() system calls?

Pitfall see APC docs on apc.use_request_time

mysqlnd_qc.time_statisticsCollect run time and store time statistics using gettimeofday() system call?

mysqlnd_qc.std_data_copyDefault handler: copy cached wire data?

EXPERIMENTAL use default of 0

Statistics and Slam defense

mysqlnd_qc.collect_statisticsCollect statistics for mysqlnd_qc_get_core_stats()?

mysqlnd_qc.slam_defenseActivates handler based slam defense if available

Query traces

mysqlnd_qc.collect_query_traceCollect query back traces?

mysqlnd_qc.query_trace_bt_depthMaximum back trace depth

mysqlnd_qc.collect_normalized_query_traceCollect aggregated normalized query traces?

APC storage handler

mysqlnd_qc.use_request_time = apc.use_request timeUse the same timer for TTL invalidation

mysqlnd_qc.apc_prefixKey prefix

APC handler stores data in the APC user cache

Users can manipulate the cache entries!

Memcache storage handler

mysqlnd_qc.memc_serverMemcache server host

Cannot be changed at run time

mysqlnd_qc.memc_portMemcache server port

SQLite storage handler

mysqlnd_qc.sqlite_data_fileSQLite data file

You should use SQLite as an in-memory storage

Exported PHP constants

MYSQLND_QC_ENABLE_SWITCHSQL-hint to enable caching, e.g. qc=on

Only this exact string will recognized!

MYSQLND_QC_DISABLE_SWITCHSQL-hint to disable caching, e.g. qc=off

Only this exact string will be recognized!

MYSQLND_QC_TTL_SWITCHSQL-hint for setting per query TTL, e.g. qc_ttl=

All constants can be changed as compile time!

Exported PHP classes

class mysqlnd_qc_handler_default { public function init() {} public function is_select(...) {} public function get_hash_key(...) {} public function return_to_cache(...) {} public function add_to_cache(...) {} public function find_in_cache(...) {} public function update_cache_stats(...) {} public function get_stats(...) {} public function clear_cache() {} public function shutdown() {}}

Exported PHP interfaces

interface mysqlnd_qc_handler { public function is_select(...) {} public function get_hash_key(...) {} public function return_to_cache(...) {} public function add_to_cache(...) {} public function find_in_cache(...) {} public function update_cache_stats(...) {} public function get_stats(...) {} public function clear_cache() {}}

PresentationsA query cache plugin - this is what you look at ;-)

Query cache plugin benchmark impressions

Dig deeper with QC statistics

Developing user storage handler

Further reading

The End
Feedback: [email protected]

The End

Feedback:
[email protected],
[email protected]

Sun Microsystems, Inc.

Page

Click to edit the title text format

Click to edit the outline text formatSecond Outline Level

Click to edit the notes format

Page

Click to edit the title text format

Presenters NamePresenters TitlePresenters Company

Click to edit the notes format

Page

DefaultAPCMEMCACHE

Config A1008792

Config B988585

Config C998687

PHP ini settingScopeDefaultmysqlnd_qc.ttlINI_ALL30mysqlnd_qc.cache_by_defaultINI_ALL0mysqlnd_qc.cache_no_tableINI_ALL0mysqlnd_qc.use_request_timeINI_ALL0mysqlnd_qc.time_statisticsINI_ALL1mysqlnd_qc.std_data_copyINI_SYSTEM0mysqlnd_qc.apc_prefixINI_ALLqc_mysqlnd_qc.memc_serverINI_ALL127.0.0.1mysqlnd_qc.memc_portINI_ALL11211

???Page ??? (???)26.11.2009, 17:18:45Page / PHP ini settingScopeDefaultmysqlnd_qc.collect_statisticsINI_ALL0 mysqlnd_qc.slam_defenseINI_SYSTEM0 mysqlnd_qc.query_traceINI_SYSTEM0 mysqlnd_qc_query_trace_bt_depthINI_SYSTEM3 mysqlnd_qc.collect_normalized_query_traceINI_SYSTEM0mysqlnd_qc.sqlite_data_fileINI_ALL:memory:

???Page ??? (???)16.06.2010, 13:50:53Page /