16.2.3.6在 PHP中使用 MySQL 和memcached

PHP 通过 PECL 扩展提供对 Memcache 函数的支持。要启用 PHPmemcache 扩展, 请在从源代码构建时 使用配置--enable-memcache选项 构建 PHP。

如果您在基于 Red Hat 的服务器上安装,则可以安装php-pecl-memcacheRPM:

#> yum --install php-pecl-memcache

在基于 Debian 的发行版上,使用 php-memcache包。

php.ini要设置全局运行时配置选项,请在文件 中指定配置选项值 。下表提供了每个全局运行时配置选项的名称、默认值和说明。

配置选项 默认 描述
memcache.allow_failover 1个 指定如果选择的第一台服务器出现故障,是否应查询列表中的另一台服务器。
memcache.max_failover_attempts 20 指定在返回失败之前要尝试的服务器数。
memcache.chunk_size 8192 定义用于与 memcached服务器交换数据的网络块的大小。
memcache.default_port 11211 定义与memcached服务器通信时使用的默认端口 。
memcache.hash_strategy 标准 指定要使用的哈希策略。设置为 consistent允许在池中添加或删除服务器,而不会导致密钥重新映射到其他服务器。设置为 时 standard,将使用较旧的(模块)策略,该策略可能使用不同的服务器进行存储。
memcache.hash_function crc32 指定将键映射到服务器时要使用的函数。 crc32使用标准的 CRC32 散列。 fnv使用 FNV-1a 哈希算法。

要创建到Memcached服务器的连接,请创建一个新Memcache对象,然后指定连接选项。例如:

<?php

$cache = new Memcache;
$cache->connect('localhost',11211);
?>

这会立即打开到指定服务器的连接。

要使用多个内存缓存服务器,您需要使用以下方法将服务器添加到内存缓存对象 addServer()

bool Memcache::addServer ( string $host [, int $port [, bool $persistent
                 [, int $weight [, int $timeout [, int $retry_interval
                 [, bool $status [, callback $failure_callback
                 ]]]]]]] )

模块内的服务器管理机制 是接口的关键部分,因为它控制到memcachedphp-memcache实例 的主要接口 以及如何通过哈希机制选择不同的实例。

要创建到两个 memcached实例的简单连接:

<?php

$cache = new Memcache;
$cache->addServer('198.51.100.100',11211);
$cache->addServer('198.51.100.101',11211);
?>

在这种情况下,实例连接并未显式打开,而是仅在您尝试存储或检索值时打开。要启用与 memcached实例的持久连接,请将 $persistent参数设置为 true。这是默认设置,并使连接保持打开状态。

为了帮助控制密钥到不同实例的分发,请使用全局memcache.hash_strategy 设置。这设置了用于选择的散列机制。您还可以为每个服务器添加另一个权重,这会有效地增加实例条目在实例列表中出现的次数,从而增加该实例被选中的可能性高于其他实例。要设置权重,请将$weight参数的值设置为大于 1。

设置和获取信息的功能与 提供的通用功能接口相同, memcached如下表所示。

PECLmemcache函数 泛型函数
get() 通用get()的。
set() 通用set()的。
add() 通用add()的。
replace() 通用replace()的。
delete() 通用delete()的。
increment() 通用incr()的。
decrement() 通用decr()的。

下面提供了 PECLmemcache接口的完整示例。当用户提供电影名称时,代码会从 Sakila 数据库加载电影数据。存储到memcached实例中的数据记录为 mysqli结果行,API 会自动为您序列化该信息。

<?php

$memc = new Memcache;
$memc->addServer('localhost','11211');

if(empty($_POST['film'])) {
?>
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      <title>Simple Memcache Lookup</title>
    </head>
    <body>
      <form method="post">
        <p><b>Film</b>: <input type="text" size="20" name="film"></p>
        <input type="submit">
      </form>
      <hr/>
<?php

} else {

    echo "Loading data...\n";

    $film   = htmlspecialchars($_POST['film'], ENT_QUOTES, 'UTF-8');
    $mfilms = $memc->get($film);

    if ($mfilms) {

        printf("<p>Film data for %s loaded from memcache</p>", $mfilms['title']);

        foreach (array_keys($mfilms) as $key) {
            printf("<p><b>%s</b>: %s</p>", $key, $mfilms[$key]);
        }

    } else {

        $mysqli = mysqli('localhost','sakila','<replaceable>password</replaceable>','sakila');

        if (mysqli_connect_error()) {
            sprintf("Database error: (%d) %s", mysqli_connect_errno(), mysqli_connect_error());
            exit;
        }

        $sql = sprintf('SELECT * FROM film WHERE title="%s"', $mysqli->real_escape_string($film));

        $result = $mysqli->query($sql);

        if (!$result) {
            sprintf("Database error: (%d) %s", $mysqli->errno, $mysqli->error);
            exit;
        }

        $row = $result->fetch_assoc();

        $memc->set($row['title'], $row);

        printf("<p>Loaded (%s) from MySQL</p>", htmlspecialchars($row['title'], ENT_QUOTES, 'UTF-8');
    }
}
?>
  </body>
</html>

使用 PHP, 只要 PHP 和关联的 Apache 实例保持运行,与memcached实例的连接就会保持打开状态。在正在运行的实例中从列表中添加或删除服务器时(例如,当启动另一个提到额外服务器的脚本时),连接是共享的,但脚本仅在脚本中显式配置的实例中进行选择。

为确保脚本中服务器列表的更改不会导致问题,请确保使用一致的散列机制。