当前位置: 首页 > news >正文

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是更好的选择。

http://www.zskr.cn/news/1440223.html

相关文章:

  • OBS多路推流实战指南:突破单平台限制的直播解决方案
  • 为什么你的Veo 2视频人物总“变脸”?揭秘OpenAI未公开的Temporal Identity Token同步协议及3种绕过方案
  • Windows窗口置顶神器:3分钟解锁高效多任务工作流
  • Python之rgsucher包语法、参数和实际应用案例
  • 国内塑料改性添加剂厂家参考指南:东莞市硕美电子材料领衔,技术驱动产业升级 - 变量人生001
  • 手撕一个前端全能日志类:位掩码 + 炫彩控制台 + 高性能调用栈
  • 2025_NIPS_The RefinedWeb Dataset for Falcon LLM: Outperforming Curated Corpora with Web Data Only
  • 炉石佣兵战记自动化脚本:告别重复操作,让游戏回归策略乐趣
  • 【AVRCP】规范精讲[21]: 从轮询到主动推送,AVRCP通知事件全解析
  • 保姆级教程:在Ubuntu 20.04上搞定Isaac Gym Preview 4和RL范例环境(含常见libpython报错解决)
  • 2026杭州静奢风家装,我跑了十几家门店,推荐这5个品牌 - 高定
  • 推荐系统信息茧房与过度拟合:技术机理与工程缓解策略
  • 医院HIS与云PACS/RIS接口对接实战:门诊住院检查单同步的那些“坑”与填坑指南
  • 失效分析实战:部件寿命延长2倍 成本直降25% - 速递信息
  • 图解Transformer:现代AI的通用基石
  • 线上人气评选如何制作?云众评选小程序三分钟搞定 - 微信投票小程序
  • UE5 GAS系统避坑指南:从碰撞检测到ApplyGameplayEffectSpecToSelf的完整流程详解
  • 4D 成像雷达深度解析 | 全网独家复现篇 | 原理拆解、代码实现、车企量产落地与典型应用案例
  • 《2026 年 IT 行业最有前途的 7 个方向,选错了再努力也没用》
  • 2026四川绵阳江油手机店哪家好?二手手机、手机分期去哪家? - 博客万
  • 从Input.GetAxis到手感调优:详解Unity中移动与旋转的平滑处理与参数配置
  • 3步解锁经典游戏潜能:WarcraftHelper魔兽争霸III终极优化方案
  • MySQL 事务管理全解:从 ACID 特性、隔离级别到 MVCC 底层原理
  • 全国自闭症全托机构实力排行:合规与服务质量测评 - 奔跑123
  • 从ChatGPT-5到AGI:技术演进、行业重塑与个人应对指南
  • 比特币的浩克体质:能源消耗、安全机制与AI量子计算博弈
  • 简历写了3页还石沉大海?你根本不懂HR在找什么!
  • 智能客服系统进入工单管理,企业服务开始重视风险分层
  • Java变量:从“盒子”比喻到代码实战
  • 1 ROS和ROS2是什么?--读后感