news 2026/6/1 11:21:58

PHP与Memcached缓存实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PHP与Memcached缓存实战

PHP与Memcached缓存实战

Memcached是一个高性能的分布式内存缓存系统。虽然Redis越来越流行,但Memcached在某些场景下仍有不可替代的优势。今天说说PHP中Memcached的使用技巧。

PHP有两个Memcached扩展,memcache和memcached。推荐使用memcached扩展,功能更完善,性能更好。

```php
// 连接Memcached
$memcached = new Memcached();
$memcached->addServer('127.0.0.1', 11211);

// 检查连接
$stats = $memcached->getStats();
$serverStats = $stats['127.0.0.1:11211'] ?? [];
echo "Memcached版本: " . ($serverStats['version'] ?? '未知') . "\n";
echo "当前连接数: " . ($serverStats['curr_connections'] ?? '0') . "\n";

// 基本操作
$memcached->set('key1', 'value1', 3600);
echo $memcached->get('key1') . "\n";

// 存储数组
$memcached->set('user:1', [
'name' => '张三',
'age' => 28,
'email' => 'zhangsan@test.com',
], 3600);

$user = $memcached->get('user:1');
echo "姓名: {$user['name']}\n";
?>
```

Memcached不支持数据持久化,纯内存缓存性能极高。适合缓存数据库查询结果、API响应、计算结果等。

```php
class CacheManager
{
private Memcached $memcached;
private string $prefix;
private int $defaultTtl;

public function __construct(string $prefix = 'app:', int $defaultTtl = 3600)
{
$this->memcached = new Memcached();
$this->memcached->addServer('127.0.0.1', 11211);
$this->memcached->setOption(Memcached::OPT_PREFIX_KEY, $prefix);
$this->memcached->setOption(Memcached::OPT_COMPRESSION, true);
$this->memcached->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
$this->prefix = $prefix;
$this->defaultTtl = $defaultTtl;
}

public function get(string $key): mixed
{
$result = $this->memcached->get($this->prefix . $key);
$this->checkResultCode('get', $key);
return $result !== false ? $result : null;
}

public function set(string $key, mixed $value, ?int $ttl = null): bool
{
$ttl = $ttl ?? $this->defaultTtl;
$result = $this->memcached->set($this->prefix . $key, $value, $ttl);
$this->checkResultCode('set', $key);
return $result;
}

public function delete(string $key): bool
{
$result = $this->memcached->delete($this->prefix . $key);
$this->checkResultCode('delete', $key);
return $result;
}

public function remember(string $key, callable $callback, ?int $ttl = null): mixed
{
$value = $this->get($key);
if ($value !== null) {
return $value;
}

$value = $callback();
$this->set($key, $value, $ttl);
return $value;
}

public function getMulti(array $keys): array
{
$prefixedKeys = array_map(fn($k) => $this->prefix . $k, $keys);
$results = $this->memcached->getMulti($prefixedKeys);

// 去掉前缀
$unprefixed = [];
foreach ($results as $key => $value) {
$originalKey = str_replace($this->prefix, '', $key);
$unprefixed[$originalKey] = $value;
}

return $unprefixed;
}

public function setMulti(array $items, ?int $ttl = null): bool
{
$ttl = $ttl ?? $this->defaultTtl;
$prefixed = [];
foreach ($items as $key => $value) {
$prefixed[$this->prefix . $key] = $value;
}
return $this->memcached->setMulti($prefixed, $ttl);
}

public function increment(string $key, int $offset = 1): int|false
{
return $this->memcached->increment($this->prefix . $key, $offset);
}

public function decrement(string $key, int $offset = 1): int|false
{
return $this->memcached->decrement($this->prefix . $key, $offset);
}

public function flush(): bool
{
return $this->memcached->flush();
}

public function getStats(): array
{
return $this->memcached->getStats();
}

private function checkResultCode(string $operation, string $key): void
{
$code = $this->memcached->getResultCode();
if ($code !== Memcached::RES_SUCCESS) {
error_log("Memcached $operation $key: " . $this->memcached->getResultMessage());
}
}
}

$cache = new CacheManager('myapp:', 1800);
$users = $cache->remember('users.active', function () {
return [['id' => 1, 'name' => '张三'], ['id' => 2, 'name' => '李四']];
}, 600);
print_r($users);
?>
```

Memcached用于计数器场景:

```php
// 计数器
function incrementPageView(string $pageId): int
{
$memcached = new Memcached();
$memcached->addServer('127.0.0.1', 11211);

$key = "pageview:$pageId";
$count = $memcached->increment($key, 1);

if ($count === false) {
$memcached->set($key, 1, 86400);
$count = 1;
}

return $count;
}

echo "页面浏览量: " . incrementPageView('homepage') . "\n";
echo "页面浏览量: " . incrementPageView('homepage') . "\n";
echo "页面浏览量: " . incrementPageView('homepage') . "\n";
?>
```

Memcached的CAS(Check and Set)操作用于并发控制:

```php
// CAS操作
function atomicUpdate(Memcached $memcached, string $key, callable $updateFn): bool
{
do {
$value = $memcached->get($key, null, $casToken);
if ($value === false) {
// key不存在
$newValue = $updateFn(null);
return $memcached->add($key, $newValue, 3600);
}

$newValue = $updateFn($value);
// CAS更新,如果casToken变了说明被其他进程修改了
$result = $memcached->cas($casToken, $key, $newValue, 3600);
} while ($result === false && $memcached->getResultCode() === Memcached::RES_DATA_EXISTS);

return $result;
}

$memcached = new Memcached();
$memcached->addServer('127.0.0.1', 11211);

$memcached->set('counter', 0, 3600);

for ($i = 0; $i < 10; $i++) {
atomicUpdate($memcached, 'counter', function ($current) {
return ($current ?? 0) + 1;
});
}

echo "最终计数: " . $memcached->get('counter') . "\n";
?>
```

Memcached作为session存储后端,可以跨服务器共享会话:

```php
// 使用Memcached存储session
ini_set('session.save_handler', 'memcached');
ini_set('session.save_path', '127.0.0.1:11211');

session_start();
$_SESSION['user_id'] = 123;
$_SESSION['username'] = '张三';
$_SESSION['role'] = 'admin';
echo "会话已存储在Memcached\n";
?>
```

Memcached的LRU淘汰策略会在内存不足时自动淘汰最近最少使用的数据。所以使用Memcached时要注意设置合理的过期时间,避免热点数据被非热点数据挤出。Memcached适合缓存小数据块,单条数据不要超过1MB。如果需要持久化或复杂数据结构,Redis是更好的选择。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/1 11:21:57

Python之rgsucher包语法、参数和实际应用案例

Python rgsucher包完整使用指南 rgsucher 是Python中专注于正则表达式快速检索、匹配、提取、替换的高效工具包&#xff0c;简化了原生re库的复杂语法&#xff0c;内置大量预设正则模板&#xff0c;支持批量文本处理、多模式匹配、结果格式化输出&#xff0c;是文本解析、数据清…

作者头像 李华
网站建设 2026/6/1 11:20:05

【信息科学与工程学】【安全领域】 第八十八篇 网络空间安全19

编号 网络空间安全领域 网络空间存在的安全问题 解决方式/方法/操作/行为详细说明和技术手段/管理方法/运营策略 关键参数/数学模型/算法 关联知识/技术标准 9981 云计算/硬件安全 (CPU/微架构) “非临时存储推测”与跨进程数据采样攻击​ 1. 微码更新与操作系统协同防…

作者头像 李华
网站建设 2026/6/1 11:18:23

实验报告册

实验拓扑图&#xff1a;实验要求&#xff1a;1、R4为ISP&#xff0c;其上只配置IP地址&#xff1b;R4与其他所直连设备间均使用公有IP&#xff1b; 2、R3-R5、R6、R7为MGRE环境&#xff0c;R3为中心站点&#xff1b; 3、整个OSPF环境IP基于172.16.0.0/16划分&#xff1b;除了R1…

作者头像 李华
网站建设 2026/6/1 11:15:49

AI文本人性化处理:消除机器感,打造个人风格写作指南

1. 项目概述&#xff1a;当AI写作成为日常&#xff0c;如何让它听起来更像“你” 最近和不少同行、学生朋友聊天&#xff0c;发现一个挺普遍的现象&#xff1a;大家或多或少都在用AI工具辅助写作&#xff0c;从起草邮件、润色报告&#xff0c;到生成初稿、整理思路。工具本身效…

作者头像 李华
网站建设 2026/6/1 11:15:27

力扣热题100题第二部分

208.实现Trie&#xff08;前缀树&#xff09;这道题目中要实现的Trie(前缀树&#xff09;。它不光是一个数据结构&#xff0c;更是一种用空间换时间&#xff0c;按前缀组织字符串的思想。它的核心优势有&#xff1a;前缀查询极快、动态插入不影响已有结构、自动压缩公共前缀。它…

作者头像 李华