手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表Tag:缓存

例行维护后引起的故障和桔子的缓存故障

最近javaeye发生一起小故障,是robbin自己说的:

XML/HTML代码
  1. @robbinfan: 昨晚JE所在机房切换电源关机导致网站无法访问。早上恢复后因为数据库和缓存服务器都被清空,巨大流量(QPS将近400,并发连接到1000)直接冲击导致web服务被阻塞,现在正在逐步恢复中。

在mikespook.com看到对待这个问题的分析时,突然想起桔子也遇到过类似的问题,所以把他们两个人的事情贴出来。

先上mikespook的:

XML/HTML代码
  1. 显然,这是一次运维事故。事故的原因是分流作用的数据库和缓存出现“故障”,导致数据层响应延迟,web 服务器阻塞。这里我没有用“清空”而是用了“故障”来描述分流数据库和缓存,是因为实质上 javaeye 的这次事故虽然是正常维护(电源切换)后发生的,但是其表象跟分流数据库和缓存宕机是一样的。  
  2.   
  3. 这个故事给我的两个启示:  
  4.   
  5. 在架构设计上,对于分流数据库或者缓存或许应有一定的持久化能力。比如,在维护时,按照从“外”到“内”的顺序逐步关闭服务。在这个例子里,“外” 就是 web服务,“内”就是数据层。在关闭了“外”服务后,手工或自动将缓存持久化。维护完成,开启顺序从“内”到“外”,并在回复完底层存储后,将持久化数据恢复到缓存。  
  6.   
  7. 在运维规范上,在维护后应让系统进入一个的磨合期,在合理的时间内通过分流(比如跳转到一个“系统忙”的页面)或者防火墙封锁的方式。让系统保持在比正常负载低一些的水平。持续一段时间(或者维护后累计访问量达到某个值)后再让系统开足马力去运行。  
  8.   
  9. 这样,应该可以避免空缓存大并发导致的宕机事故。  
  10.   
  11. 再次感谢 robbin 和 javaeye 为我们带来的启示。  

再上桔子的,汗,突然发现桔子的博客上居然没有写,看来是上次在群里看到了,大意如下:

XML/HTML代码
  1. 某次更新系统,然后需要重启,结果重启后CPU长时间处于100%(?还是死机了?),后来检查发现,原来故障是出在缓存上。  
  2. 因为是采用文件缓存,而又设定了过期时间,重启后,所有的缓存都过期了。然后网站访问量又大,突然而来的访问导致缓存重新生成,差点让机器出故障。  
  3. 所以现在开始要调整缓存架构。  
其实上面两个问题都差不多。都是在访问大的时候,缓存频繁生成造成的故障,这确实不容忽略,但如何解决真的是一个问题。很多时候在访问量不大时,我们都考虑使用文件来作为缓存存储。但真正访问量高了后,文件缓存不可避免的就带来IO的消耗,如何批量生成缓存?还是按次生成缓存?还是定有一定的策略?难道还要采用队列?那就夸张了。

所以,一个好的系统架构也是很需要的,不能因为一次宕机就永远起不来。我个人是偏向于队列生成缓存,这样就不用担心一次写入过多文件引起IO的崩溃。但队列是因为有延迟的,如果控制同样的内容不重复生成文件缓存,则需要另外考虑

Tags: 故障, 缓存, 重启, 维护

php优化:apc缓存

APC其实是PHP5自带的东西,只需要把xxx.dll前的注释去掉就可以用了,不象其他的加速 ,还需要装软件,什么xCache啦,eacceraltor之类的,都需要额外编译好之后放到扩展目录下才行(当然我说的是windows下面的,linux下面就不太一样了)

既然是自带的,又这么好,总要有个介绍的吧?

原文:http://blog.goguoguo.com/html/y2009/311.html

作者:土 豆

先说说php程序的执行流程吧,说明了这个,才好开始我们的优化之旅。

客户端(譬如浏览器)
—》请求Get hello.php
—-》cgi服务器接(譬如apache)收到请求,根据配置寻找php的处理程序(譬如mod_php)
—-》apache加载php的处理程序,php的处理程序读取php.ini初始化php的解释环境
—-》mod_php定位寻找hell.php,将其载入到内存中来
—-》mod_php编译源代码成为opcode树
—-》mod_php执行opcode
—-》生成结果给浏览器

在这个过程中我们有哪些地方可以优化呢:
1 将mod_php fast-cgi化,避免每次都要加载这个模块,这个模块还要每次都去初始化php的解释环境
2 缓存php文件的opcode码,这样话,避免每次都去编译。

缓存opcode码有很多软件,apc、以及zend提供的cache等。
转载一个apc的配置和使用:

Alternative PHP Cache(APC)是 PHP 的一个免费公开的优化代码缓存。它用来提供免费,公开并且强健的架构来缓存和优化 PHP 的中间代码。

在 Windows 下,APC 要求有 c:\tmp 目录,并且该目录要对 Web 服务器进程可写。

1. 安装:

以PHP extension 形式安装.

2. 配置
apc.enabled boolean
apc.optimization optimization
选项在脚本中可以改变

APC PHP.ini配置选项详解

[APC]
; Alternative PHP Cache 用于缓存和优化PHP中间代码

apc.cache_by_default = On
;SYS
; 是否默认对所有文件启用缓冲。
; 若设为Off并与以加号开头的apc.filters指令一起用,则文件仅在匹配过滤器时才被缓存。

apc.enable_cli = Off
;SYS
; 是否为CLI版本启用APC功能,仅用于测试和调试目的才打开此指令。

apc.enabled = On
; 是否启用APC,如果APC被静态编译进PHP又想禁用它,这是唯一的办法。

apc.file_update_protection = 2
;SYS
; 当你在一个运行中的服务器上修改文件时,你应当执行原子操作。
; 也就是先写进一个临时文件,然后将该文件重命名(mv)到最终的名字。
; 文本编辑器以及 cp, tar 等程序却并不是这样操作的,从而导致有可能缓冲了残缺的文件。
; 默认值 2 表示在访问文件时如果发现修改时间距离访问时间小于 2 秒则不做缓冲。
; 那个不幸的访问者可能得到残缺的内容,但是这种坏影响却不会通过缓存扩大化。
; 如果你能确保所有的更新操作都是原子操作,那么可以用 0 关闭此特性。
; 如果你的系统由于大量的IO操作导致更新缓慢,你就需要增大此值。

apc.filters =
;SYS
; 一个以逗号分隔的POSIX扩展正则表达式列表。
; 如果源文件名与任意一个模式匹配,则该文件不被缓存。
; 注意,用来匹配的文件名是传递给include/require的文件名,而不是绝对路径。
; 如果正则表达式的第一个字符是”+”则意味着任何匹配表达式的文件会被缓存,
; 如果第一个字符是”-”则任何匹配项都不会被缓存。”-”是默认值,可以省略掉。

apc.ttl = 0
;SYS
; 缓存条目在缓冲区中允许逗留的秒数。0 表示永不超时。建议值为7200~36000。
; 设为 0 意味着缓冲区有可能被旧的缓存条目填满,从而导致无法缓存新条目。

apc.user_ttl = 0
;SYS
; 类似于apc.ttl,只是针对每个用户而言,建议值为7200~36000。
; 设为 0 意味着缓冲区有可能被旧的缓存条目填满,从而导致无法缓存新条目。

apc.gc_ttl = 3600
;SYS
; 缓存条目在垃圾回收表中能够存在的秒数。
; 此值提供了一个安全措施,即使一个服务器进程在执行缓存的源文件时崩溃,
; 而且该源文件已经被修改,为旧版本分配的内存也不会被回收,直到达到此TTL值为止。
; 设为零将禁用此特性。

apc.include_once_override = Off
;SYS
; 关于该指令目前尚无说明文档,参见:http://pecl.php.net/bugs/bug.php?id=8754
; 请保持为Off,否则可能导致意想不到的结果。

apc.max_file_size = 1M
;SYS
; 禁止大于此尺寸的文件被缓存。

apc.mmap_file_mask =
;SYS
; 如果使用–enable-mmap(默认启用)为APC编译了MMAP支持,
; 这里的值就是传递给mmap模块的mktemp风格的文件掩码(建议值为”/tmp/apc.XXXXXX”)。
; 该掩码用于决定内存映射区域是否要被file-backed或者shared memory backed。
; 对于直接的file-backed内存映射,要设置成”/tmp/apc.XXXXXX”的样子(恰好6个X)。
; 要使用POSIX风格的shm_open/mmap就需要设置成”/apc.shm.XXXXXX”的样子。
; 你还可以设为”/dev/zero”来为匿名映射的内存使用内核的”/dev/zero”接口。
; 不定义此指令则表示强制使用匿名映射。

apc.num_files_hint = 1000
;SYS
; Web服务器上可能被包含或被请求的不同源文件的大致数量(建议值为1024~4096)。
; 如果你不能确定,则设为 0 ;此设定主要用于拥有数千个源文件的站点。

apc.optimization = 0
; 优化级别(建议值为 0 ) 。
; 正整数值表示启用优化器,值越高则使用越激进的优化。
; 更高的值可能有非常有限的速度提升,但目前尚在试验中。

apc.report_autofilter = Off
;SYS
; 是否记录所有由于early/late binding原因而自动未被缓存的脚本。

apc.shm_segments = 1
;SYS
; 为编译器缓冲区分配的共享内存块数量(建议值为1)。
; 如果APC耗尽了共享内存,并且已将apc.shm_size指令设为系统允许的最大值,
; 你可以尝试增大此值。

apc.shm_size = 30
;SYS
; 每个共享内存块的大小(以MB为单位,建议值为128~256)。
; 有些系统(包括大多数BSD变种)默认的共享内存块大小非常少。

apc.slam_defense = 0
;SYS(反对使用该指令,建议该用apc.write_lock指令)
; 在非常繁忙的服务器上,无论是启动服务还是修改文件,
; 都可能由于多个进程企图同时缓存一个文件而导致竞争条件。
; 这个指令用于设置进程在处理未被缓存的文件时跳过缓存步骤的百分率。
; 比如设为75表示在遇到未被缓存的文件时有75%的概率不进行缓存,从而减少碰撞几率。
; 鼓励设为 0 来禁用这个特性。

apc.stat = On
;SYS
; 是否启用脚本更新检查。
; 改变这个指令值要非常小心。
; 默认值 On 表示APC在每次请求脚本时都检查脚本是否被更新,
; 如果被更新则自动重新编译和缓存编译后的内容。但这样做对性能有不利影响。
; 如果设为 Off 则表示不进行检查,从而使性能得到大幅提高。
; 但是为了使更新的内容生效,你必须重启Web服务器。
; 这个指令对于include/require的文件同样有效。但是需要注意的是,
; 如果你使用的是相对路径,APC就必须在每一次include/require时都进行检查以定位文件。
; 而使用绝对路径则可以跳过检查,所以鼓励你使用绝对路径进行include/require操作。

apc.user_entries_hint = 100
;SYS
; 类似于num_files_hint指令,只是针对每个不同用户而言。
; 如果你不能确定,则设为 0 。

apc.write_lock = On
;SYS
; 是否启用写入锁。
; 在非常繁忙的服务器上,无论是启动服务还是修改文件,
; 都可能由于多个进程企图同时缓存一个文件而导致竞争条件。
; 启用该指令可以避免竞争条件的出现。

apc.rfc1867 = Off
;SYS
; 打开该指令后,对于每个恰好在file字段之前含有APC_UPLOAD_PROGRESS字段的上传文件,
; APC都将自动创建一个upload_的用户缓存条目(就是APC_UPLOAD_PROGRESS字段值)。

3. 函数:

apc_cache_info - Retrieves cached information (and meta-data) from APC’s data store
apc_clear_cache - Clears the APC cache
apc_define_constants - Defines a set of constants for later retrieval and mass-definition
apc_delete - Removes a stored variable from the cache
apc_fetch - Fetch a stored variable from the cache
apc_load_constants - Loads a set of constants from the cache
apc_sma_info - Retrieves APC’s Shared Memory Allocation information
apc_store - Cache a variable in the data store

apc的用法比较简单,只有几个函数,列举如下。
apc_cache_info () 返回缓存信息
apc_clear_cache() 清除apc缓存内容。
默认(无参数)时,只清除系统缓存,要清除用户缓存,需用‚user‘参数。
apc_define_constants ( string key, array constants [, bool case_sensitive] ) 将数组constants以常量加入缓存。
apc_load_constants (string Key)。
取出常量缓存。
apc_store ( string key, mixed var [, int ttl] )。
在缓存中保存数据。
apc_fetch ( string key )。
获得apc_store保存的缓存内容
apc_delete ( string key )。
删除apc_store保存的内容。

apc的管理:
到pecl.php.net下载apc源码包有个apc.php,copy到你的web server可以访问到的地方,浏览即可访问。
管理界面功能有:
1. Refresh Data
2. View Host Stats
3. System Cache Entries
4. User Cache Entries
5. Version Check
apc


配置php.ini的时候一定要跟进编译选项来放置这些扩展的位置。
默认apc.so要放到php.ini同一个目录下,而不是传说中的extension目录。

Tags: 缓存, 优化

学做jQuery中的data()函数

看到这个内容的时候,很吃惊,其实我在以前看到过一个R开头的网站时(记不清了,实在记不清了),他用JS做了一个cache函数,对函数做了缓存。还用了斐伯拉切函数做了测试。后来我根据他写的代码用jQuery写了一个类似的插件(它是把方法注册到了window对象里,所以加快了一些速度)。后来感觉这样的方法也同样可以用在数据上,又根据这样的想法写了一个存储数据的cache函数。也分别用在了两个不同的项目里。

如今又看到有人写这样类似的东西,就把他贴上来进行分享。

文章的内容来自:

原文如下:http://www.cssrain.cn/article.asp?id=1295

在jQuery中可以使用data()来给元素存储临时的变量:
// jQuery:
    // Set data:
    $(elem).data('customProperty', 12345);
    // Get data:
    $(elem).data('customProperty');

在mootools中可以使用store()来给元素存储临时的变量:
// MooTools:
    // Set data:
    elem.store('customProperty', 12345);
    // Get data:
    elem.retrieve('customProperty');


下面我们用JavaScript 自己动手写一个:
(function(){

    var cache = [0],
          expando = 'data' + +new Date();

    function data(elem) {

        var cacheIndex = elem[expando],
            nextCacheIndex = cache.length;

        if(!cacheIndex) {
            cacheIndex = elem[expando] = nextCacheIndex;
            cache[cacheIndex] = {};
        }

        return cache[cacheIndex];

    }

    window.data = data;

})();

使用:
var myElem = document.getElementById('id');
// 设置data:
data(myElem).customProperty = 12345;
// 获取 data:
data(myElem).customProperty; // returns 12345

//  用其他的变量
data(myElem).info = {
    a : 123,
    b : [4,5,6]
};


这个脚本其实很简单,就是往cache 数组里添加 下标 元素。
默认cache=[0] ,当 elem[expando] 没有获取到时,则往数组里 添加一个下标,同时下标又与数组是关联起来的。
如果elem[expando]获取到时,则直接返回  cache[cacheIndex] 。


这点搞定后,那就简单了,就是往一个空对象中 配置 属性了。



进一步修改函数:
// WITH ENCAPSULATION:
(function(){

    var cache = [0],
        expando = 'data' + +new Date();

    function data(elem) {

        var cacheIndex = elem[expando],
            nextCacheIndex = cache.length;

        if(!cacheIndex) {
            cacheIndex = elem[expando] = nextCacheIndex;
            cache[cacheIndex] = {};
        }

        return {
            get : function(key) {
                return cache[cacheIndex][key];
            },
            set : function(key, val) {
                cache[cacheIndex][key] = val;
                return val;
            }
        }

    }

    window.data = data;

})();

用法:
var myElem = document.getElementById('id');

// 设置data:
data(myElem).set('customProperty', 12345);

// 获取data:
data(myElem).get('customProperty'); // returns 12345


ok,一个类似jQuery的data()函数就完成了。


其实我自己还是觉得用对象更好处理一些,一来,对象不象数组,一定要用下标才能读取,而且对于对象的覆盖等,也方便很多。删除的话也容易。

Tags: data, cache, 缓存