当前位置: 首页 > 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.jsqmd.com/news/928888/

相关文章:

  • 如何从图表图像中提取精确数据?WebPlotDigitizer完整解决方案指南
  • WorkBuddy结果查看功能全解析
  • 力扣热题100题第二部分
  • 为什么你的Veo 2视频人物总“变脸”?揭秘OpenAI未公开的Temporal Identity Token同步协议及3种绕过方案
  • Windows窗口置顶神器:3分钟解锁高效多任务工作流
  • Python之rgsucher包语法、参数和实际应用案例
  • 如何3分钟搞定城通网盘下载:ctfileGet直链解析工具的完整使用指南
  • 【Flutter】Flutter 常用命令 ( 官方文档 | 环境与版本管理 | 项目创建与清理 | 设备与运行 | 构建与打包 | 环境与版本管理 | 代码管理 | 其它命令 )
  • Worldcoin虹膜识别与AI监控:数字身份与全景控制的技术风险
  • 2026气动截止阀|切断阀|闸阀采购选型:苏正自控单座/三通/高压全覆盖 - 品牌推荐大师
  • 国内塑料改性添加剂厂家参考指南:东莞市硕美电子材料领衔,技术驱动产业升级 - 变量人生001
  • Boss直聘批量投简历工具:基于Tampermonkey的智能求职自动化解决方案
  • 别再为MEIC数据发愁了!用meic2wrf工具生成WRF-CHEM排放文件的保姆级教程
  • 内容营销AI实战:从策略到分发的全流程人机协同指南
  • ncmdump音乐解密:三步解锁网易云音乐NCM格式,实现跨平台播放自由
  • 手撕一个前端全能日志类:位掩码 + 炫彩控制台 + 高性能调用栈
  • 微信立减金回收 闲置数字资产变现的实用小技巧 - 团团收购物卡回收
  • Oracle EBS(E-Business Suite)的资产模块(Oracle Assets)是企业固定资产管理的核心组件
  • 机械革命蛟龙15K在Linux下键盘失灵?别急着刷BIOS,试试这个ACPI DSDT修改法(附详细命令)
  • 西安路虎捷豹维修保养攻略|西安顺进聚宝名车,专修全系车型,老车主都选的靠谱修理厂门店 - 宁夏壹山网络
  • 2025_NIPS_The RefinedWeb Dataset for Falcon LLM: Outperforming Curated Corpora with Web Data Only
  • 炉石佣兵战记自动化脚本:告别重复操作,让游戏回归策略乐趣
  • 如何让Windows字体显示更清晰:MacType终极美化指南
  • 【AVRCP】规范精讲[21]: 从轮询到主动推送,AVRCP通知事件全解析
  • 构建以维基百科为核心的个人知识管理系统:从信息检索到知识内化
  • 拆解大语言模型预训练全流程,看懂AI文字能力的诞生逻辑
  • Python之email包语法、参数和实际应用案例
  • 市面上有哪些是真正无痕改写的降AIGC平台(顺利通过高校AIGC审核) - 降AI小能手
  • 2025_NIPS_ConDaFormer: Disassembled Transformer with Local Structure Enhancement for 3D Point Clo...
  • 企业微信接入WorkBuddy全流程指南