编程技巧
HTTP header中的 Cache-control
Cache-control常见的取值有private、no-cache、max-age、must-revalidate等
网页的缓存是由HTTP消息头中的“Cache-control”来控制的,常见的取值有private、no-cache、max-age、must-revalidate等,默认为private。其作用根据不同的重新浏览方式分为以下几种情况:
(1) 打开新窗口
如果指定cache-control的值为private、no-cache、must-revalidate,那么打开新窗口访问时都会重新访问服务器。而如果指定了max-age值,那么在此值内的时间里就不会重新访问服务器,例如:
Cache-control: max-age=5
表示当访问此网页后的5秒内再次访问不会去服务器
(2) 在地址栏回车
如果值为private或must-revalidate(和网上说的不一样),则只有第一次访问时会访问服务器,以后就不再访问。如果值为no-cache,那么每次都会访问。如果值为max-age,则在过期之前不会重复访问。
(3) 按后退按扭
如果值为private、must-revalidate、max-age,则不会重访问,而如果为no-cache,则每次都重复访问
(4) 按刷新按扭
无论为何值,都会重复访问
当指定Cache-control值为“no-cache”时,访问此页面不会在Internet临时文章夹留下页面备份。
另外,通过指定“Expires”值也会影响到缓存。例如,指定Expires值为一个早已过去的时间,那么访问此网时若重复在地址栏按回车,那么每次都会重复访问:
Expires: Fri, 31 Dec 1999 16:00:00 GMT
在ASP中,可以通过Response对象的Expires、ExpiresAbsolute属性控制Expires值;通过Response对象的CacheControl属性控制Cache-control的值,例如:
Response.ExpiresAbsolute = #2000-1-1# ‘ 指定绝对的过期时间,这个时间用的是服务器当地时间,会被自动转换为GMT时间
Response.Expires = 20 ‘ 指定相对的过期时间,以分钟为单位,表示从当前时间起过多少分钟过期。
Response.CacheControl = “no-cache”
大型网站架构
大型网站架构系列之一 不得不考虑的问题
前言:这两天机器坏了,正在送修中,写个系列的大型网站架构的文章,希望对有志在互联网做出一番事业的站长朋友们一些帮助。
注意:这里的大型网站架构只包括高互动性高交互性的数据型大型网站,基于大家众所周知的原因,我们就不谈新闻类和一些依靠HTML静态化就可以 实现的架构了,我们以高负载高数据交换高数据流动性的网站为例,比如海内,开心网等类似的web2.0系列架构。我们这里不讨论是PHP还是JSP或者. NET环境,我们从架构的方面去看问题,实现语言方面并不是问题,语言的优势在于实现而不是好坏,不论你选择任何语言,架构都是必须要面对的。
文入正题:
首先讨论一下大型网站需要注意和考虑的问题
A. 海量数据的处理。
众所周知,对于一些相对小的站点来说,数据量并不是很大,select和update就可以解决我们面对的问题,本身负载量不是很大,最多再加 几个索引就可以搞定。对于大型网站,每天的数据量可能就上百万,如果一个设计不好的多对多关系,在前期是没有任何问题的,但是随着用户的增长,数据量会是 几何级的增长的。在这个时候我们对于一个表的select和update的时候(还不说多表联合查询)的成本的非常高的。
B. 数据并发的处理
在一些时候,2.0的CTO都 有个尚方宝剑,就是缓存。对于缓存,在高并发高处理的时候也是个大问题。在整个应用程序下,缓存是全局共享的,然而在我们进行修改的时候就,如果两个或者 多个请求同时对缓存有更新的要求的情况下,应用程序会直接的死掉。这个时候,就需要一个好的数据并发处理策略以及缓存策略。
另外,就是数据库的死锁问题,也许平时我们感觉不到,死锁在高并发的情况下的出现的概率是非常高的,磁盘缓存就是一个大问题。
C. 文件存贮的问题
对于一些支持文件上传的2.0的站点,在庆幸硬盘容量越来越大的时候我们更多的应该考虑的是文件应该如何被存储并且被有效的索引。常见的方案是 对文件按照日期和类型进行存贮。但是当文件量 是海量的数据的情况下,如果一块硬盘存贮了500个G的琐碎文件,那么维护的时候和使用的时候磁盘的Io就是一个巨大的问题,哪怕你的带宽足够,但是你的 磁盘也未必响应过来。如果这个时候还涉及上传,磁盘很容易就over了。
也许用raid和专用存贮服务器能解决眼下的问题,但是还有个问题就是各地的访问问题,也许我们的服务器在北京,可能在云南或者新疆的访问速度如何解决?如果做分布式,那么我们的文件索引以及架构该如何规划。
所以我们不得不承认,文件存贮是个很不容易的问题
D. 数据关系的处理
我们可以很容易的规划出一个符合第三范式的数据库,里面布满了多对多关系,还能用GUID来替换INDENTIFY COLUMN 但是,多对多关系充斥的2.0时代,第三范式是第一个应该被抛弃的。必须有效的把多表联合查询降到最低。
E. 数据索引的问题
众所周知,索引是提高数据库效率查询的最方面最廉价最容易实现的方案。但是,在高UPDATE的情况下,update和delete付出的成本 会高的无法想想,笔者遇到过一个情况,在更新一个聚焦索引的时候需要10分钟来完成,那么对于站点来说,这些基本上是不可忍受的。
索引和更新是一对天生的冤家,问题A,D,E这些是我们在做架构的时候不得不考虑的问题,并且也可能是花费时间最多的问题,
F. 分布式处理
对于2.0网站由于其高互动性,CDN实现的效果基本上为0,内容是实时更新的,我们常规的处理。为了保证各地的访问速度,我们就需要面对一个绝大的问题,就是如何有效的实现数据同步和更新,实现各地服务器的实时通讯有是一个不得不需要考虑的问题。
G. Ajax的利弊分析
成也AJAX,败也AJAX,AJAX成为了主流趋势,突然发现基于XMLHTTP的post和get是如此的容易。客户端get或者post 到服务器数据,服务器接到数据请求之后返回来,这是一个很正常的AJAX请求。但是在AJAX处理的时候,如果我们使用一个抓包工具的话,对数据返回和处 理是一目了然。对于一些计算量大的AJAX请求的话,我们可以构造一个发包机,很容易就可以把一个webserver干掉。
H. 数据安全性的分析
对于HTTP协议来说,数据包都是明文传输的,也许我们可以说我们可以用加密啊,但是对于G问题来说的话,加密的过程就可能是明文了(比如我们 知道的QQ,可以很容易的判断他的加密,并有效的写一个跟他一样的加密和解密方法出来的)。当你站点流量不是很大的时候没有人会在乎你,但是当你流量上来 之后,那么所谓的外挂,所谓的群发就会接踵而来(从qq一开始的群发可见端倪)。也许我们可以很的意的说,我们可以采用更高级别的判断甚至HTTPS来实 现,注意,当你做这些处理的时候付出的将是海量的database,io以及CPU的成本。对于一些群发,基本上是不可能的。笔者已经可以实现对于百度空 间和qq空间的群发了。大家愿意试试,实际上并不是很难。
I. 数据同步和集群的处理的问题
当我们的一台databaseserver不 堪重负的时候,这个时候我们就需要做基于数据库的负载和集群了。而这个时候可能是最让人困扰的的问题了,数据基于网络传输根据数据库的设计的不同,数据延 迟是很可怕的问题,也是不可避免的问题,这样的话,我们就需要通过另外的手段来保证在这延迟的几秒或者更长的几分钟时间内,实现有效的交互。比如数据散 列,分割,内容处理等等问题
K.数据共享的渠道以及OPENAPI趋势
Openapi已经成为一个不可避免的趋势,从google,facebook,myspace到 海内校内,都在考虑这个问题,它可以更有效的留住用户并激发用户的更多的兴趣以及让更多的人帮助你做最有效的开发。这个时候一个有效的数据共享平台,数据 开放平台就成为必不可少的途径了,而在开放的接口的情况保证数据的安全性和性能,又是一个我们必须要认真思考的问题了。
当然还有更多需要考虑的问题,我这里就写一个最需要考虑的问题,欢迎补充。下一篇文章将针对问题A,提出具体的解决方案和思路
大型网站架构系列之二 底层架构概论
首先澄清上篇中关于几个朋友的评论。
上篇介绍的基于AJAX的攻击很多人提出疑问,比如不能跨域,减轻负担之类。Ajax是通过简单的GET和POST进行数据传递的,采用 HTTPDEBUGGER,抓取数据,然后采用如下方案,顺便写个示例的攻击代码.比传统的webform,我们更容易构造一些,其实对于webform 和ajax的处理和发包过程是一样的,ajax数据量相对小,速度也快一些。
结合SharpPcap和HttpWebRequest我们构造一个合理的正常的IP数据包过去,代码很长,我们用伪代码简单的表达一下。
request.CreateUrl(Ajax处理页面);
request.Method=”GetORPost”;
request.refere=”网页来源”;
SharpPcap.SetLinkConnection(伪造IP地址);
String content = request.GetResponseStream() 如果作为一个多线程的应用程序对对方的WEB构成批量发包的话(假如是DEDECMS),足可以把Dedecms的数据库搞垮
文入正题:
对于上回书提到要解决问题A,我们先讲解一下电信公司ADSL的布局方案。机器上没有装VISIO,我简单的用文字描述一下流程。
Adsl用户Aè输入用户名密码è远程连接到账户数据库(在天津)è账户数据库连接计费数据库并返回状è如果成功,连接PPPOE服务器,并进一步连接计费数据库è认证服务并连接。
这里没有什么特别的地方,但是和qq通讯服务是一样的,就是采用了统一的用户验证服务器,同时对于用户验证的信息数据库是只读的,我们从其中可以想到什么吗?
以上是个简单的例子,下面开始谈具体的架构策略,首先对于上篇提到的问题A,我们首先以用户数据库为例来做解释和要求。
首先做用户量估算需求,假如我们做的是学术社区,那么这个用户量不会很大,可能我们不需要考虑这个,对于用户量的级别,我们暂时把用户量级别定 为三种,百万级别(M)和千万界别(S),以及亿万级别(Q),并考虑用户登录验证以及查询常用的操作,对M和S进行扩充以及了解。
众所周知,在这个情况下,对于用户数据的负载其实并非可行而不可行的问题,而是如何最大化的保证查询和更新以及各个服务器之间的数据同步。这里 我们不再讲解如何优化如何索引,只介绍架构初期的方案,下面介绍的方案如果涉及全表查询,可以采用分区视图的方案,大家可以具体搜索相关资料。
对于M级别来说,现有的DBMS经过合理的布局完全可以满足需求。我们需要解决的问题的关键其实是处理IO方面的问题,处理方案相对简单一些, 对数据库的FILE文件分磁盘存贮(不是分区,是不同的硬盘),根据负载量大小,我们可以适当的控制硬盘的数量和文件分区的数量。
对于S级别,上个处理方案已经不能完全满足需求了,这个时候我们需要对注册和入库的流程进行简单的修改了,解决方案是数据散列和分区视图的概念,具体概念大家去google一下,我不详细说明了。
我们常用的方案有三种。第一种是等容扩充法,在用户注册控制的基础上,保证每个库的用户容量不超过500万,超过之后入第二个库,以此类推,这 个方案可以保证系统有效的扩充性,但不能保证数据被有效的索引。第二种就是共区索引方案,其实和第一种方案有异曲同工的之说但是讲第一种方案进行了合理的 优化,按照用户名进行分库存贮。比如我们可以建立26的数据库,按照用户名的索引来控制用户数据入哪个库。假如用户名是CrazyCoder,那么就讲该 用户名的数据存放在用户表C中,在数据存贮的时候可以很方便的根据用户名进行相应的数据查询,方案二可以有效的解决数据索引问题。方案三是一个更具模型化 的方案,结合方案一和方案二,进行用户ID的编码,不是INDENTIFY Cloumn,我们用一种序列化的方案将用户名以编码的形式存贮,比如用户名是CrazyCoder,我们的编码方案就是通过算法进行数字化,将 CrazyCoder按照C,R,A,….存贮为数字索引,然后进行分区存贮,数字类型的数据在数据库中可以更有效的被查询和被更新和共享,结合方案一和 方案二这个就是方案三。
对于Q级别。数据量已经是足够海量了,这个时候无论用哪种方案都是一个让人头大的数据,不能简单的用查询的方案来处理了,可以参考S级别的进行 处理。但这个时候我们采用的方案是根据用户活跃度的权值结合数据量进行临时数据表的存放。如果一个非意外的数据情况下,每天登录的用户量不会上千万。这个 时候我们需要做的是一个简单的数据代理程序。一个临时的用户验证数据库,每天执行一次批处理,将活跃度高的用户账户提取到临时数据库中,查询的时候先查询 临时库,如果没有在进行全库查询。这个根据系统的负载情况来估计阈值,不同的系统估算方案也不尽相同。
上面对于,M,S,Q三种界别进行了简单的概述,下面介绍一个在其之上更高级的一个查询方案,数据缓存服务器,我们也可以把它理解为缓冲服务器,数据做为只读来使用。
具体实现方案如下:以为涉及了海量,DBMS常规的缓存方案已经不符合我们的要求了,那么我们需要一个有效的缓存方案,这个时候处理的流程其实 [...]
mysql sql 修改表名 建立外键 修改列名 删除列
–重命名表
rename table t_softwareport to software_port;
–建立外键
alter table software_port add constraint fk_software_port_softwareprocessid foreign key (softwareprocessid)
references software_process (id) on delete restrict on update restrict;
–删除列
alter table software_type
drop column upid,
drop column orderid;
–修改列名
alter table software_process change software_id softwareid int(11) not null;
MYSQL系统优化与系统设置参数
MYSQL系统优化与系统设置参数的一次调查
对mysql进行优化意味着适当地分配内存,并让mysqld了解将会承担何种类型的负载。减少磁盘访问的次数。
类似地,确保 MySQL 进程正确操作就意味着它花费在服务查询上的时间要多于花费在处理后台任务(如处理临时磁盘表或打开和关闭文件)上的时间。
记录慢速查询
在一个 SQL 服务器中,数据表都是保存在磁盘上的。索引为服务器提供了一种在表中查找特定数据行的方法,而不用搜索整个表。当必须要搜索整个表时,就称为表扫描。通常 来说,您可能只希望获得表中数据的一个子集,因此全表扫描会浪费大量的磁盘 I/O,因此也就会浪费大量时间。当必须对数据进行连接时,这个问题就更加复杂了,因为必须要对连接两端的多行数据进行比较。
当然,表扫描并不总是会带来问题;有时读取整个表反而会比从中挑选出一部分数据更加有效(服务器进程中查询规划器用来作出这些决定)。如果索引的使用效率 很低,或者根本就不能使用索引,则会减慢查询速度,而且随着服务器上的负载和表大小的增加,这个问题会变得更加显著。执行时间超过给定时间范围的查询就称 为慢速查询。
您可以配置 mysqld 将这些慢速查询记录到适当命名的慢速查询日志中。管理员然后会查看这个日志来帮助他们确定应用程序中有哪些部分需要进一步调查。清单 1 给出了要启用慢速查询日志需要在 my.cnf 中所做的配置。
启用 MySQL 慢速查询日志
[mysqld]
; enable the slow query log, default 10 seconds
log-slow-queries
; log queries taking longer than 5 seconds
long_query_time = 5
; log queries that don’t use indexes even if they take less than long_query_time
; MySQL 4.1 and newer only
log-queries-not-using-indexes
这三个设置一起使用,可以记录执行时间超过 5 秒和没有使用索引的查询。请注意有关 log-queries-not-using-indexes [...]
关于邮件群发的经验和技巧
一、关于邮件群发的经验和技巧
1、强力推荐使用免smtp服务器的群发软件。这种软件将您的电脑虚拟成发信服务器,邮件直接地送至对方的邮箱,可以清楚地知道发送成功的数量,还可以知道邮址不能发送成功的原因。如亿虎Email邮差和WorldCast等。
2、尽量不要使用多smtp服务器的群发软件。多smtp的服务器软件,由于先将邮件发送至smtp服务器进行中转,现在,一般的邮件服务器都做了 设置,如果smtp服务器检测到短时间内来自同一个IP地址的大量连接请求,就会中止转发邮件,从而产生大量退信现象。况且,现在免费的smtp服务器已 经很难找了。
3、建议将邮件地址打乱发送,效果最佳。您可以使用一些电子邮件地址列表筛选和管理软件,如Mail List Management和欧阳邮件列表管家可以轻松实现这一要求。
4、发送信件的时候,建议申请多个hotmail、yahoo等免费信箱作为发送信箱,轮流使用,而将自己常用的信箱作为回复信箱,这样可以避免常 用的信箱受到封锁,从而也可以避免因此产生的大量退信现象。如sohu.com的邮箱,经常使用同一个信箱发送信件的话,服务器会屏蔽您的邮址,从而不能 发送,碰到这种情况,就需要更换发送信箱了。
5、合理使用群发线程。群发线程越多,速度自然越快,但现在很多的服务器自动检测,如163.net、263.net的邮箱,如果线程数使用很多, 服务器马上显示太多的连接请求,拒绝再转发。具体多少线程数为好,用户可以根据自己的电脑进行测试,从而找到最佳的发送线程数,既要保证发送速度快,同时 也要保证最高的成功率,还要保证发送邮件的时候不死机。
6、群发软件的选择使用。由于每一款群发软件在设计时发送参数都略有不同,所以不是每一款群发软件都能发送邮件到任何一个邮箱。如:一款群发软件可 发送邮件至21cn.com、sohu.com、263.net等,但却不能够发送邮件至sina.com、etang.com。而另一款群发软件却可发 送邮件至sina.com、263.net、etang.com、sohu.com等,但它不能发送邮件至21cn.com。这种情况在免SMTP群发软 件中尤为突出。因此,要尽可能全面的群发邮件到不同的邮箱,建议用户使用不同的群发软件,一种软件不能发送成功的邮址,可以导入到另一种群发软件,试试 看。
7、由于网络速度和服务器设置等多方面的原因,发送的时候可能经常会出现服务器连接失败的提示,您可以将这些邮址重新发送一次,很多又可以成功的。
二、关于邮件地址收集的经验和技巧
1、搜集网站邮址软件。通过扫描网页及相关链接方式,不断搜索网页上公布的Email地址。重点推荐亿虎Email扫描大师、Fast Email Spider和商舟邮箱搜集大师。这些软件对收集行业邮件地址比较有用。建议您先收集一些行业网站的网址,然后利用这些软件搜索这些网站,可以得到大量活 跃程度比较高的邮址。
2、搜索服务器邮址软件。利用字典文件直接从邮件服务器收集邮址,重点推荐邮件地址探索者和伊妹捕神,本站已经整理了一份比较全面的中国邮件服务器和国际邮件服务器的清单以及字典文件,如果您觉得本站提供的邮址不够,可以利用这种搜索软件自行搜索服务器邮址。
3、搜索硬盘、光盘邮址软件。快速搜索电脑硬盘、光盘、软盘中的文本文件、网页文件及*.eml格式文件中的电子邮件地址,重点推荐:小不点 Email地址提取大师和科蓝邮件地址搜寻工具。基于这种软件的用途,您还可以利用teleport等网站下载软件将那些供求信息BBS信息,“拉回”到 自己的电脑,然后用这种软件进行搜索邮址,可以得到大量的有效Email地址。
三、关于邮件地址和管理和验证
1、邮址管理软件。电子邮件地址列表筛选和管理软件,可以帮助客户管理好自己的电子邮件列表,避免发送大量重复垃圾邮件, 重点推荐:Mail List Management(MLM)和欧阳邮件列表管家。MLM软件是我们使用过的邮址管理软件中功能最强,速度最快的软件,100万的邮址几分钟就可以完成 过滤重复邮址、重新排序等。欧阳邮件列表管家则可以快速将一个很大的邮址文件分割成较小的文件,以方便群发。
2、邮址验证软件。采用模拟向被校验邮箱发信,而实际上又并没有发出的方式来对检查邮件地址的存在与否,重点推荐: Advanced Email Verifier和Advanced Maillist Verify。我们在实际使用中发现,很多验证有效的邮址,在群发的时候就是不能发送成功,这是由于邮件服务器设置的原因,所以,如果您需要建立一个自己 的高效率的邮址列表,可以直接使用免smtp服务器的软件导入邮址群发,将那些发送成功的邮址保存下来以便今后使用。
四、关于信息发布软件
由于现在对邮件发送的越来越多的限制,群发邮件很容易产生“垃圾邮件”,很多的人采用供求信息BBS进行推广。这样的软件现在也很多,比较有名的如 商务快车、环球商务信息发布系统、营销之星和网际营销等等。这些软件可以将您的信息发布至国内外上千个BBS站点或者新闻组。但这些软件相对比较贵。
tar打包一个目录时,去掉其中的几个子目录
tar cvfz chenxu.tar.gz dir –exclude dir/dir1 –exclude dir/dir2/dir3 可以陆续添加, 注意添加排队目录时不要加“/”根符号
awstats安装和配置
1.下载&&安装
http://awstats.sourceforge.net/
tar .. && cd …. && perl awstats_configure.pl
#然后根据提示操作,可以不要这步,直接根据自带的模版定义
#cp ../cgi-bin/awstats.model.conf /etc/awstats/common.conf
2.按照一下样例设置配置文件:
#cd /etc/awstats
#vi awstats.www.zhangjianfeng.com.conf
Include “common.conf”
LogFile=”/home/apache/logs/access_log.%YYYY-24%MM-24%DD-24″ %YYYY-24%MM-24%DD-24>>>
是指用24小时前的年月日日志文件名,如access_log.20061206
SiteDomain=”www.zhangjianfeng.com”
HostAliases=”zhangjianfeng.com”
DefaultFile=”index.html”
DirData=”/home/cgi-bin/awstats/data/”
3.更新数据
perl awstats.pl -config=mysite -update
4.配置apache
# Directives to allow use of AWStats as a CGI
Alias /awstatsclasses “/app/awstats-6.5/wwwroot/classes/”
Alias /awstatscss “/app/awstats-6.5/wwwroot/css/”
Alias /awstatsicons “/app/awstats-6.5/wwwroot/icon/”
ScriptAlias /awstats/ “/app/awstats-6.5/wwwroot/cgi-bin/”
<Directory “/app/awstats-6.5/wwwroot”>
Options None
AllowOverride None
Order allow,deny
Allow from all
</Directory>
5.对要分析的虚拟主机, 将CustomLog logs/access_xxx_log >>>
<<<common中的common改成combined
6. 重启apache,如果虚拟主机或目录配置好了,
就http://server/awstats/awstats.pl?config=mysite
7.添加定时分析指令
crontab -e
* */1 * * * (cd /path/to/apache/cgi-bin/; ./awstats.pl >>>
<<<-update -config=blog.zhangjianfeng.com)
8.直接分析gunzip压过的log
查了一下,如果是gz格式的压缩包,可以在配置文件中参考如下格式修改:
LogFile=”gzip -d [...]
如何编写兼容各主流邮箱的HTML邮件
1、全局规则之一,不要写<style>标签、不要写class,所有CSS都用style属性,什么元素需要什么样式就用style写内联的CSS。
2、全局规则之二,少用图片,邮箱不会过滤你的img标签,但是系统往往会默认不载入陌生来信的图片,如果用了很多图片的邮件,在片没有载入的情况下,丑陋无比甚至看不清内容,没耐心的用户直接就删除了。图片上务必加上alt。
3、不要在style里面写float、position这些style,因为会被过滤。那么如何实现左右布局或者更复杂的布局呢?用table。
4、 style内容里面background可以设置color,但是img会被过滤,就是说不能通过CSS来设置背景图片了。但是有一个很有意思的元素属 性,也叫background,里面可以定义一个图片路径,这是个不错的替代方案,虽然这样功能有限,比如无法定位背景图片了,有总比没有好。例如要给一 个单元格加一个背景,必须这样写:
5、div模式的邮箱不支持flash,iframe模式的有待验证。
MySQL4.1以上版本字符集
MySQL 4.1开始,对多语言的支持有了很大变化 (这导致了问题的出现)。尽管大部分的地方 (包括个人使用和主机提供商),MySQL 3、4.0 仍然占主导地位;但 MySQL 4.1 乃至5.0是 MySQL 官方推荐的数据库,已经有主机提供商开始提供并将会越来越多;因为 latin1 在许多地方 (下边会详细描述具体是哪些地方) 作为默认的字符集,成功的蒙蔽了许多 PHP 程序的开发者和用户,掩盖了在中文等语言环境下会出现的问题。
MySQL 4.1开始把多国语言字符集分的更加详细,所以导致数据库迁移,或则dz论坛升级到4.0后(dz4.0开始使用gbk或utf-8编码)出现乱码问题。
MySQL 4.1的字符集支持(Character Set Support)有两个方面:字符集(Character set)和排序方式(Collation)。对于字符集的支持细化到四个层次: 服务器(server),数据库(database),数据表(table)和连接(connection)。
查看系统的字符集和排序方式的设定可以通过下面的两条命令:
QUOTE:
mysql> SHOW VARIABLES LIKE ‘character_set_%’;
+————————–+—————————-+
| Variable_name | Value |
+————————–+—————————-+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_results | latin1 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| [...]
从LiveJournal后台发展看大规模网站性能优化方法
一、LiveJournal发展历程
LiveJournal是99年始于校园中的项目,几个人出于爱好做了这样一个应用,以实现以下功能:
博客,论坛
社会性网络,找到朋友
聚合,把朋友的文章聚合在一起
LiveJournal采用了大量的开源软件,甚至它本身也是一个开源软件。在上线后,LiveJournal实现了非常快速的增长:
2004年4月份:280万注册用户。
2005年4月份:680万注册用户。
2005年8月份:790万注册用户。
达到了每秒钟上千次的页面请求及处理。
使用了大量MySQL服务器。
使用了大量通用组件。
二、LiveJournal架构现状概况
三、从LiveJournal发展中学习
LiveJournal从1台服务器发展到100台服务器,这其中经历了无数的伤痛,但同时也摸索出了解决这些问题的方法,通过对LiveJournal的学习,可以让我们避免LJ曾经犯过的错误,并且从一开始就对系统进行良好的设计,以避免后期的痛苦。
下面我们一步一步看LJ发展的脚步。
1、一台服务器
一 台别人捐助的服务器,LJ最初就跑在上面,就像Google开始时候用的破服务器一样,值得我们尊敬。这个阶段,LJ的人以惊人的速度熟悉的Unix的操 作管理,服务器性能出现过问题,不过还好,可以通过一些小修小改应付过去。在这个阶段里LJ把CGI升级到了FastCGI。
最终问题出现了,网站越来越慢,已经无法通过优过化来解决的地步,需要更多的服务器,这时LJ开始提供付费服务,可能是想通过这些钱来购买新的服务器,以解决当时的困境。
毫无疑问,当时LJ存在巨大的单点问题,所有的东西都在那台服务器的铁皮盒子里装着。
2、两台服务器
用付费服务赚来的钱LJ买了两台服务器:一台叫做Kenny的Dell 6U机器用于提供Web服务,一台叫做Cartman的Dell 6U服务器用于提供数据库服务。
LJ有了更大的磁盘,更多的计算资源。但同时网络结构还是非常简单,每台机器两块网卡,Cartman通过内网为Kenny提供MySQL数据库服务。
暂时解决了负载的问题,新的问题又出现了:
原来的一个单点变成了两个单点。
没有冷备份或热备份。
网站速度慢的问题又开始出现了,没办法,增长太快了。
Web服务器上CPU达到上限,需要更多的Web服务器。
3、四台服务器
又买了两台,Kyle和Stan,这次都是1U的,都用于提供Web服务。目前LJ一共有3台Web服务器和一台数据库服务器。这时需要在3台Web服务器上进行负载均横。
LJ把Kenny用于外部的网关,使用mod_backhand进行负载均横。
然后问题又出现了:
单点故障。数据库和用于做网关的Web服务器都是单点,一旦任何一台机器出现问题将导致所有服务不可用。虽然用于做网关的Web服务器可以通过保持心跳同步迅速切换,但还是无法解决数据库的单点,LJ当时也没做这个。
网站又变慢了,这次是因为IO和数据库的问题,问题是怎么往应用里面添加数据库呢?
4、五台服务器
又买了一台数据库服务器。在两台数据库服务器上使用了数据库同步(Mysql支持的Master-Slave模式),写操作全部针对主数据库(通过Binlog,主服务器上的写操作可以迅速同步到从服务器上),读操作在两个数据库上同时进行(也算是负载均横的一种吧)。
实现同步时要注意几个事项:
读操作数据库选择算法处理,要选一个当前负载轻一点的数据库。
在从数据库服务器上只能进行读操作
准备好应对同步过程中的延迟,处理不好可能会导致数据库同步的中断。只需要对写操作进行判断即可,读操作不存在同步问题。
5、更多服务器
有钱了,当然要多买些服务器。部署后快了没多久,又开始慢了。这次有更多的Web服务器,更多的数据库服务器,存在 IO与CPU争用。于是采用了BIG-IP作为负载均衡解决方案。
6、现在我们在哪里:
现在服务器基本上够了,但性能还是有问题,原因出在架构上。
数据库的架构是最大的问题。由于增加的数据库都是以Slave模式添加到应用内,这样唯一的好处就是将读操作分布到了多台机器,但这样带来的后果就是写操作被大量分发,每台机器都要执行,服务器越多,浪费就越大,随着写操作的增加,用于服务读操作的资源越来越少。
由一台分布到两台
最终效果
现在我们发现,我们并不需要把这些数据在如此多的服务器上都保留一份。服务器上已经做了RAID,数据库也进行了备份,这么多的备份完全是对资源的浪费,属于冗余极端过度。那为什么不把数据分布存储呢?
问题发现了,开始考虑如何解决。现在要做的就是把不同用户的数据分布到不同的服务器上进行存储,以实现数据的分布式存储,让每台机器只为相对固定的用户服务,以实现平行的架构和良好的可扩展性。
为 了实现用户分组,我们需要为每一个用户分配一个组标记,用于标记此用户的数据存放在哪一组数据库服务器中。每组数据库由一个master及几个slave 组成,并且slave的数量在2-3台,以实现系统资源的最合理分配,既保证数据读操作分布,又避免数据过度冗余以及同步操作对系统资源的过度消耗。
由一台(一组)中心服务器提供用户分组控制。所有用户的分组信息都存储在这台机器上,所有针对用户的操作需要先查询这台机器得到用户的组号,然后再到相应的数据库组中获取数据。
这样的用户架构与目前LJ的架构已经很相像了。
在具体的实现时需要注意几个问题:
在数据库组内不要使用自增ID,以便于以后在数据库组之间迁移用户,以实现更合理的I/O,磁盘空间及负载分布。
将userid,postid存储在全局服务器上,可以使用自增,数据库组中的相应值必须以全局服务器上的值为准。全局服务器上使用事务型数据库InnoDB。
在数据库组之间迁移用户时要万分小心,当迁移时用户不能有写操作。
7、现在我们在哪里
问题:
一个全局主服务器,挂掉的话所有用户注册及写操作就挂掉。
每个数据库组一个主服务器,挂掉的话这组用户的写操作就挂掉。
数据库组从服务器挂掉的话会导致其它服务器负载过大。
对于Master-Slave模式的单点问题,LJ采取了Master-Master模式来解决。所谓Master-Master实际上是人工实现的,并不是由MySQL直接提供的,实际上也就是两台机器同时是Master,也同时是Slave,互相同步。
Master-Master实现时需要注意:
一个Master出错后恢复同步,最好由服务器自动完成。
数字分配,由于同时在两台机器上写,有些ID可能会冲突。
解决方案:
奇偶数分配ID,一台机器上写奇数,一台机器上写偶数
通过全局服务器进行分配(LJ采用的做法)。
Master-Master模式还有一种用法,这种方法与前一种相比,仍然保持两台机器的同步,但只有一台机器提供服务(读和写),在每天晚上的时候进行轮换,或者出现问题的时候进行切换。
8、现在我们在哪里
现在插播一条广告,MyISAM VS InnoDB。
使用InnoDB:
支持事务
需要做更多的配置,不过值得,可以更安全的存储数据,以及得到更快的速度。
使用MyISAM:
记录日志(LJ用它来记网络访问日志)
存储只读静态数据,足够快。
并发性很差,无法同时读写数据(添加数据可以)
MySQL非正常关闭或死机时会导致索引错误,需要使用myisamchk修复,而且当访问量大时出现非常频繁。
9、缓存
去年我写过一篇文章介绍memcached,它就是由LJ的团队开发的一款缓存工具,以key-value的方式将数据存储到分布的内存中。LJ缓存的数据:
12台独立服务器(不是捐赚的)
28个实例
30GB总容量
90-93%的命中率(用过squid的人可能知道,squid内存加磁盘的命中率大概在70-80%)
如何建立缓存策略?
想缓存所有的东西?那是不可能的,我们只需要缓存已经或者可能导致系统瓶颈的地方,最大程度的提交系统运行效率。通过对MySQL的日志的分析我们可以找到缓存的对象。
缓存的缺点?
没有完美的事物,缓存也有缺点:
增大开发量,需要针对缓存处理编写特殊的代码。
管理难度增加,需要更多人参与系统维护。
当然大内存也需要钱。
10、Web访问负载均衡
在数据包级别使用BIG-IP,但BIG-IP并不知道我们内部的处理机制,无法判断由哪台服务器对这些请求进行处理。反向代理并不能很好的起到作用,不是已经够快了,就是达不到我们想要的效果。
所以,LJ又开发了Perlbal。特点:
快,小,可管理的http web 服务器/代理
可以在内部进行转发
使用Perl开发
单线程,异步,基于事件,使用epoll , kqueue
支持Console管理与http远程管理,支持动态配置加载
多种模式:web服务器,反向代理,插件
支持插件:GIF/PNG互换?
11、MogileFS
LJ使用开源的MogileFS作为分布式文件存储系统。MogileFS使用非常简单,它的主要设计思想是:
文件属于类(类是最小的复制单位)
跟踪文件存储位置
在不同主机上存储
使用MySQL集群统一存储分布信息
大容易廉价磁盘
到目前为止就这么多了,更多文档可以在http://www.danga.com/words/找到。Danga.com和LiveJournal.com的 同学们拿这个文档参加了两次MySQL Con,两次OS Con,以及众多的其它会议,无私的把他们的经验分享出来,值得我们学习。在web2.0时代快速开发得到大家越来越多的重视,但良好的设计仍是每一个应 用的基础,希望web2.0们在成长为Top500网站的路上,不要因为架构阻碍了网站的发展。
参考资料:http://www.danga.com/words/2005_oscon/oscon-2005.pdf
