Memcached二三事儿
Memcached绝对称得上是NoSQL老兵!可惜随着时间的推移,Redis等后起之秀羽翼渐丰,Memcached相比之下已呈颓势。那我们还用不用学习它?答案是肯定的!毕竟仍然有很多项目依赖着它,如果忽视它,一旦出了问题就只有干瞪眼的份儿了。 网络上关于Memcached的资
Memcached绝对称得上是NoSQL老兵!可惜随着时间的推移,Redis等后起之秀羽翼渐丰,Memcached相比之下已呈颓势。那我们还用不用学习它?答案是肯定的!毕竟仍然有很多项目依赖着它,如果忽视它,一旦出了问题就只有干瞪眼的份儿了。
网络上关于Memcached的资料可以说是浩如烟海,其中不乏一些精彩之作,比如说由爱好者翻译的「Memcached全面剖析」系列文章,在中文社区广为流传,虽然已经是几年前的文章了,但是即便现在读起来,依然感觉收获良多,推荐大家多看几遍:
- Memcached的基础
- 理解Memcached的内存存储
- Memcached的删除机制和发展方向
- Memcached的分布式算法
- Memcached的应用和兼容程序
当然,官方Wiki永远是最权威的资料,即便是里面的ReleaseNotes也不要放过。
实际应用Memcached时,我们遇到的很多问题都是因为不了解其内存分配机制所致,下面就让我们以此为开端来开始Memcached之旅吧!
为了规避内存碎片问题,Memcached采用了名为SlabAllocator的内存分配机制。内存以Page为单位来分配,每个Page分给一个特定长度的Slab来使用,每个Slab包含若干个特定长度的Chunk。实际保存数据时,会根据数据的大小选择一个最贴切的Slab,并把数据保存在对应的Chunk中。如果某个Slab没有剩余的Chunk了,系统便会给这个Slab分配一个新的Page以供使用,如果没有Page可用,系统就会触发LRU机制,通过删除冷数据来为新数据腾出空间,这里有一点需要注意的是:LRU不是全局的,而是针对Slab而言的。
一个Slab可以有多个Page,这就好比在古代一个男人可以娶多个女人;一旦一个Page被分给某个Slab后,它便对Slab至死不渝,犹如古代那些贞洁的女人。但是女人的数量毕竟是有限的,所以一旦一些男人娶得多了,必然另一些男人就只剩下咽口水的份儿,这在很大程度上增加了社会的不稳定因素,于是乎我们要解放女性。
好在Memcached已经意识到解放女性的重要性,新版本中Page可以调配给其它的Slab:
shell> memcached -o slab_reassign,slab_automove
换句话说:女人可以改嫁了!这方面,其实Memcached的儿子Twemcache革命得更彻底,他甚至写了一篇大字报,以事实为依据,痛斥老子的无能,有兴趣的可以继续阅读:Random Eviciton vs Slab Automove。
了解Memcached内存使用情况的最佳工具是:Memcached-tool。如果我们发现某个Slab的Evicted不为零,则说明这个Slab已经出现了LRU的情况,这通常是个危险的信号,但也不能一概而论,需要结合Evict_Time来做进一步判断。
…
在Memcached的使用过程中,除了会遇到内存分配机制相关的问题,还有很多稀奇古怪的问题等着你呢,下面我选出几个有代表性的问题来逐一说明:
Cache失效后的拥堵问题
通常我们会为两种数据做Cache,一种是热数据,也就是说短时间内有很多人访问的数据;另一种是高成本的数据,也就说查询很很耗时的数据。当这些数据过期的瞬间,如果大量请求同时到达,那么它们会一起请求后端重建Cache,造成拥堵问题,就好象在北京上班做地铁似的,英文称之为:stampeding herd,老外这里的用词还是很形象的。
一般有如下几种解决思路可供选择:
首先,我们可以主动更新Cache。前端程序里不涉及重建Cache的职责,所有相关逻辑都由后端独立的程序(比如CRON脚本)来完成,但此方法并不适应所有的需求。
其次,我们可以通过加锁来解决问题。以PHP为例,伪代码大致如下:
<?php function query() { $data = $cache->get($key); if ($cache->getResultCode() == Memcached::RES_NOTFOUND) { if ($cache->add($lockKey, $lockData, $lockExpiration)) { $data = $db->query(); $cache->set($key, $data, $expiration); $cache->delete($lockKey); } else { sleep($interval); $data = query(); } } return $data; } ?>
不过这里有一个问题,代码里用到了sleep,也就是说客户端会卡住一段时间,就拿PHP来说吧,即便这段时间非常短暂,也有可能堵塞所有的FPM进程,从而使服务中断。于是又有人想出了柔性过期的解决方案,所谓柔性过期,指的是设置一个相对较长的过期时间,或者干脆不再直接设置数据的过期时间,取而代之的是把真正的过期时间嵌入到数据中去,查询时再判断,如果数据过期就加锁重建,如果加锁失败,不再sleep,而是直接返回旧数据,以PHP为例,伪代码大致如下:
<?php function query() { $data = $cache->get($key); if (isset($data['expiration']) && $data['expiration'] add($lockKey, $lockData, $lockExpiration)) { $data = $db->query(); $data['expiration'] = $expiration; $cache->set($key, $data); $cache->delete($lockKey); } } return $data; } ?>
问题到这里似乎已经圆满解决了,且慢!还有一些特殊情况没有考虑到:设想一下服务重启;或者某个Cache里原本没有的冷数据因为某些情况突然转换成热数据;又或者由于LRU机制导致某些键被意外删除,等等,这些情况都可能会让上面的方法失效,因为在这些情况里就不存在所谓的旧数据,等待用户的将是一个空页面。
好在我们还有Gearman这根救命稻草。当需要更新Cache的时候,我们不再直接查询数据库,而是把任务抛给Gearman来处理,当并发量比较大的时候,Gearman内部的优化可以保证相同的请求只查询一次后端数据库,以PHP为例,伪代码大致如下:
<?php function query() { $data = $cache->get($key); if ($cache->getResultCode() == Memcached::RES_NOTFOUND) { $data = $gearman->do($function, $workload, $unique); $cache->set($key, $data, $expiration); } return $data; } ?>
说明:如果多个并发请求的$unique参数一样,那么实际上Gearman只会请求一次。
Multiget的无底洞问题
Facebook在Memcached的实际应用中,发现了Multiget无底洞问题,具体表现为:出于效率的考虑,很多Memcached应用都已Multiget操作为主,随着访问量的增加,系统负载捉襟见肘,遇到此类问题,直觉通常都是通过增加服务器来提升系统性能,但是在实际操作中却发现问题并不简单,新加的服务器好像被扔到了无底洞里一样毫无效果。
为什么会这样?让我们来模拟一下案发经过,看看到底发生了什么:
我们使用Multiget一次性获取100个键对应的数据,系统最初只有一台Memcached服务器,随着访问量的增加,系统负载捉襟见肘,于是我们又增加了一台Memcached服务器,数据散列到两台服务器上,开始那100个键在两台服务器上各有50个,问题就在这里:原本只要访问一台服务器就能获取的数据,现在要访问两台服务器才能获取,服务器加的越多,需要访问的服务器就越多,所以问题不会改善,甚至还会恶化。
不过,作为被告方,Memcached官方开发人员对此进行了辩护:
请求多台服务器并不是问题的症结,真正的原因在于客户端在请求多台服务器时是并行的还是串行的!问题是很多客户端,包括Libmemcached在内,在处理Multiget多服务器请求时,使用的是串行的方式!也就是说,先请求一台服务器,然后等待响应结果,接着请求另一台,结果导致客户端操作时间累加,请求堆积,性能下降。
如何解决这个棘手的问题呢?只要保证Multiget中的键只出现在一台服务器上即可!比如说用户名字(user:foo:name),用户年龄(user:foo:age)等数据在散列到多台服务器上时,不应按照完整的键名(user:foo:name和user:foo:age)来散列的,而应按照特殊的键(foo)来散列的,这样就保证了相关的键只出现在一台服务器上。以PHP的 Memcached客户端为例,有getMultiByKey和setMultiByKey可供使用。
Nagle和DelayedAcknowledgment的延迟问题
老实说,这个问题和Memcached没有半毛钱关系,任何网络应用都有可能会碰到这个问题,但是鉴于很多人在写Memcached程序的时候会遇到这个问题,所以还是拿出来聊一聊,在这之前我们先来看看Nagle和DelayedAcknowledgment的含义:
先看看Nagle:
假如需要频繁的发送一些小包数据,比如说1个字节,以IPv4为例的话,则每个包都要附带40字节的头,也就是说,总计41个字节的数据里,其中只有1个字节是我们需要的数据。为了解决这个问题,出现了Nagle算法。它规定:如果包的大小满足MSS,那么可以立即发送,否则数据会被放到缓冲区,等到已经发送的包被确认了之后才能继续发送。通过这样的规定,可以降低网络里小包的数量,从而提升网络性能。
再看看DelayedAcknowledgment:
假如需要单独确认每一个包的话,那么网络中将会充斥着无数的ACK,从而降低了网络性能。为了解决这个问题,DelayedAcknowledgment规定:不再针对单个包发送ACK,而是一次确认两个包,或者在发送响应数据的同时捎带着发送ACK,又或者触发超时时间后再发送ACK。通过这样的规定,可以降低网络里ACK的数量,从而提升网络性能。
Nagle和DelayedAcknowledgment虽然都是好心,但是它们在一起的时候却会办坏事。下面我们举例说说Nagle和DelayedAcknowledgment是如何产生延迟问题的:
Nagle和DelayedAcknowledgment的延迟问题
客户端需要向服务端传输数据,传输前数据被分为ABCD四个包,其中ABC三个包的大小都是MSS,而D的大小则小于MSS,交互过程如下:
首先,因为客户端的ABC三个包的大小都是MSS,所以它们可以耗无障碍的发送,服务端由于DelayedAcknowledgment的存在,会把AB两个包放在一起来发送ACK,但是却不会单独为C包发送ACK。
接着,因为客户端的D包小于MSS,并且C包尚未被确认,所以D包不会立即发送,而被放到缓冲区里延迟发送。
最后,服务端触发了超时阈值,终于为C包发送了ACK,因为不存在未被确认的包了,所以即便D包小于MSS,也总算熬出头了,可以发送了,服务端在收到了所有的包之后就可以发送响应数据了。
说到这里,假如你认为自己已经理解了这个问题的来龙去脉,那么我们尝试改变一下前提条件:传输前数据被分为ABCDE五个包,其中ABCD四个包的大小都是MSS,而E的大小则小于MSS。换句话说,满足MSS的完整包的个数是偶数个,而不是前面所说的奇数个,此时又会出现什么情况呢?答案我就不说了,留给大家自己思考。
知道了问题的原委,解决起来就简单了:我们只要设置socket选项为TCP_NODELAY即可,这样就可以禁用Nagle,以PHP为例:
<?php $memcached->setOption(Memcached::OPT_TCP_NODELAY, true); ?>
如果大家意犹未尽,可以继续浏览:TCP Performance problems caused by interaction between Nagle’s Algorithm and Delayed ACK。
…
希望本文能让大家在使用Memcached的过程中少走一些弯路。相对于Memcached,其实我更喜欢Redis,从功能上看,Redis可以说是Memcached的超集,不过Memcached自有它存在的价值,即便已呈颓势,但是:老兵永远不死,只是慢慢凋零。
原文地址:Memcached二三事儿, 感谢原作者分享。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Memcached는 웹 애플리케이션의 성능을 크게 향상시킬 수 있는 일반적으로 사용되는 캐싱 기술입니다. PHP에서 일반적으로 사용되는 세션 처리 방법은 세션 파일을 서버의 하드 디스크에 저장하는 것입니다. 그러나 이 방법은 서버의 하드 디스크가 성능 병목 현상 중 하나가 되기 때문에 최적이 아닙니다. Memcached 캐싱 기술을 사용하면 PHP에서 세션 처리를 최적화하고 웹 애플리케이션의 성능을 향상시킬 수 있습니다. PHP 세션

PHP8.0의 캐싱 라이브러리: Memcached 인터넷의 급속한 발전으로 인해 최신 애플리케이션에는 성능을 향상하고 대용량 데이터를 처리하기 위해 효율적이고 안정적인 캐싱 기술이 필요합니다. PHP의 인기와 오픈 소스 특성으로 인해 PHP 캐싱 라이브러리는 웹 개발 커뮤니티에서 필수적인 도구가 되었습니다. Memcached는 수백만 개의 동시 연결된 캐시 요청을 처리할 수 있고 소셜 네트워크, 온라인 등 다양한 유형의 애플리케이션에서 사용할 수 있는 널리 사용되는 오픈 소스 고속 메모리 캐싱 시스템입니다.

인터넷이 발전하면서 PHP 애플리케이션은 인터넷 애플리케이션 분야에서 점점 더 보편화되었습니다. 그러나 PHP 애플리케이션의 동시 액세스가 높으면 서버의 CPU 사용량이 높아져 애플리케이션 성능에 영향을 줄 수 있습니다. PHP 애플리케이션의 성능을 최적화하기 위해서는 Memcached 캐싱 기술이 좋은 선택이 되었습니다. 이 기사에서는 Memcached 캐싱 기술을 사용하여 PHP 애플리케이션의 CPU 사용량을 최적화하는 방법을 소개합니다. Memcached 캐싱 기술 소개 Memcached는

인터넷 기술의 지속적인 발전으로 오디오 및 비디오 리소스는 인터넷상의 매우 중요한 콘텐츠 형태가 되었으며, 네트워크 개발에서 가장 널리 사용되는 언어 중 하나인 PHP는 비디오 분야에서도 지속적으로 사용되고 있습니다. 그리고 오디오 재생. 그러나 오디오 및 비디오 웹사이트의 사용자 수가 증가함에 따라 많은 웹사이트에서 문제를 발견했습니다. 높은 동시성 조건에서 PHP의 오디오 및 비디오 처리 속도가 크게 느려져 제 시간에 재생할 수 없거나 재생이 중단되는 등의 문제가 발생합니다. . 이 문제를 해결하려면 Memcached 캐싱 기술이 필요합니다.

인터넷의 급속한 발전으로 인해 대규모 MySQL 데이터베이스 백업 및 복구는 주요 기업과 웹사이트에 필요한 기술 중 하나가 되었습니다. Memcached가 널리 적용되면서 Memcached를 백업하고 복원하는 방법도 중요한 문제가 되었습니다. 웹 개발의 주요 언어 중 하나인 PHP는 MySQL 및 Memcached의 백업 및 복구를 처리하는 데 있어 고유한 장점과 기술을 가지고 있습니다. 이 기사에서는 PHP에서 MySQL을 처리하고 Memcached 백업 및 복구를 수행하는 방법을 자세히 소개합니다.

네트워크 애플리케이션의 지속적인 증가와 데이터 볼륨의 지속적인 확장으로 인해 데이터 읽기 및 쓰기 효율성은 애플리케이션 성능에 영향을 미치는 중요한 요소 중 하나가 되었습니다. 캐싱 기술을 적용하면 이 문제를 잘 해결할 수 있습니다. PHP 애플리케이션에서 Memcached는 가장 일반적으로 사용되는 캐시 서버입니다. Memcached는 일반적으로 사용되는 데이터를 메모리에 저장하고 데이터 검색 효율성을 향상시킬 수 있는 고성능 분산 메모리 개체 캐싱 시스템입니다. 이 기사에서는 캐시 관리를 위해 PHP와 Memcached를 사용하는 방법과 최적화 방법을 소개합니다.

현대 인터넷 애플리케이션의 급속한 발전으로 인해 사용자 경험은 애플리케이션의 성공에 매우 중요합니다. 애플리케이션의 고성능 및 고가용성을 보장하는 방법은 개발자가 해결해야 하는 중요한 문제 중 하나가 되었습니다. 널리 사용되는 프로그래밍 언어 중 하나인 PHP의 성능 모니터링 및 최적화도 매우 중요합니다. Memcached는 애플리케이션의 성능과 확장성을 향상시키는 데 도움이 되는 고성능 분산 메모리 개체 캐싱 시스템입니다. 이 기사에서는 PHP와 Memcached를 사용하여 성능 모니터링을 구현하는 방법을 소개합니다.

인터넷이 발전하면서 캐싱 기술은 웹 개발에서 점점 더 중요한 역할을 하고 있습니다. 널리 사용되는 캐시 서버인 Redis와 Memcached는 다양한 웹 애플리케이션 개발에 널리 사용됩니다. 그러나 Linux 시스템에 익숙하지 않은 개발자의 경우 이러한 캐시 서버를 설치하고 구성하면 문제가 발생할 수 있습니다. 그러나 Pagoda Panel을 사용하면 이 프로세스가 매우 간단해집니다. 1. 파고다 패널이란 무엇입니까? Pagoda 패널은 Linux 서버 관리 패널입니다.
