Submitted by admin on 2011, July 5, 10:21 PM
一个功能比较完整的keepalived的配置文件,其配置文件keepalived.conf可以包含三个文本块:全局定义块、VRRP实例定义块及虚拟服务器定义块。全局定义块和虚拟服务器定义块是必须的,如果在只有一个负载均衡器的场合,就不须VRRP实例定义块。
接下来,我们以一个配置文件模版为例,有选择的说明其中一些重要项的功能或作用。
● 全局定义块
1、 email通知。作用:有故障,发邮件报警。这是可选项目,建议不用,用nagios全面监控代替之。
2、 Lvs负载均衡器标识(lvs_id)。在一个网络内,它应该是唯一的。
3、 花括号“{}”。用来分隔定义块,因此必须成对出现。如果写漏了,keepalived运行时,不会得到预期的结果。由于定义块内存在嵌套关系,因此很容易遗漏结尾处的花括号,这点要特别注意。
● VRRP定义块
1、 同步vrrp组vrrp_sync_group。作用:确定失败切换(FailOver)包含的路由实例个数。即在有2个负载均衡器的场景,一旦某个负载均衡器失效,需要自动切换到另外一个负载均衡器的实例是哪些?
2、 实例组group.至少包含一个vrrp实例。
3、 Vrrp实例vrrp_instance.实例名出自实例组group所包含的那些名字。
(1) 实例状态state.只有MASTER和BACKUP两种状态,并且需要大写这些单词。其中MASTER为工作状态,BACKUP为备用状态。当MASTER所在的服务器失效时,BACKUP所在的系统会自动把它的状态有BACKUP变换成MASTER;当失效的MASTER所在的系统恢复时,BACKUP从MASTER恢复到BACKUP状态。
(2) 通信接口interface。对外提供服务的网络接口,如eth0,eth1.当前主流的服务器都有2个或2个以上的接口,在选择服务接口时,一定要核实清楚。
(3) lvs_sync_daemon_inteface。负载均衡器之间的监控接口,类似于HA HeartBeat的心跳线。但它的机制优于Heartbeat,因为它没有“裂脑”这个问题,它是以优先级这个机制来规避这个麻烦的。在DR模式中,lvs_sync_daemon_inteface 与服务接口interface 使用同一个网络接口。
(4) 虚拟路由标识virtual_router_id.这个标识是一个数字,并且同一个vrrp实例使用唯一的标识。即同一个vrrp_stance,MASTER和BACKUP的virtual_router_id是一致的,同时在整个vrrp内是唯一的。
(5) 优先级priority.这是一个数字,数值愈大,优先级越高。在同一个vrrp_instance里,MASTER 的优先级高于BACKUP。若MASTER的priority值为150,那么BACKUP的priority只能是140或更小的数值。
(6) 同步通知间隔 advert_int .MASTER与BACKUP负载均衡器之间同步检查的时间间隔,单位为秒。
(7) 验证authentication。包含验证类型和验证密码。类型主要有PASS、AH两种,通常使用的类型为PASS,据说AH使用时有问题。验证密码为明文,同一vrrp实例MASTER与BACKUP 使用相同的密码才能正常通信。
4、 虚拟ip地址virtual_ipaddress . 可以有多个地址,每个地址占一行,不需要指定子网掩码。注意:这个ip必须与我们在lvs客户端设定的vip相一致!
● 虚拟服务器virtual_server定义块
虚拟服务器定义是keepalived框架最重要的项目了,是keepalived.conf必不可少的部分。
1、 虚拟服务器virtual_server. 这个ip来自于vrrp定义块的第“4”步,后面一个空格,然后加上端口号。定义一个vip,可以实现多个tcp端口的负载均衡功能。
(1) delay_loop。健康检查时间间隔,单位是秒。
(2) lb_algo. 负载均衡调度算法,互联网应用常使用wlc或rr。
(3) lb_kind. 负载均衡转发规则。一般包括DR,NAT,TUN3种,在我的方案中,都使用DR的方式。
(4) persistence_timeout.会话保持时间,单位是秒。这个选项对动态网站很有用处:当用户从远程用帐号进行登陆网站时,有了这个会话保持功能,就能把用户的请求转发给同一个应用服务器。在这里,我们来做一个假设,假定现在有一个lvs 环境,使用DR转发模式,真实服务器有3个,负载均衡器不启用会话保持功能。当用户第一次访问的时候,他的访问请求被负载均衡器转给某个真实服务器,这样他看到一个登陆页面,第一次访问完毕;接着他在登陆框填写用户名和密码,然后提交;这时候,问题就可能出现了—登陆不能成功。因为没有会话保持,负载均衡器可能会把第2次的请求转发到其他的服务器。
(5) 转发协议protocol.一般有tcp和udp两种。实话说,我还没尝试过udp协议类的转发。
2、 真实服务器real_server.也即服务器池。Real_server的值包括ip地址和端口号。多个连续的真实ip,转发的端口相同,是不是可以以范围表示?需要进一步实验。如写成real_server 61.135.20.1-10 80 .
(1) 权重weight.权重值是一个数字,数值越大,权重越高。使用不同的权重值的目的在于为不同性能的机器分配不同的负载,性能较好的机器,负载分担大些;反之,性能差的机器,则分担较少的负载,这样就可以合理的利用不同性能的机器资源。
(2) Tcp检查 tcp_check.
集群/分流 | 评论:0
| Trackbacks:0
| 阅读:1182
Submitted by admin on 2011, July 4, 8:13 PM
TCP_IMS_HIT:NONE 客户端发送确认请求,Squid发现更近来的、新鲜的请求资源的拷贝。
Squid发送更新的内容到客户端,而不联系原始服务器。(这指明Squid对本次请求,不会与任何其他服务器(邻居或原始服务器)通信。)
TCP_MEM_HIT:NONE 类似 TCP_IMS_HIT:NONE, 从内存中响应
TCP_REFRESH_HIT:FIRST_UP_PARENT/d
Squid发现请求资源的貌似陈旧的拷贝,并发送确认请求到原始服务器。
原始服务器返回304(未修改)响应,指示squid的拷贝仍旧是新鲜的。或者是重新更新文件。(Squid直接转发请求到原始服务器)
#######2011-03-22 http206 test###
refresh_pattern -i \.exe 60 80% 1440 ignore-reload
maximum_object_size 60 MB
range_offset_limit -1
#################################
range_offset_limit这个参数,主要是对各种流媒体和要断点续传的文件的缓存的。 默认是 是
range_offset_limit 0
squidclient -t 1 -h 127.0.0.1 -p 80 mgr:info
/usr/local/squid/bin/squidclient -p80 -m PURGE URL
squid/缓存 | 评论:0
| Trackbacks:0
| 阅读:1275
Submitted by admin on 2011, July 4, 2:06 PM
首先要明确一下,squid 能够用来作什么。很多人没有搞明白 squid 的工作原理,只是听说 squid 性能不错可以用来给网站提速,就直接在自己的 website 前面套了一个 squid ,这基本没有任何用处,即使你都是静态页面,后面apache上面没有开 mod_expires,一样缓存不了,squid只能起到一个连接管理的用处。
一般说来,网站用 squid 加速,目的有二种
1: squid 本身具有缓存功能,可以将webserver输出的内容缓存起来,在缓存没有过期之前来的访问,都直接用缓存里面的内容,这样可以有效减少 webserver 机器上面的请求数量。这是 squid 的主要功用。
2: 网络慢的用户会长时间占用 webserver 的 TCP 连接,webserver 对每个连接占用的资源比较大,如果长时间不能释放出来服务其他请求,性能会有比较大的影响。前面放一个 squid, webserver 就可以迅速处理完逻辑以后,把数据快速发送给 squid, 然后去处理别的逻辑,而 squid 每个 TCP 连接占用的资源很少,不用担心占用太多资源。这个用途也叫做连接管理,有一些网络设备也可以做这个事情,价格都很贵。
下面针对 squid 的两种功用,来讲述如何调整业务逻辑和 squid 参数
预操作
在搞 squid 之前,不管你用什么编译配置,需要什么特殊选项,都请 –enable-snmp ,并配置好 mrtg 之类,可以图形化的显示 squid 状态,例如 Request Hit Ratio(RHR), Byte Hit Ratio(BHR), 等等,反馈是做一切事情的基础,优化也不例外。
缓存
A: 使用 Expires header 来控制缓存
squid在缓存webserver内容的时候,需要后端webserver输出一些控制信息告诉他页面是不是可以被缓存,以及可以缓存多久。否则 squid 是不会自作主张给你缓存内容的。一个页面到底能不能缓存,只有开发网站的人才知道,因此开发人员有责任在动态页面里面输出 Expires 和 Cache-Control header。简单举一个 php 的例子以说明这两个 header 的值是什么含义,其中$expiretime 的单位是秒。
header(”Expires: ” . gmt_date_format(time()+$expiretime));
header(”Cache-Control: max-age=” . “$expiretime”);
对于静态文件,有两种方式来让 squid 自动给静态文件缓存,一种是使用 apache 的 mod_expires ,可以针对路径或者针对文件类型/扩展名来自动输出 cache 头。详细的请参考 mod_expires 的说明 。另一种是用 squid 的 refresh_pattern 来指定。详细的还是请参考 squid 的配置文件。一般来说,如果后端不是配置很麻烦,建议还是在后端做,前端的配置修改大多数都是违背http协议的,如果出现问题,也比较难排查。
B 根据 squid 访问的模式,进行业务拆分
进行了 Expires Header 的处理以后,squid 就真正可以起到加速的作用了,你可能也能感觉到,网站的访问速度明显加快。但是不要满足于这点成绩,查看 squid 的 snmp 统计图,通常 hit ratio 并不会太高,有 50% 就了不起了。这就是我们需要进一步优化的,我们的目标是让大部分 squid 都达到 9X% 的命中率。
为什么 squid 命中这么低呢,这大概有两种原因。大多数的网站都是有一些页面不能够被缓存的,例如登录页面。这些页面请求也从 squid 走,成为分母的一部分,直接就降低了命中率,我们首先可以做的事情是,把这些不能够缓存的页面请求,拆分到单独一个 squid 上面,或者访问量不大的话,干脆把 apache 暴露出来。这样能够缓存的那个 squid 命中率马上上升一截。
有人可能会说,把不能缓存的页面分拆开去,就光为了让能缓存的那个数字好看,这不是掩耳盗铃么?其实这么做是有意义的,首先就是去掉了不能缓存页面 的干 扰,使得我们进一步优化 squid 的依据更加准确。其次是不可缓存请求和可缓存请求之间的重要性通常是有差距的,分拆了以后,它们之间不容易互相抢占资源,不会因为下载图片的连接太多把 squid 占满,影响更重要的登录请求。第三就是可缓存内容通常是图片等页面元素, 浏览器在 load 它们的时候,对每个站点的并发连接会有控制,如果分开成不同的IP,可以多一些请求同时执行。提高少许显示速度。
其实观察 sohu, sina 之类的页面,你会发现它们的页面也是分拆的,可以看到页面里面的图片都是指向 images.sohu.com 之类的地址,虽然它们可能和其他页面一样后台都指向同一个 apache。
这样做完,缓存命中率大概能上升到 70%-80% 了,运气好的时候完全可以上 90%。
另一种导致 squid 命中低的原因和这个比较类似,同样都是可缓存的内容,有的可能是软件下载站上面的大文件,有的是新闻站点上面的小图片,如果同一个 squid 对这样差别巨大的文件加速的话,会严重干扰 squid 的缓存策略,两者不能兼顾,要不就是大文件占据了 cache ,把小文件都挤出了 cache, 要不就是小文件特别多,大文件无法进入 cache, 导致大文件经常 miss 。这个比不能缓存的页面还要恶心,因此即使在服务器资源有限的情况下,也要优先拆分这两类型访问。一般来说,文件大小分界线定在 1M 左右就可以了,如果是有软件下载这样特别大的文件,可以在 4M – 10M 左右再拆分一次。对于不同访问类型的 squid, 其系统优化参数也会有所不同,这个我们后面还会讲到。
只要悉心按照访问模式来拆分业务,大部分起缓存作用的 squid 都可以达到很高的命中率,至少都可以到达 9X%。
C 根据不同的需求,调整参数优化缓存
完成 A 和 B 两步优化以后, squid 的命中率经常可以达到 9x%, 可以说我们已经给 squid 创造了非常优秀的外部环境,下面我们就要从 squid 本身入手,通过调整它的缓存参数和缓存策略,甚至系统的参数,来让 squid 发挥出更好的性能。
在 B 步骤中,我们把 squid 划分成了三种用途,缓存大文件,缓存小文件,不缓存文件,这其中最后一种用途情况下面 squid 不起到缓存效果,只用来做连接管理,因此我们把它放到后面的连接管理里面叙述,这里只讨论和缓存相关的 squid 参数。
squid 有内存缓存和磁盘缓存两级缓存, 通常来说, 只要是专门给 squid 用的机器, 内存缓存都建议开得比较大, 大内存缓存总是有好处的嘛, 但是注意不要使得系统开始吃 swap ,像Linux这样一开始吃 swap 性能就下降比较严重的系统尤其要注意. 这个程度需要自己试验确定.
通常 1G 内存的Linux机器用来跑 squid ,内存缓存可以开到 512M.
有些libc比较差的平台, 例如比较老的 freebsd 系统, 其 malloc 函数的质量不高,可能会造成比较多的内存碎片,导致 squid 运行一段时间以后分配不出来内存挂掉. 这时候推荐在编译时候使用 dlmalloc package. 即使如此, 仍然要再缩小 squid 的内存缓存,以防不幸发生.
磁盘缓存的情况比较复杂, squid 有 ufs, aufs, coss, diskd, null 五种存储后端, 其中 ufs, aufs, diskd 都是在文件系统上面保存很多小文件, coss 是 squid 自己实现了一个简单的文件系统,可以使用一个大文件或者一个磁盘设备来存储. null 则是给不想要磁盘缓存的情况准备的. coss 看起来好像比较拽, 但是以前试验并不足够稳定,因此并不推荐使用. 剩下的三种存储方式,具体选择哪种需要根据操作系统的特性来进行.
ufs 是最传统的存储方式, 我们知道, squid 是一个单进程的程序, 它使用 ufs 存储后端时, 直接在进程里面读写文件. 这是一种很简单的方式, 缺点是当读写磁盘被阻塞的时候, squid 不能够处理请求, 会造成服务质量波动比较大. 因此出现了 aufs 和 diskd 两种存储后端, 原理都是 squid 主服务循环不负责读写文件, 而是通过消息队列或者tcp/pipe连接将数据传送给其他的线程(aufs)/进程(diskd), 然后其他线程/进程进行读写. 很显然,这两种存储方式有一定的通信开销, 因此不一定就比 ufs 好, 需要具体问题具体分析
前面说到, ufs/aufs/diskd都是在文件系统上面存储很多小文件,因此文件系统本身的特性严重影响了squid缓存的性能,对于 Linux ,强烈推荐用 reiserfs 等适合处理小文件的文件系统, bsd 则至少要打开 softupdate, 以及 dirhash 等一切对很多小文件有好处的选项. 在比较新的系统上面, reiserfs 等文件系统的性能已经足够优越, 通常 ufs 就已经可以应付需要. 对于一些老系统,使用 aufs 或者 diskd 是比较好的选择,如果系统的线程库比较好(如Linux,Solaris),那么使用 aufs, 否则 diskd.
也有一些例外情况, 比如多 cpu 的 Linux 2.6 系统, 线程库很优秀, 虽然 ufs 本身已经比较快了,但是 squid 单进程无法利用另外的 cpu , 不如使用 aufs , 让另外的 cpu 也可以起到一些作用, aufs 在编译的时候可以选择使用几个读写线程. 这个个人觉得稍微超过 cpu 个数就可以了.但是并没有实际测试过.
磁盘缓存开多大? 这个问题没有固定答案. 需要经过试验来确定, 一般来说开大一些没有太大问题. 只要你的硬盘足够
转
squid/缓存 | 评论:0
| Trackbacks:0
| 阅读:866
Submitted by admin on 2011, July 3, 9:46 AM
3. 通过使用多播HTCP包来完成Squid清理,这是MediaWiki目前正在使用的方法,当wiki更新时用于更新全球的Squid缓存服务器,实现原理为:发送PURGE请求到特定的多播组,所有Squid服务器通过订阅该多播组信息完成删除操作,这种实现方式非常高效,避免了Squid服务器处理响应和建立TCP连接的开销。参考资料:Multicast HTCP purging
发送no-cache头的方式在很多情况下不适用,因为大多数站长都会配置ignore-reload来阻止no-cache和reload头以提高Squid的命中率;通过适当的权限控制PURGE清理将是一种非常简单可行的方式,考虑到安全问题我们可以仅允许特定的主机进行PURGE清理操作,对第1,2种方式进行简单的变通就可以用于管理较大规模数量的前端缓存服务器 - 我们可以在被允许的主机上提供一个专门的后台刷新队列,这个刷新队列在接收到刷新操作时就多线程的向前端服务器发送删除指令,这样就达到了同步刷新的效果。第3种方式没有进行过尝试,因为需要安装相应的补丁,并进行配置,操作成本相对较高,在服务器数量特别巨大的情况下这无疑是一种非常高效的实现方式。
squid/缓存 | 评论:0
| Trackbacks:0
| 阅读:827
Submitted by admin on 2011, July 3, 9:45 AM
Refresh_pattern 指令间接的控制磁盘缓存。宽松的设置增加了cache的命中率,同样也增加了用户接受过时相应的几率; 保守的设置,降低了cache的命中率和过时响应
Refresh_pattern 规则仅仅应用到没有明确过时期限响应。原始服务器能使用Expires 头部,或者使用Cache-Control:max-age指令来设置过时期限,当然在squid主配置文件中配置refresh_pattern 配置任意数量,squid是按照顺序进行查找以匹配正则表达式,。一旦squid找到一个匹配时,squid会使用相应的值来决定,某个缓存响应是存活还是过期,当正则表达式之一被匹配URI时,squid 就会停止搜索
Refresh_pattern 的语法
Refresh _pattern [-i] regexp min percent max [Option]
一 regexp 参数是大小写敏感的正则表达式,- i 选项是忽略大小写,
二 min 参数是分钟数量,它是过时响应的最低是时间限制。如果魔鬼响应驻留在cache里的时间没有超过这个最低限制,那么它不会过期。同样max 参数是存活响应的最高时间限制。如果某个响应驻留在cache里的时间高于这个最高限制,那么它必须被刷新
三 在min 和max 时间限制之间的响应,会面对squid的最后修改系统LM-factor算法LM-factor=(responseb age)/(resource age). 对这样的响应,squid计算响应的年龄和最后修改系数,然后将它作为百分比值进行比较,响应年龄简单地就是从原始服务器产生,或者是最后一次验证响应后,经历的时间数量。源年龄在Last-Modified 和Date头部之间是不同的,LM-factor 是响应年龄与源年龄的比率。这不是一个精确控制过期的参数,如果要精确控制过期,就不要使用该参数
四 squid的refresh_pattern 算法的简单描述
1 如果响应年龄超过refresh_pattern 的max值,该响应过期;
2 如果LM-factor 少于refresh_pattern 的percent的值。该响应存活
3 如果响应年龄少于refresh_pattern 的min值,该响应存活
4 其他情况,响应过期
五 Refresh_pattern percent 计算方法
Resource age=对象进入cache的时间 – 对象的last_modified
Response age= 当前时间 – 对象进入cache的时间
LM-factor =(response age)/(resource age )
例如 refresh_pattern 20%
假如源服务器上www.aaa.com/index.html - --lastmodified 是2007-04-10 02:00:00
Squid 上的proxy.aaa.com/index.html index.html存入cache的时间2007-04-10 03:00:00
1 如果当前时间 2007-04-10 03:00:00
Resource age =3点 – 2点 =60分钟
Response age =0 分钟
Index.html 还可以在cache 中停留的时间(resource age)*20%= 12 分钟,换句话说, index.html 进入cache后,可以停留十二分钟,才被重新载入
2 如果当前时间是 2007-04-10 03:05:00
Resource age =3点 – 2点 =60 分钟
Response age=5 分钟
Index.html 还可以在cache中停留的时间
( resource age)*20%=12 分钟-5=7分钟
LM-factor=5/60 =8.3% <20%
3 所有说2007-04-10 03:12:00 LM-factor=12/60=20% 之后,cache中的页面index.html 终于stale,如果这段时间没有index.html的请求,index.html会一直缓存中,如果有index.html 请求,squid收到请求后,由于已经过期,squid 会像源服务器发一个index.html是否有改变的请求,如果源服务器收到请求后,如果index.html没有更新,squid就不用缓存,直接会把缓存中的内容给客户端;同时,重置对象进入cache的时间为源服务器确认的时间。比如2007-04-10 03:13:00 ,如果正好在这个后重新确认了页面。重置后,resource age 变长,相应在cache中的cache中存活的时间也同样变长
如果有改变则把最新的index.html返还给squid ,而squid 收到会更新缓存,然后把新的index.html 返还给客户端,同时根据新页面中的Last_Modified 和取页面的时间,重新计算resource age,同样也重新计算存活时间
实际上,一个对象进入cache后,同样他的存活时间就确定了,即(resource age)* percent ,直到被重新确认
六 refresh_pattern 指令
1 Override-expire
该项导致squid在检查Ecpires 头部之前,先检查min 值,这样。一个非零的min时间让squid返回一个未确认的cache命中,及时该响应准备过期
2 Override-lastmod
该选项导致squid在检查LM-factor 百分比之前先检查min值,其生效在expire 之后
3 Reload-into-ims
该项让squid在确认请求里,以no-cache指令传送一个请求,话句话说,squid在转发请求前,对该请求增加一个If-Modified-Since 头部,主要该点的是,仅仅在目标有Last-Modified 时间截时才能工作。外面进来的请求保留no-cache 指令,以便他到达原始服务器。一般情况下可以使用reload-into-ims。它是强行控制对象的超时时间,这违反了http协议的精神,但是也在带宽较窄的情况下。可以明显的提高系统的响应时间
如
refresh_pattern -i \.css$ 1440 50% 129600 reload-into-ims
refresh_pattern -i \.xml$ 1440 50% 129600 reload-into-ims
refresh_pattern -i \.html$ 1440 90% 129600 reload-into-ims
refresh_pattern -i \.shtml$ 1440 90% 129600 reload-into-ims
refresh_pattern -i \.hml$ 1440 90% 129600 reload-into-ims
refresh_pattern -i \.jpg$ 1440 90% 129600 reload-into-ims
refresh_pattern -i \.png$ 1440 90% 129600 reload-into-ims
refresh_pattern -i \.bmp$ 1440 90% 129600 reload-into-ims
refresh_pattern -i \.js$ 1440 90% 129600 reload-into-ims
4 Ignore-reload
该选项导致squid的忽略请求里的任何no-cache指令
如果希望内容一旦进入cache就不删除,除非是被主动purge掉为止,可以加上ignore-reload 选项,该项常用在mp3,wma,wmv,gif 之类
如
refresh_pattern -i \.mp3$ 1440 50% 2880 ignore-reload
refresh_pattern -i \.wmv$ 1440 50% 2880 ignore-reload
refresh_pattern -i \.rm$ 1440 50% 2880 ignore-reload
refresh_pattern -i \.swf$ 1440 50% 2880 ignore-reload
refresh_pattern -i \.mpeg$ 1440 50% 2880 ignore-reload
refresh_pattern -i \.wma$ 1440 50% 2880 ignore-reload
5 Ignore-no-cache
该项导致squid强制忽略从源站而来的“Pragma:no-cache”和“cache-control:no-cache”
6 Ignore-private
该项导致squid强制忽略从源站而来的“cache-control:private”
7 Ignore-auth
该项导致squid 强制将一个请求认为是源站发送的带有“cache-control:public”
8 Ignore-no-store
该指令是忽略来自源站不缓存对象
a no-store directive from the Web server which makes an object non-cacheable is ignored.
9 Refresh-ims
该项是client一个刷新请求转换成一个If-Modified-Since 请求
a refresh request from a client is converted into an If-Modified-Since request.
转
squid/缓存 | 评论:0
| Trackbacks:0
| 阅读:817
Submitted by admin on 2011, July 3, 9:44 AM
公司的网站使用Squid 2.6STABLE2作缓存加速服务器,缓存的命中率一直不好,最好也只能达到90%,折腾了许久,终于发现影响最大的原来只是一个小参数,不过期间也学 到了不少东西~
起初,考虑缓存命中率不高,考虑是不是给Squid的内存不够,所以就加大了内存配置,2G内存的机器给Squid 1G用,测试了两天,结果基本没有什么大的改变;于是调整refresh_pattern的参数,增大内容缓存时间,测试了两天,效果也不理想。
从 kxn的文章中知道可以使用Expires模块让Apache给文件指定缓存时间,期望可以提高缓存性能,于是在服务器上:
ExpiresActive On
ExpiresDefault A2592000
结果第二天一早发现缓存命中率竟然比前一天还下降了2个百本点,有点晕了~
于是将cachemgr配置起来,详细地检查squid的运行状况,发现1G的内存缓存实际只用了不到300M,所以显然不是内存不够的问题。
为了充分利用内存,将maximum_object_size_in_memory调大到128KB,让其可以缓存更大的文件,而不是默认的 8KB。顺手将ufs换成aufs,启用异步IO。
之后情况稍有改善,1个小时之后,内存的占用达到了1G,但命中率并没有明显上升。
于是又调整了内存的覆盖策略(memory_replacement_policy),听从kxn的教诲,使用lru,发现变化不大,也许是我们的 访问量还不大的原因吧。
这时候缓存命中率仍然在90%以下徘徊。是不是我们的网站结构影响只能达到这么高呢?但是网站结构我没有办法改变,所以还是要从其他方面入手来解决 问题。
于是使用Cache Manager 仔细的查看各个统计数据,当看到In-Memory and In-Transit Objects项目时,发现一个问题,那就是所有的网页文件都显示NOT_IN_MEMORY,这就比较奇怪了,问什么访问量最大的网页文件竟然没有被缓 存到内存呢?是因为文件太大还是因为文件请求的数量太少,所以才没有被缓存呢?于是找了一个页面作测试,使用工具查看了返回的大小,只有40K多一些,与 我的maximum_object_size_in_memory最大值128KB还有相当大的差距,所以不可能是这个原因。于是有使用ab程序对这个页 面做了1000次请求,心想这下总会缓存了吧。可是查看缓存内容,依然没有,而且不但内存中没有,就连硬盘上也没有!
至此得出结论,一定是什么原因阻止了Squid对这些网页进行缓存。仔细的检查In-Memory and In-Transit Objects中的内容,发现IN_MEMORY 状态的对象基本都是jpg和gif图像文件,html,css等文本文件内容则都没有缓存。
这两种文件有什么不同吗?记忆中Squid也没有对这些文件类型的设定呀,refresh_pattern对所有的静态文件的设置也都是一致的,所 以差异不应该来源于squid本身——也就是因为这种记忆使得我后来多费了许多的功夫~
在Apache上找到了文本文件与图像文件之间设置的差异——deflate压缩。是不是所有使用deflate压缩的内容都不会缓存呢?使用同样 的squid软件版本及配置文件,相同的Apache软件版本和配置,快速的搭建了一套测试环境。squid只有1台,重建其磁盘缓冲区,重新启动 squid,观察内存中对象的变化。果然,对于deflate压缩的内容,squid内存中没有缓存,磁盘也找不到。停止apache的deflate功 能,重新请求页面,立即在squid的内存中查到了内容的缓存,这么看来是squid和deflate不太兼容了?
好吧,先将产品环境Apache的deflate停掉,过了一段时间,有两台squid的缓存命中了提高到了94%,虽然只提升了4个百分点,但是 这充分验证了squid和deflate不兼容的观点。
然而,事情到此才刚刚开始!
难道Squid真的无法缓存deflate压缩的页面吗?好吧google一下,squid+deflate,在squid的邮件列表中找到了一些 讨论deflate的东西,属于比较古老的吧,说因为deflate压缩之后,会产生Content-Encoding: gzip这样的HTTP头部,属于HTTP/1.1的内容,而Squid并不完全兼容HTTP/1.1之类的,需要用Transfer-Encoding 之类的代替,可是mod_deflate和mod_gzip产生的头部就是Content-Encoding,怎么办?
为了解决这个问题,引入了另一个Apache的模块,mod_headers,用它来改写HTTP应答的头部,将Content-Encoding 更改给Transfer-Encoding,可是,很自然的,页面一片乱码!说明此路不通啊!
又以Content-Encoding为关键字,快速的搜索了一下squid 2.6STABLE2的源代码,也没有发现几个地方用到这个东西,无果。
继续Google之,squid+can’t cache+Content-Encoding找到一篇文章,其中说’SQUID would never bother to cache ANYTHING that had
a “Vary:” header on it.’ 看来Squid缓存内容与Vary: 头部有关系。再次检查一下HTTP请求返回的头部内容,发现对于deflate压缩的内容,拥有”Vary: Accept-Encoding”这样一个头部,而没有经过deflate压缩的内容则没有这个头部,这次看来问题比较清楚了,因为deflate压缩添 加了Vary: Accept-Encoding这个头部,导致了内容无法被squid缓存。
那么难道真的没有办法让squid缓存deflate压缩之后的内容吗?
基于上面的经验,很自然的想到使用mod_headers模块的功能将Vary头抹掉Squid不就可以缓存了吗?后来一想,这样会有其它问题: 1)如果用户浏览器不支持gzip压缩功能,那么将无法正常的浏览网页;2)其它可能很重要的Vary内容也没有了,可能会导致更大的隐患。那么这种办法 不行。
还有其它的办法吗?再次的快速搜索了Squid的源文件中关于Vary的内容,在Changelog中找到了这么一条:
- Full ETag/Vary support, caching responses which varies with request details (browser, language etc).
也就是说已经完全支持带ETag/Vary头部的内容缓存了。这一条出现在Changes to squid-2.6.STABLE1,也就是说在Squid2.6STABLE1就已经完全实现了这个功能,那么2.6STABLE2应该没有问题,会不 会是2.6STABLE2的BUG呢,查询了一下2.6系列的所有Changelog,没有提到此故障的信息。推断我们的故障要么由一个未知BUG导致, 要么是自己配置不当。BUG的问题我无法确认,只能先从配置入手。
找来一份2.6STABLE2带的默认配置文件,搜索Vary,第一条:
# TAG: cache_vary
# Set to off to disable caching of Vary:in objects.
#
#Default:
# cache_vary on
难道我的配置文件是off不成?赶紧检查,发现还真是off,sign,原来就是这个问题折磨我,改成on,将 Apache的Deflate配置启用,再观察内存对象,发现静态网页真的被缓存了!
郁闷了许久,终于可以松口气了。
过了一会儿,再查看Squid的状态,发现缓存命中率没有下降,稳定在94%左右。
也许Squid还有什么可挖掘的空间吧,改天接着折腾!
后记:Squid对Vary和Etag的支持属于2.6的一项主要改进,这一特性改进Squid对HTTP/1.1标准的支持。在将Squid升级 至2.6之前,也看过他的Changelog,但当时并不明白Vary到底有什么用途,这么一折腾,明白了不少。看来应该把HTTP/1.1的标准再好好 研读一下。
转
squid/缓存 | 评论:0
| Trackbacks:0
| 阅读:744
Submitted by admin on 2011, July 2, 10:05 AM
Ubuntu 10.10 x64的版本
第一步:安装Java SDK 1.6 后续的版本估计都是要用JDK 1.6了吧
这里给个地址,大家自助下载:
http://www.oracle.com/technetwork/java/javase/downloads/index.html
然后修改~/.profile 添加下边这两行:
export PATH=$PATH:/opt/jdk1.6/bin/
export JAVA_HOME=/opt/jdk1.6/
其中上边的/opt/jdk1.6是我安装JDK的地方,大家想装那里就随意吧,也可以让1.6和1.5共存,就看大家愿意怎么弄了
第二步:Ubuntu 10.10中缺少什么就装什么,这里主要总结一下出错的地方
1、编译过程中出现com.sun.javadoc不存在的错误,如下方式解决:
export ANDROID_JAVA_HOME=$JAVA_HOME
2、usr/include/gnu/stubs.h:7:27: error: gnu/stubs-32.h: No such file or directory
解决办法:sudo apt-get install libc6-dev-i386
3、/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.3/libstdc++.so when searching for -lstdc++
解决办法:sudo apt-get install g++-multilib
4、Traceback (most recent call last):
File "../repo", line 595, in <module>
main(sys.argv[1:])
File "../repo", line 562, in main
_Init(args)
File "../repo", line 181, in _Init
_CheckGitVersion()
File "../repo", line 210, in _CheckGitVersion
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
File "/usr/lib/python2.6/subprocess.py", line 623, in __init__
errread, errwrite)
File "/usr/lib/python2.6/subprocess.py", line 1141, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
解决办法:sudo apt-get install git
5、/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../libz.so when searching for -lz
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../libz.a when searching for -lz
/usr/bin/ld: skipping incompatible //usr/lib/libz.so when searching for -lz
/usr/bin/ld: skipping incompatible //usr/lib/libz.a when searching for -lz
/usr/bin/ld: cannot find -lz
collect2: ld returned 1 exit status
解决办法:sudo apt-get install lib32z1-dev
6、/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.3/libstdc++.so when searching for -lstdc++
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.3/libstdc++.a when searching for -lstdc++
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.3/libstdc++.so when searching for -lstdc++
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.3/libstdc++.a when searching for -lstdc++
解决办法:sudo apt-get install g++-multilib
7、/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../libncurses.so when searching for -lncurses
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../libncurses.a when searching for -lncurses
/usr/bin/ld: skipping incompatible /usr/lib/libncurses.so when searching for -lncurses
/usr/bin/ld: skipping incompatible /usr/lib/libncurses.a when searching for -lncurses
/usr/bin/ld: cannot find -lncurses
解决办法:sudo apt-get install lib32ncurses5-dev
8、prebuilt/linux-x86/sdl/include/SDL/SDL_syswm.h:55:22: error: X11/Xlib.h: 没有那个文件或目录
prebuilt/linux-x86/sdl/include/SDL/SDL_syswm.h:56:23: error: X11/Xatom.h: 没有那个文件或目录
解决办法:sudo apt-get install libx11-dev
最后就是搞定代码开始编译了
转
android | 评论:0
| Trackbacks:0
| 阅读:869
Submitted by admin on 2011, July 2, 10:04 AM
建立编译环境
1.在VirtualBox上安装Ubuntu
2.安装JDK
$ sudo apt-get install sun-java5-jdk 或
$ sudo apt-get install sun-java6-jdk (donut 1.6)
3.安装flex,bison,gperf,libsdl-dev,libesd0-dev,libwxgtk2.6-dev(可选),build-essential,zip,curl。
$ sudo apt-get install flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl libncurses5-dev zlib1g-dev
4.安装Valgrind(可选),此工具可以帮你查找内存泄漏、堆栈破坏以及数组访问越界等错误。
$ sudo apt-get install valgrind
5.下载Android源代码
从Android官方下载donut分支的Android源代码
sudo apt-get install git-core curl
curl http://android.git.kernel.org/repo >~/bin/repo
chmod a+x ~/bin/repo
cd ~/bin/
$ ./repo init -u git://android.git.kernel.org/platform/manifest.git -b android-1.6_r2
$ ./repo sync
6.在 ~/.bashrc 加环境变量。
$ vim ~/.bashrc
在.bashrc文件的最后面加入如下2行,即将JDK的安装路径加入到环境变量中
export JAVA_HOME=/usr/lib/jvm/java-6-sun
export ANDROID_JAVA_HOME=$JAVA_HOME
完成后,$source ~/.bashrc即可生效。
运行 $ java -version 将出现下面提示:
[root@Neil java]# java -version
java version "1.6.0_11"
Java(TM) SE Runtime Environment (build 1.6.0_11-b03)
Java HotSpot(TM) Client VM (build 11.0-b16, mixed mode, sharing)
[root@Neil java]#
说明Java已经成功被安装了
通过
$ update-alternatives --config javadoc
$ sudo update-alternatives --config java
$ sudo update-alternatives --config javac
然后选一个编号,就切换过去了。
编译Android
$ cd android //(进入android目录)
$ make //(编译android)
注意:编译时要确保系统的内存在1.2GM以上,且有足够的硬盘可用空间,否则会编译失败终止。
Android编译环境提供了”showcommands”选项来显示编译命令行,如:
$ make showcommands
1.5_r2版编译出错的解决方法:
The Android code contains a bug that hasn’t been solved up to the date of this article.
So before you start compiling the code, you’ll need a few modifications, or the build will fail (after consuming some of your time and patience). The error is:
external/qemu/sockets.c: In function 'sock_address_init_resolve':
external/qemu/sockets.c:637: error: 'EAI_NODATA' undeclared (first use
in this function)
external/qemu/sockets.c:637: error: (Each undeclared identifier is
reported only once
external/qemu/sockets.c:637: error: for each function it appears in.)
make: *** [out/host/linux-x86/obj/EXECUTABLES/emulator_intermediates/
sockets.o] Error 1
To fix this, before compiling the android code, open ~/mydroid/external/qemu/sockets.c and add
#define __USE_GNU
just before the #include <netdb.h>
新编译的system.img不能正常使用sdcard 的解决办法:
$ mount -t vfat /dev/block//vold/179:0 /sdcard
也可以更改system/core/vold程序
运行emulator
我们这里使用已经编译好的模拟器kernel镜像,即kernel-qemu,位于android/prebuilt/android-arm/kernel目录下,然后运行模拟器。
1.在 ~/.bashrc 加环境变量。(本项可选)
$ vim ~/.bashrc
在.bashrc文件的最后面加入如下2行,即将Android工具的路径
export PATH=/archer/external/android/out/host/linux-x86/bin
PATH
export ANDROID_PRODUCT_OUT=/archer/external/android/out/target/product/generic
export ANDROID_SWT=/android/out/host/linux-x86/framework
2.创建Android虚拟设备
$ cd android/out/host/linux-x86/bin (进入模拟器程序所在目录)
$ ./android create avd -t 2 -n g1
其中 -t 指定TargetID (Android 1.5 SDK的ID为2,Android 1.0 SDK的ID为1),-n指定创建的Android虚拟设备名字。
3.运行emulator
$ cd android/out/host/linux-x86/bin (进入模拟器程序所在目录)
$ ./emulator -avd g1 或者
$ ./emulator -avd g1 -scale 0.8
其中 -avd指定Android设备名,-scale指定缩放比例。
按 Ctrl + F12 可以使模拟器屏幕旋转90度,即横屏、竖屏切换。
4.删除创建的Android虚拟设备
$ ./android delete avd -n g1
编译linux kernel
直接编译Android源码时,并没有编译 linux kernel。如果只运行模拟器,不用编译 linux kernel。
从emulator获取内核编译参数的配置文件:
启动模拟器
$ adb pull /proc/config.gz .
解压缩config.gz $ gzip -d config.gz
将config文件替换kernel文件夹下的.config文件。
根据需要,修订config与Makefile配置文件
编译模块
Android中的一个应用程序可以单独编译,编译后需要重新生成system.img。
在Android目录下运行
$ . build/envsetup.sh 或者
$ source build/envsetup.sh ,然后就会多出几个可用的命令:
- croot: Changes directory to the top of the tree.
- m: Makes from the top of the tree.
- mm: Builds all of the modules in the current directory.
- mmm: Builds all of the modules in the supplied directories.
- cgrep: Greps on all local C/C++ files.
- jgrep: Greps on all local Java files.
- resgrep: Greps on all local res/*.xml files.
- godir: Go to the directory containing a file.
- printconfig: 当前build的配置情况.
可以使用 --help查看用法。
如:在修改了某一个模块以后,可以使用 $ mmm <目录> 来重新编译所有在<目录>中的所有模块,使用 $ mm 编译当前目录中的所有模块。
编完之后,即修改了Android系统以后,可以使用 $ make snod 重新生成system.img。
转
android | 评论:0
| Trackbacks:0
| 阅读:1431