2008年11月17日星期一

告诉搜索引擎你的Sitemap更新了

当Sitemap随着网站的更新增加了内容,如何最快的让搜索引擎知道而不是坐等蜘蛛光临呢?当然最好的办法就是告诉搜索引擎你的Sitemap更新了,就等你放蜘蛛过来了!

如何告诉搜索引擎?用他们开放的Ping功能。

遗憾的是国内搜索引擎对Sitemap都不感兴趣,更别说Ping了,所以中文站可能效果有限。

下面几个地址是老乐搜集过来的,大家可以照此格式将其中Sitemap完整地址换成你自己的,Ping一下搜索引擎,告诉你的Sitemap更新。

Google:http://www.google.com/webmasters/sitemaps/ping?sitemap=XML文件完整地址

Yahoo:http://api.search.yahoo.com/SiteExplorerService/V1/updateNotification?appid=YahooDemo&url=XML文件完整地址

Live:http://webmaster.live.com/ping.aspx?siteMap=XML文件完整地址

Ask:http://submissions.ask.com/ping?sitemap=XML文件完整地址

Moreover:http://api.moreover.com/ping?u=XML文件完整地址

可惜,主流中文搜索引擎对Sitemap不感冒,支持Sitemap的搜索引擎市场份额又上不去。

2008年11月15日星期六

Using the robots meta tag

Recently, Danny Sullivan brought up good questions about how search engines handle meta tags. Here are some answers about how we handle these tags at Google.

Multiple content values
We recommend that you place all content values in one meta tag. This keeps the meta tags easy to read and reduces the chance for conflicts. For instance:

<meta name="ROBOTS" content="NOINDEX, NOFOLLOW">

If the page contains multiple meta tags of the same type, we will aggregate the content values. For instance, we will interpret

<meta name="ROBOTS" content="NOINDEX">
<meta name="ROBOTS" content="NOFOLLOW">

The same way as:

<meta name="ROBOTS" content="NOINDEX, NOFOLLOW">

If content values conflict, we will use the most restrictive. So, if the page has these meta tags:

<meta name="ROBOTS" content="NOINDEX">
<meta name="ROBOTS" content="INDEX">

We will obey the NOINDEX value.

Unnecessary content values
By default, Googlebot will index a page and follow links to it. So there's no need to tag pages with content values of INDEX or FOLLOW.

Directing a robots meta tag specifically at Googlebot
To provide instruction for all search engines, set the meta name to "ROBOTS". To provide instruction for only Googlebot, set the meta name to "GOOGLEBOT". If you want to provide different instructions for different search engines (for instance, if you want one search engine to index a page, but not another), it's best to use a specific meta tag for each search engine rather than use a generic robots meta tag combined with a specific one. You can find a list of bots at robotstxt.org.

Casing and spacing
Googlebot understands any combination of lowercase and uppercase. So each of these meta tags is interpreted in exactly the same way:

<meta name="ROBOTS" content="NOODP">
<meta name="robots" content="noodp">
<meta name="Robots" content="NoOdp">

If you have multiple content values, you must place a comma between them, but it doesn't matter if you also include spaces. So the following meta tags are interpreted the same way:

<meta name="ROBOTS" content="NOINDEX, NOFOLLOW">
<meta name="ROBOTS" content="NOINDEX,NOFOLLOW">

If you use both a robots.txt file and robots meta tags
If the robots.txt and meta tag instructions for a page conflict, Googlebot follows the most restrictive. More specifically:
  • If you block a page with robots.txt, Googlebot will never crawl the page and will never read any meta tags on the page.
  • If you allow a page with robots.txt but block it from being indexed using a meta tag, Googlebot will access the page, read the meta tag, and subsequently not index it.
Valid meta robots content values
Googlebot interprets the following robots meta tag values:
  • NOINDEX - prevents the page from being included in the index.
  • NOFOLLOW - prevents Googlebot from following any links on the page. (Note that this is different from the link-level NOFOLLOW attribute, which prevents Googlebot from following an individual link.)
  • NOARCHIVE - prevents a cached copy of this page from being available in the search results.
  • NOSNIPPET - prevents a description from appearing below the page in the search results, as well as prevents caching of the page.
  • NOODP - blocks the Open Directory Project description of the page from being used in the description that appears below the page in the search results.
  • NONE - equivalent to "NOINDEX, NOFOLLOW".
A word about content value "NONE"
As defined by robotstxt.org, the following direction means NOINDEX, NOFOLLOW.

<meta name="ROBOTS" content="NONE">

However, some webmasters use this tag to indicate no robots restrictions and inadvertently block all search engines from their content.

2008年11月11日星期二

美国新当选总统奥巴马获胜演讲全文

以下是奥巴马(Barack Obama)为今晚在芝加哥演讲准备的讲稿:

如果还有人对美国是否凡事都有可能存疑,还有人怀疑美国奠基者的梦想在我们所处的时代是否依然鲜活,还有人质疑我们的民主制度的力量,那么今晚,这些问题都有了答案。

这是设在学校和教堂的投票站前排起的前所未见的长队给出的答案;是等了三四个小时的选民所给出的答案,其中许多人都是有生以来第一次投票,因为他们认定这一次肯定会不一样,认为自己的声音会是这次大选有别于以往之所在。

这是所有美国人民共同给出的答案--无论老少贫富,无论是民主党还是共和党,无论是黑人、白人、拉美裔、亚裔、原住民,是同性恋者还是异性恋者、残疾人还是健全人--我们从来不是“红州”和“蓝州”的对立阵营,我们是美利坚合众国这个整体,永远都是。

长久以来,很多人一再受到告诫,要对我们所能取得的成绩极尽讽刺、担忧和怀疑之能事,但这个答案让这些人伸出手来把握历史,再次让它朝向美好明天的希望延伸。

已经过去了这么长时间,但今晚,由于我们在今天、在这场大选中、在这个具有决定性的时刻所做的,美国已经迎来了变革。

我 刚刚接到了麦凯恩参议员极具风度的致电。他在这场大选中经过了长时间的努力奋斗,而他为自己所深爱的这个国家奋斗的时间更长、过程更艰辛。他为美国做出了 我们大多数人难以想像的牺牲,我们的生活也因这位勇敢无私的领袖所做出的贡献而变得更美好。我向他和佩林州长所取得的成绩表示祝贺,我也期待着与他们一起 在未来的岁月中为复兴这个国家的希望而共同努力。

我要感谢我在这次旅程中的伙伴--已当选美国副总统的拜登。他全心参与竞选活动,为普通民众代言,他们是他在斯克兰顿从小到大的伙伴,也是在他回特拉华的火车上遇到的男男女女。

如 果没有一个人的坚决支持,我今晚就不会站在这里,她是我过去16年来最好的朋友、是我们一家人的中坚和我一生的挚爱,更是我们国家的下一位第一夫人:米歇 尔•奥巴马(Michelle Obama)。萨莎(Sasha)和玛丽亚(Malia),我太爱你们两个了,你们已经得到了一条新的小狗,它将与我们一起入驻白宫。虽然我的外祖母已经 不在了,但我知道她与我的亲人肯定都在看着我,因为他们,我才能拥有今天的成就。今晚,我想念他们,我知道自己欠他们的无可计量。

我的竞选经理大卫•普劳夫(David Plouffe)、首席策略师大卫•艾克斯罗德(David Axelrod)以及政治史上最好的竞选团队--是你们成就了今天,我永远感激你们为实现今天的成就所做出的牺牲。

但最重要的是,我永远不会忘记这场胜利真正的归属--它属于你们。

我从来不是最有希望的候选人。一开始,我们没有太多资金,也没有得到太多人的支持。我们的竞选活动并非诞生于华盛顿的高门华第之内,而是始于得梅因、康科德、查尔斯顿这些地方的普通民众家中。

我 们的竞选活动能有今天的规模,是因为辛勤工作的人们从自己的微薄积蓄中拿出钱来,捐出一笔又一笔5美元、10美元、20美元。而竞选活动的声势越来越大则 是源自那些年轻人,他们拒绝接受认为他们这代人冷漠的荒诞说法;他们离开家、离开亲人,从事报酬微薄、极其辛苦的工作;同时也源自那些已经不算年轻的人 们,他们冒着严寒酷暑,敲开陌生人的家门进行竞选宣传;更源自数百万的美国民众,他们自动自发地组织起来,证明了在两百多年以后,民有、民治、民享的政府 并未从地球上消失。这是你们的胜利。



我知道你们的所做所为并不只是为了赢得大选,我也知道你们做这一切并不是为了 我。你们这样做是因为你们明白摆在面前的任务有多艰巨。因为即便我们今晚欢呼庆祝,我们也知道明天将面临我们一生之中最为艰巨的挑战--两场战争、一个面 临危险的星球,还有百年来最严重的金融危机。今晚站在此地,我们知道伊拉克的沙漠里和阿富汗的群山中还有勇敢的美国士兵醒来,甘冒生命危险保护着我们。会 有在孩子熟睡后仍难以入眠的父母,担心如何偿还按揭月供、付医药费或是存够钱送孩子上大学。我们亟待开发新能源、创造新的工作机会;我们需要修建新学校, 还要应对众多威胁、修复与许多国家的关系。

前方的道路会十分漫长艰辛。我们可能无法在一年甚至一届任期之内实现上述目标,但我从未像今晚这样满怀希望,相信我们会实现。我向你们承诺--我们作为一个整体将会达成目标。

我 们会遭遇挫折和不成功的开端。对于我作为总统所做的每项决定和政策,会有许多人持有异议,我们也知道政府并不能解决所有问题。但我会向你们坦陈我们所面临 的挑战。我会聆听你们的意见,尤其是在我们意见相左之时。最重要的是,我会请求你们参与重建这个国家,以美国221年来从未改变的唯一方式--一砖一瓦、 胼手胝足。

21个月前那个寒冬所开始的一切不应该在今天这个秋夜结束。今天的选举胜利并不是我们所寻求的改变--这只是我们进行改变的机会。而且如果我们仍然按照旧有方式行事,我们所寻求的改变不可能出现。没有你们,也不可能有这种改变。

因此,让我们发扬新的爱国精神,树立新的服务意识和责任感,让我们每个人下定决心全情投入、更加努力地工作,并彼此关爱。让我们铭记这场金融危机带来的教训:我们不可能在金融以外的领域备受煎熬的同时拥有繁荣兴旺的华尔街--在这个国家,我们患难与共。

让 我们抵制重走老路的诱惑,避免重新回到令美国政治长期深受毒害的党派纷争和由此引发的遗憾和不成熟表现。让我们牢记,正是伊利诺伊州的一名男子首次将共和 党的大旗扛到了白宫。共和党是建立在自强自立、个人自由以及全民团结的价值观上,这也是我们所有人都珍视的价值。虽然民主党今天晚上赢得了巨大的胜利,但 我们是以谦卑的态度和弥合阻碍我们进步的分歧的决心赢得这场胜利的。林肯在向远比我们眼下分歧更大的国家发表讲话时说,我们不是敌人,而是朋友……虽然激 情可能褪去,但是这不会割断我们感情上的联系。对于那些现在并不支持我的美国人,我想说,或许我没有赢得你们的选票,但是我听到了你们的声音,我需要你们 的帮助,而且我也将是你们的总统。

那些彻夜关注美国大选的海外人士,从国会到皇宫,以及在这个世界被遗忘的角落里挤在收音机旁的人 们,我们的经历虽然各有不同,但是我们的命运是相通的,新的美国领袖诞生了。那些想要颠覆这个世界的人们,我们必将击败你们。那些追求和平和安全的人们, 我们支持你们。那些所有怀疑美国能否继续照亮世界发展前景的人们,今天晚上我们再次证明,我们国家真正的力量并非来自我们武器的威力或财富的规模,而是来 自我们理想的持久力量:民主、自由、机会和不屈的希望。

这才是美国真正的精华--美国能够改变。我们的联邦会日臻完善。我们取得的成就为我们将来能够取得的以及必须取得的成就增添了希望。



这次大选创造了多项“第一”,也诞生了很多将世代流传的故事。但是今天晚上令我难忘的却是在亚特兰大投票的一名妇女:安•尼克松•库波尔(Ann Nixon Cooper)。她和其他数百万排队等待投票的选民没有什么差别,除了一点:她已是106岁的高龄。


她出生的那个时代奴隶制度刚刚结束;那时路上没有汽车,天上也没有飞机;当时像她这样的人由于两个原因不能投票--一是她是女性,另一个原因是她的肤色。

今天晚上,我想到了她在美国过去一百年间所经历的种种:心痛和希望;挣扎和进步;那些我们被告知我们办不到的世代,以及那些坚信美国信条──是的,我们能做到──的人们。

曾几何时,妇女没有发言权,她们的希望化作泡影,但是安•尼克松•库波尔活了下来,看到妇女们站了起来,看到她们大声发表自己的见解,看到她们去参加大选投票。是的,我们能做到。

当30年代的沙尘暴和大萧条引发人们的绝望之情时,她看到一个国家用罗斯福新政、新就业机会以及对新目标的共同追求战胜恐慌。是的,我们能做到。

当炸弹袭击了我们的海港、独裁专制威胁到全世界,她见证了美国一代人的伟大崛起,见证了一个民主国家被拯救。是的,我们能做到。

她看到蒙哥马利通了公共汽车、伯明翰接上了水管、塞尔马建了桥,一位来自亚特兰大的传教士告诉人们:我们能成功。是的,我们能做到。

人类登上月球、柏林墙倒下,世界因我们的科学和想像被连接在一起。今年,就在这次选举中,她用手指触碰屏幕投下自己的选票,因为在美国生活了106年之后,经历了最好的时光和最黑暗的时刻之后,她知道美国如何能够发生变革。是的,我们能做到。

美国,我们已经走过漫漫长路。我们已经历了很多。但是我们仍有很多事情要做。因此今夜,让我们自问--如果我们的孩子能够活到下个世纪;如果我们的女儿有幸活得和安一样长,他们将会看到怎样的改变?我们将会取得怎样的进步?

现 在是我们回答这个问题的机会。这是我们的时刻。这是我们的时代--让我们的人民重新就业,为我们的后代敞开机会的大门;恢复繁荣发展,推进和平事业;让 “美国梦”重新焕发光芒,再次证明这样一个基本的真理:我们是一家人;一息尚存,我们就有希望;当我们遇到嘲讽和怀疑,当有人说我们办不到的时候,我们要 以这个永恒的信条来回应他们:

是的,我们能做到。感谢你们。上帝保佑你们。愿上帝保佑美利坚合众国。

Barack Obama

2008年11月9日星期日

揭秘“重复内容处罚”

转载自谷歌中文网站管理员博客
发表者:Susan Moskwa, 网站管理员趋势研究员

原文:Demystifying the“duplicate content penalty”
发表于:2008 年 9 月 12 日星期五,上午 8: 30

重复内容始终是一个经常被谈论的话题。我们不断地发表关于这方面文章,人们也在不断地提出问题。特别是,我还听到有很多网站管理员担心自己受到了“重复内容处罚”。

在这里请允许我们把这个问题一次性跟大家讲清楚:根本不存在所谓的“重复内容处罚”。至少,也不是大多数人谈论时所认为的那样。

有一些处罚是和抄袭其他网站的内容有关的,比如完全抄袭并且发布其他网站的内容,或者在完全没有提供任何其他附加价值的情况下发布这些抄袭的内容。这些都是我们不提倡的做法,您可以在网站管理员指南里找到有关此问题的清晰的论述:

* 请不要创建含有大量重复内容的多个页面、子域或者域。
* 请避免使用那种“一个模子印出来”(cookie cutter)的方式创建网站,比如没有或者很少原创内容的联属计划。
* 如果您的网站参与联属计划,请确保您的网站可提供附加价值。提供独特且相关的内容,使用户首先有理由访问您的网站。

(请注意,我们不希望您从其他网站那里抄袭内容,但是如果其他人抄袭了您的网站就是另外一回事了;如果您担心别人抄袭了您的网站,请您参考这篇文章)。

但 是我听到的一些担心重复性内容的网站管理员所谈论的并不是抄袭或者域名农场(domain farms);他们讨论的是诸如在同一个域上有多个网址指向相同的内容。比如,www.example.com/skates.asp?color= black&brand=riedell
和www.example.com/skates.asp?brand=riedell&color=black。这种类型的重复性内容可能会对您网站在搜索结果中的表现有潜在的影响,但是它不会使您的网站受到惩罚。下面这段文字来自我们关于重复内容的帮助文章:

除非重复内容看起来意在欺骗用户并操纵搜索引擎结果,否则,我们不会对有重复内容的网站采取特别措施。如果您的网站存在重复内容问题,而您又未遵循上述建议,我们会自行以恰当的方式选择在搜索结果中显示的内容版本。

这种非恶意的重复是比较常见的,特别是很多内容管理系统(CMS)缺省条件下对此处理的并不是很好。因此,当人们谈到此种类型的重复性内容会影响您的网站时,并不是因为您可能会因此受到处罚,而仅仅是由于网站和搜索引擎的工作方式所造成的。

大多数搜索引擎都力求保持一定程度的多样性:他们想在搜索结果页上向您展示十个不同的搜索结果,而不是含有相同内容的十个不同的网址。为此,谷歌试着去掉重复的内容从而使用户较少看到这些多余的重复性的内容。您可以在这篇博客里了解更多的细节,其中谈到

1. 当我们探测重复内容时,比如由网址参数造成的衍生网址,我们会将这些相似的网址放在同一组里。
2. 我们会选择我们认为最能代表这一组的网址在搜索结果里进行展示。
3. 我们还会对这一组网址的特性进行相应的整理,像链接的受欢迎程度,并将其合并到此代表性网址上。

作为网站管理员,上述过程可能会影响到您的是:

* 在步骤二中,谷歌所认为最具有代表性的网址并不一定和您的想法一致。如果您想控制究竟是 www.example.com/skates.asp?color=black&brand=riedell 还是www.example.com/skates.asp?brand=riedell&color=black出现在我们的搜索结果中的话, 您或许想采取适当措施以减少您的重复内容。告诉我们哪一个是您比较喜欢的网址的有效方法之一就是将其列入您的网站地图(Sitemap) 里。
* 在步骤三中,如果我们无法探测出某一特定页面的所有重复性页面的话,我们在对其页面特性进行整合时就不可能包括所有这些重复性页面的特性。这可能会削弱这一特定内容的排名竞争力,因为他们被分散分配到了多个网址上。

在 大多数情况下,谷歌可以很好的处理此类重复内容。然而,对于那些不同域名上的重复性内容,您或许需要再考虑一下。尤其是,当您决定建立一个网站而它的目的 从本质上来讲就是内容抄袭和重复的话,如果您的商业模式又依赖于搜索引擎的流量,那么除非您可以给用户带来很多的附加价值,不然对于建立此类网站您还是要 三思而后行。举个例子,我们有时听到来自 Amazon.com 的联盟网站说他们网站上那些完全由 Amazon 提供的内容很难有好的排名。这难道是因为谷歌想阻止他们卖《Everyone Poops》 这本书吗?不;这是因为如果他们的网站提供完全一样的内容的话,他们怎么可能会比 Amazon 的排名更好呢?对于在线购物来讲,Amazon 在很多方面具有权威性(对于一个典型的 Amazon 联盟网站来说更是如此),一般的谷歌搜索用户可能想看到的是 Amazon 上的原始信息,除非这个联盟网站提供了相当数量的、额外的附加值给用户。

最 后,想一下重复内容给您网站带宽带来的影响吧。重复内容会造成抓取效率低下:当 Googlebot 在您的网站上发现了十个网址,在它知道这些网址含有完全相同的内容之前(如上所述,也就是在我们能够对他们进行归类之前),它必须对这十个网址逐一进行抓 取。Googlebot 耗费在抓取重复性内容上的时间和资源越多,它用来抓取其他内容的时间也就相对变少了。

总而言之,网站上的重复性内容会以多种方式影响您的网站。但是除非您是恶意抄袭造成内容重复,否则这些方式不会构成对您网站的处罚。这也意味着:

* 当您清除了无恶意的重复性内容时,您无须提交重新收录的请求。
* 如果您是一个介于初级到中级经验值之间的网络管理员,您可能不需花费过多精力来担心重复性内容,因为大多数搜索引擎都有方法来处理它。
* 通过澄清和杜绝关于重复性内容处罚的杜撰之说,您可以帮到您的网站管理员同行们!解决重复性内容的方法完全在您的掌控之中,这里有几篇较好的文章您可以参考

2008年11月8日星期六

网页栅格系统研究(3):粒度问题

研究(2)中讨论了栅格系统的基础知识。这一篇将集中探讨栅格系统的粒度问题。(注:如非特别指明,栅格系统均指24列960栅格系统) 淘宝的首页目前尚未严格遵守栅格系统,如果重构的话,宽度方向可以考虑采用下面的栅格布局(只考虑页面主体部分,忽略高度的比例):

(图1)

纷乱的高度世界

我们来看下图1左上角。左上角部分目前的宽度为256px, 重构的话可以将宽度缩小到230px以符合栅格(不可避免的要调整内容,比如人气宝贝中将只能放下3张图片)。来仔细看下高度方向:

(图2)
高度方向的布局是:90 : 117 : 100, 第一个间隔是8, 总高度为325. 很明显,高度方向没有任何栅格化的迹象。实际上,

即便是严格遵守栅格系统的Yahoo!首页,高度方向上也没有严格栅格化。

这究竟是为何?

一切皆有可能

我们缩小关注点:

(图3)
上图中,图像的大小是70 x 70, 刚好是24列960栅格系统两列的宽度。对于右边的文字,采取了如下样式:
font-size: 12px;
line-height: 150%; /* 12 x 150% = 18px */

中文字体是宋体,line-height的计算值是18px. 注意图3中文字部分可视区域的高度为65, 上下各有4px和1px的间隙。为什么会产生这么奇怪的间隙呢?我们来看下图:

(图4)
从上图中我们可以得知,12px的宋体中文字,实际高度只有11px. line-height减去11多出来的高度,则“均匀”分布在上下间隙中(如果多出来的高度为偶数,则上下均分;为奇数时,上面比下面多1px)。这样,对于70px的高度来说,要布局4行文字时,假设行高多出来的上半部分为x, 下半部分为y, 在最理想的情况下,应该满足以下公式:

11 * 4 + 4 * x + 3 * y = 70

x = y 或 x = y + 1

不难推出,x最理想的整数解为4. 从而line-height为 4 + 11 + 3 = 18. 因此:

对于24列960栅格系统来说,如果要在高度方向上实现栅格,font-size为12px时,line-height的最佳取值是18px(150%).

追求完美点话,还可以将文字部分margin-top: -1px, 使得65上下的间隙为3和2.

至此,我们可以初步判断:

高度方向上是有可能严格栅格化的。一切皆有可能!

然而,现实总那么残酷


(图5)
上图中的标题高度为22, 这在24列960栅格系统中是无法对齐的。而且总高度为100, 在24列960栅格系统中也不存在(110才可以)。或许高度方向上我们可以细化行宽为20, 但依旧没法解决上面两个问题(22是明显不能解决的,而对于100px的高度,也无法通过细化行宽来解决。可选高度永远是10的奇数倍,如果进一步细化, 小于10后,会变得非常繁琐,没什么实际应用价值)

宽度世界里会好些吗


(图6)
上面是Yahoo!首页上的两个小模块,我都不想去标注模块里面的布局宽度了(因为一点都不符合24列960栅格系统)。宽度世界里,和高度世界一样充满希望但现实却残酷无比。

银弹是不存在的

栅格系统是美好的。但如果我们一味地追求将所有设计都栅格化(必须承认我曾有这个幻想),则立刻会陷入地狱一般的黑暗中。这篇文章中的艰难尝试(我 分析了20多个小模块),让我突然醒悟到一个粒度问题:任何设计都有适用范围,超出最佳适用范围,强行使用只会带来无尽的烦恼。对于栅格系统(这里指所有 栅格系统,包括多种栅格系统混合使用的情景)来说,我觉得以下场景非常适合:

  1. 页面的总体宽度布局,比如两栏、三栏等布局
  2. 一些固定区块的尺寸,比如广告图片的尺寸
  3. 区块之间的间距,可以参考栅格系统的槽宽(Gutter)
  4. 一些可以栅格化的小区域,比如图3中的例子,暗合栅格往往能简化布局上的考虑

除了上面这些应用场景,强行使用栅格系统,往往会束手束脚,适得其反。这篇文章的目的,就是尝试用最啰嗦最费神貌似很科学实际很无聊的分析来指出栅 格系统应用时的粒度问题。在粒度问题上达成一致后,下一篇中我们将讨论栅格系统的技术实现,最后一篇则讨论栅格系统的压轴好戏:模块化开发。

2008年11月6日星期四

网页栅格系统研究(2):蛋糕的切法

首先澄清一个应用场景问题。研究(1)中指出,对于结构复杂的网站,不少设计师们喜欢采用960固定宽度布局。但要注意的是,960并不是万能钥匙,大部分网站没有也不需要栅格系统。Amazon采用的是宽度自适应布局,最大限度的呈现信息。Google更是简简单单,主题部分就一个列表。eBay的页面非常简洁,商品页面宽度自适应,信息自然流畅,噪音少,购物很踏实。类似的站点还有很多,对于这些站点来说,宽度自适应布局更受青睐。

有个很有意思的网站是Yahoo!, 看起来是固定宽度布局,实际上在CSS中只要去掉一行,就能摇身一变自适应宽度了:

#page {
width: 70em;
}

为什么Yahoo!最后选择了定宽布局呢?这很可能是因为定宽布局比宽度自适应布局更容易控制。对于结构复杂的网站来说,可维护性和可扩展性非常重要。Yahoo!是以信息展示为主的门户型网站,960的宽度对于信息的阅读比较友善(Joe Clark写了一篇屏幕阅读时有关行长的有趣文章)。种种因素使得Yahoo!最后采用了定宽布局(Tommy Olsson总结了每种布局设计的优缺点)。

这里将只关注定宽布局,适用的场景是搭建复杂的门户型网站。对于宽度自适应布局和相应的栅格系统,暂不讨论(根据实现的技术手段不同,宽度自适应布局又分为流体布局和弹性布局。我个人蛮喜欢弹性布局,以后有时间再研究)。

好了,已经将范围缩小到定宽布局的网页栅格系统,那我们开始吧。

并不遥远的750

还记得800×600的显示器不?虽然才时隔几年,感觉却好像是上个世纪的事了。Mark Boulton做了最早的探索

将750分割成均等的6份,这就形成了栅格系统,稍加组合划分就形成了两栏布局和三栏布局。Mark Boulton还研究了Gutter(垂直栏之间的间隙)对栅格的影响,有兴趣的可以阅读原文,或者跟着我往下看吧,下面将详细阐述。

几个术语和一个公式

一个标准的栅格系统,包括以下部分:

将Flowline的总宽度标记为W, Column的宽度标记为c, Gutter宽度标记为g, Margin的宽度标记为m, Column的个数标记为N, 我们可以得到以下公式:
W = c * N + g * (N - 1) + 2 * m

一般来说,Gutter的宽度是Margin的两倍,上面的公式可以简化为:

W = c * N + g * (N - 1) + g = (c + g) * N

将c+g标记为C, 公式变得非常简单:

W = C * N

上面的公式就是栅格系统的基础,很简单吧。

950的来历

具体应用时,Margin其实是一个空白边,从视觉上看并不属于总宽度。不少栅格设计里习惯性地设定Gutter为10px, 这样Margin就是5px. 当W为960,分割成6列时,栅格如下图:

上图的处理是左右Margin各为5px. 也可以将Margin集中放在一边,比如右边:



无论Margin放在何处(这只影响技术实现,不影响设计),我们真正要关注的是去除Margin之后的部分:

这就是我们要真正关注的950!将W的含义变为去除Margin的总宽度,公式变化为:
W = N * C - g

将上面的公式实例化一下:

950 = 12 * 80 - 10
950 = 16 * 60 - 10
950 = 24 * 40 - 10

这就形成了960蛋糕的三种常见切法。

12 x 80

16 x 60

24 x 40

上面三种切法,N越大,灵活度越高。可以根据网页的实际复杂度来选用对应的切法。在960 Grid System首页中,展示了12 x 80的应用:

我们来看下 研究(1)中开头列举的网站的栅格应用情况。

Yahoo!是很标准的 24 x 40 栅格:

淘宝网目前只有商城上部分使用了栅格系统(大的两栏布局遵守了 24 x 40 的栅格化,主体部分使用的另一套740的栅格划分):

网易很不错,采用的是 16 x 60 的栅格系统:

研究(1)中的其它站点都没有真正严格地采用栅格系统。

栅格系统的优势

上面的“发现”是让人有点沮丧的。目前严格采用栅格系统的站点非常少,为什么我们还要努力的让网页栅格化呢?

栅格系统具有以下优势:

  1. 能大大提高网页的规范性。在栅格系统下,页面中所有组件的尺寸都是有规律的。这对于大型网站的开发和维护来说,能节约不少成本。
  2. 基于栅格进行设计,可以让整个网站各个页面的布局保持一致。这能增加页面的相似度,提升用户体验。
  3. 对于设计师们来说,灵活地运用栅格系统,能做出很多优秀和独特的设计。(详见《超越CSS》一书)

对于大型网站来说,我相信栅格化将是一种潮流和趋势。

下面讨论栅格系统中的黄金分割。

黄金分割

黄金分割可以归结为数学问题:对于长度为1的线段,将其分成两部分 x 和 1 - x, 使得:

x / 1 = (1 - x) / x

化为简单的二次方程:

x^2 + x - 1 = 0

正数解为:

x = (sqrt(5) - 1) / 2 ~= 0.618

这就是黄金分割。这个比例不仅仅出现在诸如绘画、雕塑、音乐、建筑等艺术领域,在管理、工程设计等方面也有着不可忽视的作用。 (这是个自然界的魔数,类似的还有真空光速、普朗克常数、精细结构等等,感兴趣的Google吧)

在平面设计领域,黄金分割点被广泛采用。比如下面这种图:

数一数上面有多少黄金分割? 对于960栅格,实际宽度是950. 两栏布局时,黄金分割为:

对于 24 x 40 的情景,最接近黄金分割的两栏布局是 350 : 590, 栏数比例为 9 : 15. 但实际使用时,因为窄栏经常用来做导航或放辅助信息,并不需要350px这么宽。因此实际情况下经常被采用的布局是:

上面讲的都是宽度方向上的栅格化,下面我们看看高度方向上如何应用。

高度方向上的栅格

还记得研究(1)中那张红红的很刺眼的图吗?注意高度值560也是很神奇的。

N(560) = N(2^4 * 5 * 7) = 18

560 / 960 ~= 0.583
N(560)比较大,同时可以让高宽比接近黄金分割。针对560, 我们采用 14 x 40 栅格:

这样,我们就在宽度和高度两个方向上都实现了栅格化。

下一篇将详细阐述960栅格系统的模块化应用。

网页栅格系统研究(1):960的秘密

研究网页栅格系统前,来看一组数据:

网站 首页页面宽度 px
Yahoo! 950
淘宝 950
MySpace 960
新浪 950
网易 960
Live Search 958
搜狐 950
优酷 960
AOL 960

上面列举的都是Alexa全球排名前100的站点,它们的首页宽度为950px/960px. 除了微软的Live Search, 这些站点有个共同特点:页面结构较复杂,都可以认为是门户型网站。

再来看看Google, YouTube, Facebook, Flickr!, eBay等知名站点,它们的首页宽度没什么固定规律,共同的特点是:功能专一,页面结构相对简单。

根据上面的简单分析可以认为:当搭建页面结构复杂的门户型网站时,开发工程师们不约而同地都选择将页面宽度定为950px/960px.

这是一件很有趣的事情,为什么要选择这个宽度呢?这个宽度值究竟有什么魔力

神奇的960

设计师们对苹果情有独衷。在 1024 x 768 的分辨率下,打开Firefox:


自然状态下,Firefox窗体的大小约为 974 x 650. 减掉左右两边7px的边框,网页的实际大小为上图中的红色部分,高宽为 960 x 650.

有趣的960就这样出现了。是的,可以认为一切就这么简单。栅格系统最早出现在平面设计领域,设计师们爱用苹果,苹果下浏览器的默认宽度为960px, 于是960就这么“自然”地出现了。

数字背后的奥妙

上面的“自然”出现,细究自然是不让人信服的。苹果系统的设计者们在没有喝醉酒的情况下选择了960,而不是其它什么1000之类的整数,自然另有奥妙。

科学界有很多问题都可以归结到数学问题上,我们也从数学着手:

960可以分解为2的6次方乘以3和5, 这使得960可以分割成以下宽度的整数倍:

2, 3, 4, 5, 6, 8, 10, 12, 15, 16, 20, 24, 30, 32, 40,
48, 60, 64, 80, 96, 120, 160, 192, 240, 320, 480

共26种(26 = 7 * 2 * 2 - 2, 减去2是去掉1和960自身),我们标记为:

N(960) = N(2^6 * 3 * 5) = 26

根据上面的算法,可以得到:

N(360) = N(2^3 * 3^2 * 5) = 22
N(480) = N(2^5 * 3 * 5) = 22
N(720) = N(2^4 * 3^2 * 5) = 28
N(750) = N(2 * 3 * 5^3) = 14
N(800) = N(2^5 * 5^2) = 16
N(960) = N(2^6 * 3 * 5) = 26
N(1000) = N(2^3 * 5^3) = 14
N(1024) = N(2^10) = 9
N(1440) = N(2^6 * 3^2 * 5) = 40
N(1920) = N(2^7 * 3 * 5) = 30

根据直觉(严格证明也不难,不过还是留给数学系的学生去证明吧),我们得到一个有趣的结论:

要使得N(width)最大,width的取值有两个系列:
A系列: …, 320, 720, 1440, …
B系列: …, 480, 960, 1920, …

N越大,可组合的宽度值就越多。对栅格系统来说,这意味着越灵活!

目前绝大多数显示器都支持 1024 x 768 及其以上分辨率。为了有效的利用屏幕宽度同时保证栅格的灵活度,可以看出960是非常合适的。这样,在目前主流显示器下,960就成为网页栅格系统中的最佳宽度了。(也许不久的将来,将会流行1440)

细心的你也许会记得,本文开头列举的宽度值中,950也出现了好几次。950是怎么来的?和960是啥关系?这些疑问,请关注本系列的下一篇文章。

2008年11月5日星期三

QQ游戏百万人同时在线服务器架构实现

QQ游戏于前几日终于突破了百万人同时在线的关口,向着更为远大的目标迈进,这让其它众多传统的棋牌休闲游戏平台黯然失色,相比之下,联众似乎已经根本不是QQ的对手,因为QQ除了这100万的游戏在线人数外,它还拥有3亿多的注册量(当然很多是重复注册的)以及QQ聊天软件900万的同时在线率,我们已经可以预见未来由QQ构建起来的强大棋牌休闲游戏帝国。


  那么,在技术上,QQ游戏到底是如何实现百万人同时在线并保持游戏高效率的呢?
  事实上,针对于任何单一的网络服务器程序,其可承受的同时连接数目是有理论峰值的,通过C++中对TSocket的定义类型:word,我们可以判定这个连接理论峰值是65535,也就是说,你的单个服务器程序,最多可以承受6万多的用户同时连接。但是,在实际应用中,能达到一万人的同时连接并能保证正常的数据交换已经是很不容易了,通常这个值都在2000到5000之间,据说QQ的单台服务器同时连接数目也就是在这个值这间。
  如果要实现2000到5000用户的单服务器同时在线,是不难的。在windows下,比较成熟的技术是采用IOCP--完成端口。与完成端口相关的资料在网上和CSDN论坛里有很多,感兴趣的朋友可以自己搜索一下。只要运用得当,一个完成端口服务器是完全可以达到2K到 5K的同时在线量的。但,5K这样的数值离百万这样的数值实在相差太大了,所以,百万人的同时在线是单台服务器肯定无法实现的。
  要实现百万人同时在线,首先要实现一个比较完善的完成端口服务器模型,这个模型要求至少可以承载2K到5K的同时在线率(当然,如果你MONEY多,你也可以只开发出最多允许100人在线的服务器)。在构建好了基本的完成端口服务器之后,就是有关服务器组的架构设计了。之所以说这是一个服务器组,是因为它绝不仅仅只是一台服务器,也绝不仅仅是只有一种类型的服务器。
  简单地说,实现百万人同时在线的服务器模型应该是:登陆服务器+大厅服务器+房间服务器。当然,也可以是其它的模型,但其基本的思想是一样的。下面,我将逐一介绍这三类服务器的各自作用。
  登陆服务器:一般情况下,我们会向玩家开放若干个公开的登陆服务器,就如QQ登陆时让你选择的从哪个QQ游戏服务器登陆一样,QQ登陆时让玩家选择的六个服务器入口实际上就是登陆服务器。登陆服务器主要完成负载平衡的作用。详细点说就是,在登陆服务器的背后,有N个大厅服务器,登陆服务器只是用于为当前的客户端连接选择其下一步应该连接到哪个大厅服务器,当登陆服务器为当前的客户端连接选择了一个合适的大厅服务器后,客户端开始根据登陆服务器提供的信息连接到相应的大厅上去,同时客户端断开与登陆服务器的连接,为其他玩家客户端连接登陆服务器腾出套接字资源。在设计登陆服务器时,至少应该有以下功能:N 个大厅服务器的每一个大厅服务器都要与所有的登陆服务器保持连接,并实时地把本大厅服务器当前的同时在线人数通知给各个登陆服务器,这其中包括:用户进入时的同时在线人数增加信息以及用户退出时的同时在线人数减少信息。这里的各个大厅服务器同时在线人数信息就是登陆服务器为客户端选择某个大厅让其登陆的依据。举例来说,玩家A通过登陆服务器1连接到登陆服务器,登陆服务器开始为当前玩家在众多的大厅服务器中根据哪一个大厅服务器人数比较少来选择一个大厅,同时把这个大厅的连接IP和端口发给客户端,客户端收到这个IP和端口信息后,根据这个信息连接到此大厅,同时,客户端断开与登陆服务器之间的连接,这便是用户登陆过程中,在登陆服务器这一块的处理流程。
  大厅服务器:大厅服务器,是普通玩家看不到的服务器,它的连接IP和端口信息是登陆服务器通知给客户端的。也就是说,在QQ游戏的本地文件中,具体的大厅服务器连接IP和端口信息是没有保存的。大厅服务器的主要作用是向玩家发送游戏房间列表信息,这些信息包括:每个游戏房间的类型,名称,在线人数,连接地址以及其它如游戏帮助文件URL的信息。从界面上看的话,大厅服务器就是我们输入用户名和密码并校验通过后进入的游戏房间列表界面。大厅服务器,主要有以下功能:一是向当前玩家广播各个游戏房间在线人数信息;二是提供游戏的版本以及下载地址信息;三是提供各个游戏房间服务器的连接IP和端口信息;四是提供游戏帮助的URL信息;五是提供其它游戏辅助功能。但在这众多的功能中,有一点是最为核心的,即:为玩家提供进入具体的游戏房间的通道,让玩家顺利进入其欲进入的游戏房间。玩家根据各个游戏房间在线人数,判定自己进入哪一个房间,然后双击服务器列表中的某个游戏房间后玩家开始进入游戏房间服务器。
  游戏房间服务器:游戏房间服务器,具体地说就是如“斗地主1”,“斗地主2”这样的游戏房间。游戏房间服务器才是具体的负责执行游戏相关逻辑的服务器。这样的游戏逻辑分为两大类:一类是通用的游戏房间逻辑,如:进入房间,离开房间,进入桌子,离开桌子以及在房间内说话等;第二类是游戏桌子逻辑,这个就是各种不同类型游戏的主要区别之处了,比如斗地主中的叫地主或不叫地主的逻辑等,当然,游戏桌子逻辑里也包括有通用的各个游戏里都存在的游戏逻辑,比如在桌子内说话等。总之,游戏房间服务器才是真正负责执行游戏具体逻辑的服务器。
  这里提到的三类服务器,我均采用的是完成端口模型,每个服务器最多连接数目是5000人,但是,我在游戏房间服务器上作了逻辑层的限定,最多只允许300 人同时在线。其他两个服务器仍然允许最多5000人的同时在线。如果按照这样的结构来设计,那么要实现百万人的同时在线就应该是这样:首先是大厅, 1000000/5000=200。也就是说,至少要200台大厅服务器,但通常情况下,考虑到实际使用时服务器的处理能力和负载情况,应该至少准备 250台左右的大厅服务器程序。另外,具体的各种类型的游戏房间服务器需要多少,就要根据当前玩各种类型游戏的玩家数目分别计算了,比如斗地主最多是十万人同时在线,每台服务器最多允许300人同时在线,那么需要的斗地主服务器数目就应该不少于:100000/300=333,准备得充分一点,就要准备 350台斗地主服务器。
  除正常的玩家连接外,还要考虑到:
  对于登陆服务器,会有250台大厅服务器连接到每个登陆服务器上,这是始终都要保持的连接;
  而对于大厅服务器而言,如果仅仅有斗地主这一类的服务器,就要有350多个连接与各个大厅服务器始终保持着。所以从这一点看,我的结构在某些方面还存在着需要改进的地方,但核心思想是:尽快地提供用户登陆的速度,尽可能方便地让玩家进入游戏中。

服务器网页缓存的深入分析

Expires、Cache-Control、Last-Modified、ETag是RFC 2616(HTTP/1.1)协议中和网页缓存相关的几个字段。前两个用来控制缓存的失效日期,后两个用来验证网页的有效性。要注意的是, HTTP/1.0有一个功能比较弱的缓存控制机制:Pragma,使用HTTP/1.0的缓存将忽略Expires和Cache-Control头。我们这里以Apache2.0服务器为例,只讨论HTTP/1.1协议。
Expires
Expires字段声明了一个网页或URL地址不再被浏览器缓存的时间,一旦超过了这个时间,浏览器都应该联系原始服务器。RFC告诉我们:“由于推断的失效时间也许会降低语义透明度,应该被谨慎使用,同时我们鼓励原始服务器尽可能提供确切的失效时间。”
对于一般的纯静态页面,如html、gif、jpg、css、js,默认安装的Apache服务器,不会在响应头添加这个字段。Firefox浏览器接受到相应后,如果发现没有Expires字段,浏览器根据文件的类型和“Last-Modified”字段来推断出一个合适的失效时间,并存储在客户端。推测出的时间一般是接受到响应时间后的三天左右。
Apache的expires_module模块可以在Http响应头部自动加上Expires字段。在Apache的httpd.conf文件中进行如下配置:
#启用expires_module模块
LoadModule expires_module modules/mod_expires.so
# 启用有效期控制
ExpiresActive On
# GIF有效期为1个月
ExpiresByType image/gif A2592000
# HTML文档的有效期是最后修改时刻后的一星期
ExpiresByType text/html M604800
#以下的含义类似
ExpiresByType text/css “now plus 2 month”
ExpiresByType text/js “now plus 2 day”
ExpiresByType image/jpeg “access plus 2 month”
ExpiresByType image/bmp “access plus 2 month”
ExpiresByType image/x-icon “access plus 2 month”
ExpiresByType image/png “access plus 2 month”
对于动态页面,如果在页面内部没有通过函数强制加上Expires,例如header(”Expires: ” . gmdate(”D, d M Y H:i:s”) . ” GMT”),Apache服务器会把Wed, 11 Jan 1984 05:00:00 GMT作为Expires字段内容,返回给浏览器。即认为动态页面总是失效的。而浏览器仍然会保存已经失效的动态页面。
可以发现Firefox浏览器总是缓存所有页面,不管失效、不失效还是没有声明失效时间。即使缓存中声明了一个网页的实效日期是 1970-01- 01 08:00:00,浏览器仍然会发送该文件在缓存中的Last-Modified和ETag字段。如果在服务器端验证通过,返回304状态,浏览器就还会使用此缓存。
Cache-Control
Cache-Control字段中可以声明多些元素,例如no-cache, must-revalidate, max-age=0等。这些元素用来指明页面被缓存最大时限,如何被缓存的,如何被转换到另一个不同的媒介,以及如何被存放在持久媒介中的。但是任何一个 Cache-Control指令都不能保证隐私性或者数据的安全性。“private”和“no-store”指令可以为隐私性和安全性方面提供一些帮助,但是他们并不能用于替代身
份验证和加密。
Apache的mod_cern_meta模块允许文件级Http响应头部的控制,同时它也可以配置Cache-Control头(或任何其他头)。响应头文件是放在原始目录的子目录中,根据原始文件名所命名的一个文件。具体用法请参阅Apache的官方网站。其中Cache-Control : max-age表示失效日期。如果没有启动mod_cern_meta模块,Apache服务器会把Expires字段中的日期换算成以秒为单位的一个 delta值,赋值给max-age。如果启动mod_cern_meta模块,并且配置了max-age值,Apache会将这个覆盖Expires字段。同时,max-age隐含了Canche-Control: public。这样浏览器接受到的Cache-Control : max-age和Expires值就是一致的。
如果失效日期Cache-Control : max-ag=0或者是负值,浏览器会在对应的缓存中把Expires设置为1970-01-01 08:00:00。
Last-Modified
Last-Modified和ETag是条件请求(Conditional Request)相关的两个字段。如果一个缓存收到了针对一个页面的请求,它发送一个验证请求询问服务器页面是否已经更改,在HTTP头里面带上” ETag”和”If Modify Since”头。服务器根据这些信息判断是否有更新信息,如果没有,就返回HTTP 304(NotModify);如果有更新,返回HTTP 200和更新的页面内容,并且携带新的”ETag”和”LastModified”。
使用这个机制,能够避免重复发送文件给浏览器,不过仍然会产生一个HTTP请求。
一般纯静态页面本身都会有Last-Modified信息,Apache服务器会读取页面文件中的Last-Modified信息,并添加到http响应头部。
对于动态页面,如果在页面内部没有通过函数强制加上Last-Modified,例如header(”Last-Modified: ” . gmdate(”D, d M Y H:i:s”) . ” GMT”),Apache服务器会把当前时间作为Last-Modified,返回给浏览器。
无论是纯静态页面还是动态页面,Firefox浏览器巧妙地按照接受到服务器响应的时间设置缓存页面的Last-Modified,而不是按照http响应头部中的Last-Modified字段。
ETag
既然有了Last-Modified,为什么还要用ETag字段呢?因为如果在一秒钟之内对一个文件进行两次更改,Last-Modified就会不正确。因此,HTTP/1.1利用Entity Tag头提供了更加严格的验证。
Apache服务器默认情况下,会对所有的静态、动态文件的响应头添加ETag字段。在Apache的httpd.conf文件中可以通过FileETag指令配置该选项。
FileETag指令配置了当文档是基于一个文件时用以创建 Etag(entity tag)响应头的文件的属性。在Apache 1.3.22及以前,ETag的值是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。如果一个目录的配置包含了‘FileETag INode MTime Size’而其一个子目录包含了‘FileETag -INode’那么这个子目录的设置(并会被其下任何没有进行覆盖的子目录继承)将等价于‘FileETag MTime Size’。
在多台负载平衡的服务器环境下,同一个文件会有不同的etag或者文件修改日期,浏览器每次都会重新下载。设置‘FileETag None’可以使响应头不再包含ETag字段。

三种典型web服务器Header设置内容过期方法
一、Internet 信息服务 (IIS)的内容过期设置
如果IIS 网站中有时间敏感信息,可以配置设置来保证过期信息不被代理服务器或 Web 浏览器缓存。可以配置网站内容,使之在任
何的时间自动过期。当启用内容过期时,Web 浏览器将比较当前日期和截止日期,以便决定是显示缓存页还是从服务器请求更新的页
。Microsoft ASP.NET 这样的服务器端技术可用于动态更改提供的内容。通常,时间敏感信息只限于单个文件、目录或网站;不过,您也可以为某台计算机上的所有网站设置内容过期。
必须是本地计算机上 Administrators 组的成员或者必须被委派了相应的权限,才能执行下列步骤。作为安全性的最佳操作,请使用不属于 Administrators 组的帐户登录计算机,然后使用运行方式命令以管理员身份运行 IIS管理器
在命令提示符下,键入 runas /user:administrative_accountname "mmc %systemroot%\system32\inetsrv\iis.msc"。
设置网站内容的过期时间
1. 在 IIS 管理器中,展开本地计算机;右键单击要设置内容过期的网站、虚拟目录或文件,然后单击“属性”。
2. 单击“HTTP 头”选项卡。
3. 选中“启用内容过期”复选框。
4. 单击“立即过期”、“此时间段后过期”或“过期时间”,然后在对应的框中输入所需的过期信息。
5. 单击“确定”。

二、APACHE服务的内容过期设置
Apache配置摘录及解释
i. 过期相关设置
LoadModule headers_module modules/mod_headers.so
#Load 修改header的模块。
LoadModule expires_module modules/mod_expires.so
#Load 设定过期header的模块。
Header append Via: CCN-BJ-4-502
#增加一个Via header,值配置成设备的hostname。
KeepAliveTimeout 60
#设置连接的保持时间为60秒。
ExpiresActive On
#启用过期header功能。
ExpiresDefault A604800
#缺省过期时间为“访问后的604800秒”


Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
ExpiresByType text/html A300
#text/html类型文件的过期设置为“访问后的300秒”
ExpiresByType text/css A259200
#text/css类型文件的过期设置为“访问后的259200秒”
ExpiresByType application/x-javascript A300
# application/x-javascript类型文件的过期设置为“访问后的300秒”
ExpiresByType image/gif A2592000
#image/gif类型文件的过期设置为“访问后的2592000秒”
ExpiresByType application/x-shockwave-flash A2592000
# application/x-shockwave-flash类型文件的过期设置为“访问后的2592000秒”

上述配置文件中load的两个模块:mod_headers.so 和mod_expires.so 可以让Apache具有对header的一些定制功能。
ExpiresByType: 表示按照文件类型-MIME-TYPE设定过期策略;
A300: 表示在Access后300秒后过期;
ExpiresByType text/css A2592000: 表示Mime type是text/css的文件,在Access后2592000秒过期。
ExpiresDefault A604800: 表示除了单独制定的文件类型等过期策略外的其他内容,按照这个缺省的策略设定:访问后604800秒过期。
上面的方法可以实现根据web发布的不同文件类型,针对不同的发布目录进行过期策略设置。在按照如上方法设置后,Apache会自动的产生两个相关的http header,举例如下:
HTTP/1.1 200 OK
Date: Tue, 27 Mar 2007 17:44:21 GMT
Server: Apache/2.0.54 (Unix)
Last-Modified: Thu, 25 Jan 2007 07:45:45 GMT
ETag: “72df3a-93-99499c40”
Accept-Ranges: bytes
Content-Length: 147
Cache-Control: max-age=2592000
Expires: Thu, 26 Apr 2007 17:44:21 GMT
Via: CCN-BJ-4-575
Keep-Alive: timeout=60, max=100
Connection: Keep-Alive
Content-Type: image/gif
Length: 147 [image/gif]
其中:Date + Max-age = Expires. Max-age是个时间长度,对应web server上面设置的过期时间;Expires是根据max-age算出来的过期时间点,两者是一致的,不同cache在判断内容是否过期时会严格比较系统时间和上述过期时间,或者比较age(在cache中存住的时间长度)和max-age的值。

三、lighttpd
lighttpd默认是没有开启expire模块的,需要我们在使用是手工开启这个模块支持。把mod_expire前面的“#”号去掉。
# vi /usr/local/lighttpd/etc/lighttpd.conf
"mod_expire",
设定过期时间
* 设定指定url的过期时间:
expire.url = (
"/images/" => "access 3 hours",
"/admin/" => "access 3 hours",
"/area/" => "access 3 hours",
"/calendar/" => "access 3 hours",
"/common/" => "access 3 hours",
"/front/" => "access 3 hours",
"/inc/" => "access 3 hours",
"/jeditor/" => "access 3 hours",
"/js/" => "access 3 hours",
"/script/" => "access 3 hours",
"/theme/" => "access 3 hours",
"/upload/" => "access 3 hours",
"/view/" => "access 3 hours",
"/help/" => "access 3 hours",
"/htm/" => "access 5 minutes"
)
设置Etag
在配置文件中增加,etag.use-inode="disable"(i节点不参与etag的运算),保证多台服务器生成的Etag值一致。

2008年10月31日星期五

让垃圾留言远离您的网站和用户

转载自谷歌中文网站管理员博客
发表者: Jason Morrison,搜索质量组


原文: Keeping comment spam off your site and away from users

假设您已经在您的网站上开辟了一个论坛,或者在您的博客上激活了评论功能。您精心准备了一两篇帖子,点击了提交按钮,然后开始屏住呼吸等待评论的到来。

评论真的来了。您的一个博友发表了友好的评论,您参加的在线角色扮演游戏的盟友发来了新的消息,Millie阿姨发来了星期四晚上聚餐的提醒…但同时您还收到另外一些东西…一些让您头疼的东西。比如一些鼓吹得天花乱坠的广告信息,乱七八糟不知所云的信息,甚至还有一些暴露的图片。可以这样说,您已经陷入可怕的垃圾留言里了。

垃圾留言对您来说是有害的,因为它加重了您的工作负担。垃圾留言对您的用户来说也是有害的,因为他们只是来您的网站来寻找感兴趣的内容,而这些毫不相关的内容只会影响他们的注意力。垃圾留言对整个网络来说也是有害的,因为它使网站管理员们不敢轻易开放自己的网站,这给人们在论坛和博客上自由发表自己的观点带来了不便。

那么作为一个网站管理员,您可以做些什么呢?

注:下面的解决办法是一个很好的起点,但可能并不是全部的解决方案。互联网上有许多不同的博客,论坛和BBS 我们不可能对每一种系统都提供详尽的指导,以下是较广泛通用的解决办法。

确保是真正的人而不是机器在您的网站上留言

  • 添加一个输入验证码环节(CAPTCHA)CAPTCHA要求用户阅读一段模糊的文字并输入相应的文字,这种办法能够验证对方究竟是真正的人类还是机器程序。如果您的博客或论坛没有植入验证环节的话,您可以使用Recaptcha这个插件。验证环节并不能解决所有的问题,但是它可以有效地制止垃圾留言制造者的猖狂行为。您可以了解更多类型的CAPTCHAS,但是请记住仅仅是添加这么一个环节,就可以起到很大的作用。
  • 阻止可疑行为。许多论坛允许您设置两次发贴之间的最小时间间隔。您也可以通过安装插件,监控那些来自于同一IP地址或proxy的异常巨大的流量,以及其他更可能来自于机器程序而不是人类访问者的异常行为。

使用自动过滤系统

  • 通过将一些关键词加入黑名单能够帮助您阻止一些明显的不恰当的留言。垃圾制者们有时候会故意模糊所使用的词语,所以这个方法也不是万能的,不过您也不妨一试。
  • 使用能够自动删除垃圾留言的插件或系统特性。垃圾制造者们使用自动程序的方式来侵扰您的站点,那我们为什么不也用自动的方式来保护自己呢?像Akismet(有很多针对博客和论坛的插件)这样的系统和TypePad Antispam(开源并兼容Akismet),很容易安装,并能帮您完成大部分的工作。

将您的设置调整地更严格一些

  • 禁止跟踪不被信任的链接。许多系统有这样的功能,可以给链接添加"nofollow"的属性。这样做可以防止某种类型的垃圾留言,但并不是唯一可行的方式。
  • 您可以考虑要求用户在发帖前必须登录,这样可以防止用户任意地发表留言。但是,这样做也会使信噪比提高。
  • 改变您的设置,使留言必须经过您的批准才能展示。如果您是一个规模较小的网站,并且没有太多的留言的话,这是一个使自己网站留言保持高水平的很好的办法。您可以允许自己的员工或者值得信赖的用户能够自助批准自己的留言,这样能减轻您一部分工作负担。
  • 可以考虑禁止某些类型的留言。比如,您可以将那些比较陈旧、已经不太可能有高质量评论的帖子冻结。在博客上,您可以把引用通告等功能暂停,因为这是极易吸引网络垃圾的地方。

及时更新您的网站

  • 请您花些时间将您的软件及时更新,并关注那些重大的安全升级。一些网络垃圾制造者会利用旧版本博客、论坛或内容管理系统的安全漏洞攻击您的网站。您可以在网站安全快速检查清单上找到更多相应的解决方案。

您可能需要权衡您的软件、您的用户群,及您的经验等多种因素来选择实施各种方法。无论您是一个小型的个人博客,还是一个大型的多用户的网站,不加任何保护地就贸然开放您的网站留言是有很大风险的。另外,如果您的网站已经被成千上万条垃圾帖所侵蚀并且不再出现在Google搜索结果的话,当您已经彻底清除了这些不良内容并采取了相应保护措施的话,您可以考虑提交一个重新收录的申请

作为一个有较长时间经验的网站开发者和博客一员,我可以以我自己的切身体验告诉您,花一点点时间做一些预防措施会节省您将来大量的时间和精力。我是网站管理员中心组的一个较新的成员。我很乐意帮助我的网站管理员同行们,而且我对搜索质量也非常感兴趣(我已经在这一领域做了一些学术研究)。欢迎您在留言板里分享您对防止留言垃圾的心得,同时始终欢迎您访问Google网站管理员支持论坛并提出您的问题。

2008年10月30日星期四

设计完美商标图案的45条原则

  1. 不要使用超过3种颜色。
  2. 不是不可或缺的内容就无需展示。
  3. 字体务必清晰明了,让你奶奶都能看懂。
  4. 商标图案务必易于识别。
  5. 设计一个造型或者布局独特的商标图案。
  6. 独立思考,不要理会您父母爱人对你设计的想法。
  7. 保证商标图案看起来至少要能吸引三个人的注意。
  8. 不要将流行商标中的元素融入到设计中,并称为原创作品。
  9. 任何情况下都不要用剪贴画。
  10. 将商标图案设置为黑白两色时看起来依然效果良好。
  11. 反置商标图案后依然清晰明辨。
  12. 调整商标图案大小后依然清晰明辨。
  13. 如果商标图案中包含图标、符号或文字等元素,合理布局让他们相辅相成。
  14. 让您的设计避免沿袭最新流行的商标设计潮流,而要看起来能够经久不衰。
  15. 不要使用特殊效果(包括也并不局限于:斜体、阴影、反射和射线字)。
  16. 如果可能让商标呈方形布局,避免使用难以理解的布局。
  17. 避免复杂的细节。
  18. 考虑商标放置的不同地方和方式。
  19. 激发勇敢和自信的感觉,而不是无力呆板的感觉。
  20. 你应该知道你创作的商标图案绝不是完美的。
  21. 对于精明的生意采用锋利的线条,缓和的生意采用缓和的线条。
  22. 商标图案必须与其表现的主题有所关联。
  23. 照片不能做商标图案。
  24. 你要让顾客对你的设计有惊艳的感觉。
  25. 不要使用超过2种字体。
  26. 商标中的每个元素都应该排列地井井有条。左、中、右、上或底。
  27. 图标看起来浑然一体,没有拖尾元素。
  28. 在你构思设计商标之前要明确商标即将面对的群体。
  29. 强调功能胜过创新。
  30. 如果商标名字让人印象深刻,那么就用商标名字做商标图案。
  31. 镜像商标图案后依然清晰可见。
  32. 甚至大公司也需要小图案。
  33. 商标图案应该让所有人喜欢,而不仅仅为该商家喜欢而已。
  34. 创造变化。变化越多,你设计出来的商标就越适合。
  35. 商标图案在多个平台下看起来连贯。
  36. 商标图案必须轻易地描述出来。
  37. 不要在商标图案里用标志性语言。
  38. 在计算机上设计之前先把思路用铅笔在纸上绘制出来。
  39. 设计简约。
  40. 不要使用“嗖”或者“全球”符号。
  41. 商标图案不能够分散注意力。
  42. 在设计中应该如实表现设计内容。
  43. 商标图案应该视觉平衡。
  44. 避免使用明亮霓幻颜色,以及灰暗呆板颜色。
  45. 商标设计不能打破以上任何一条原则。

2008年10月29日星期三

面试中的陷阱:Java面试中的陷阱(一)

找工作要面试,有面试就有对付面试的办法。以下一些题目来自我和我朋友痛苦的面试经历,提这些问题的公司包括IBM, E*Trade, Siebel, Motorola, SUN, 以及其它大小公司。

面试是没什么道理可讲的,它的题目有的不合情理、脱离实际。有在纸上写的,有当面考你的,也有在电话里问的,给你IDE的估计很少(否则你赶快去买彩票, 说不定中)。所以如果你看完此文后,请不要抱怨说这些问题都能用IDE来解决。你必须在任何情况下准确回答这些问题,在面试中如果出现一两题回答不准确很 有可能你就被拒之门外了。

当然这些都是Java的基本题,那些面试的人大多数不会问你Hibernate有多先进,Eclipse的三个组成部分,或command design pattern,他们都是老一辈了,最喜欢问的就是基础知识。别小看了这些基础,我朋友水平一流,结果就栽在一到基础知识的问题下,和高薪无缘。

好了废话少说,开始正题。

第一,谈谈final, finally, finalize的区别。
最常被问到。

第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?

第三,Static Nested Class 和 Inner Class的不同,说得越多越好(面试题有的很笼统)。

第四,&和&&的区别。
这个问得很少。

第五,HashMap和Hashtable的区别。
常问。

第六,Collection 和 Collections的区别。
你千万别说一个是单数一个是复数。

第七,什么时候用assert。
API级的技术人员有可能会问这个。

第八,GC是什么? 为什么要有GC?
基础。

第九,String s = new String("xyz");创建了几个String Object?

第十,Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

第十一,short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
面试题都是很变态的,要做好受虐的准备。

第十二,sleep() 和 wait() 有什么区别?
搞线程的最爱。

第十三,Java有没有goto?
很十三的问题,如果哪个面试的问到这个问题,我劝你还是别进这家公司。

第十四,数组有没有length()这个方法? String有没有length()这个方法?

第十五,Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
常问。

第十六,Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?

第十七,给我一个你最常见到的runtime exception。
如果你这个答不出来,面试的人会认为你没有实际编程经验。

第十八,error和exception有什么区别?

第十九,List, Set, Map是否继承自Collection接口?

第二十,abstract class和interface有什么区别?
常问。

第二十一,abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?

第二十二,接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?

第二十三,启动一个线程是用run()还是start()?

第二十四,构造器Constructor是否可被override?

第二十五,是否可以继承String类?

第二十六,当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?

第二十七,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?

第二十八,编程题: 用最有效率的方法算出2乘以8等於几?
有C背景的程序员特别喜欢

2008年10月19日星期日

无知者无畏——中国程序员和印度程序员的对话

一个在美国IBM工作过2年,在印度公司工作了4年的项目经理与我司资深软件开发经理有这样一段对话。
印方经理问:"你们每月生产多少行代码?"
我方经理掂量了很久,谦虚地说:"人均代码1万多行吧,不到2万行"。
印方经理听后,眼睛瞪得圆圆的:"喔!你们已经远远超过国际最高水平了。"
我方经理惴惴不安地反问:"你们的呢?"
印方经理很认真地回答:"我们公司目前的效率为每人每月300行。"
这是一个真实的故事,我想换了其他人(包括以前的我)也会给出同样的答案。
为什么与软件大国有这么大的差距呢?
首先我们没有生产率的概念。大多数人是这么算的,一天编400行-500行代码还不是小菜一碟。一个月有30天,这样每月1万多行还不是轻松搞掂?
殊不知,这个伟大的假设有两个致命的错误:第一、没有考虑需求分析、概要设计、详细设计、单元测试、集成测试、系统测试的时间,也没有考虑文档的时间,甚至都有可能不知道有这些过程。
这不是笑话,试问:我们有需求分析吗?我们有单元测试吗?我们有编程规范,但我们遵守了吗?
我们的代码花花绿绿,风格千奇百怪――
我们不是有"开发完了,还没有设计文档的经历"吗?
我们不是有"要转中试了,所有人才开始埋头苦干写文档"的经历吗?
我们不是有人在文档中写过,"该软件对人畜没有伤害"吗?
当然,我们更不可能想到有review的时间,根本考虑不到质量控制?
我 们最熟悉写程序、系统测试、维护,其他的都是多余。这是典型的小公司游击战的做法,一个人搞一个小软件,不需要任何流程,没有任何质量体系,除了写代码, 测试以外,什么都不需要,非常自由,自以为"牛得不行",这很easy,那很容易,"管理是罗嗦,流程是麻烦",但实际的结果是什么样大家都知道。
第二、一天能写400-500行代码,并不表示,你平均每个月能写12000-15000行代码,道理很简单,一个人100米速度是12秒,并不表示他的3000米速度是6分钟。我们不是机器人,写软件需要思考,写嵌入式软件尤其需要质量。
印度工程师是人,中国软件工程师也是人,我们的代码生产率与水平能高到哪里去呢?正如大家都是凡人,你突然说你比子弹还快,一蹦3层楼高。
这真是"无知"者"无畏"?
其 实我们的生产率很低,自己不觉得罢了,很多人并不相信我司的公开数字――月产代码才120行?如果算一算所有的人力,所有阶段的时间,我们就不会惊奇这个 数据了。不信的话,我们拿一个产品算一算!或许我们的经理自己都不知道在这个产品投了多少人力。华为有职业化的软件开发管理人才吗?目前几乎没有,或许我 们真的有月产2万行的编程高手,也有很多自以为能写2万行代码的"泡沫"高手,但我们没有真正专业的软件人才!
目前我们公司的销售情况很好,卖得 很火。但这是项目开发成功了吗?不是,可能更多的是市场的成功,以及产品预研立项人员的成功。生命周期内还要花那么多维护费用,这怎么能算成功?如果我们 造飞机,我们可能自己都不敢坐。衡量项目成功的标准与要素是什么?很多人并不知道。印度发展最快的Infosys公司告诉我们:衡量项目成功的标准是"质 量、成本与进?quot;,达到这一目标的重要条件是"流程、技术、人"。
我们做计划时,只有进度,或许会考虑一下成本,但从来没有考虑过质量。我们知道项目开发的质量活动是什么吗?我们不知道;我们知道我们的质量目标吗?我们也没有;我们知道如何控制我们的质量吗?我们没有干过。
所以我们才无所畏惧,百折不饶。但如果我们知道"折"一次要花100万,我们还会无所畏惧地"百折"吗?再回头看看一些业界标准:某印度合作公司通过了CMM5级,联合开发项目的生产率为每月400行。其中编码阶段,印度工程师每天可以写200至900行代码。
在4个月的联合开发过程中――
在编码速度上,我方优秀工程师与对方差不多,但别人教会了我们如何保证代码规范以及编程风格的一致;
在阅读协议标准方面,对方的速度是我们的4-5倍;
在设计方面,对方有明显的优势;
在质量控制,我们与他们就没有办法比较了;
在预测方面,对方估计工作量为36人月,我方估计为22人月,实际数为35人月。
通过对比,我的结论是:我们富有,因为我们有很多bug;我们快速,因为我们没有质量体系。
有些人还以为――
会使用配置工具sourcesafe,就知道什么是配置管理;
会画CANTT图/PERT图,就知道项目计划是怎么回事了;
填一下表格就是管理;
吃一顿饭就是沟通。
没有对质量整体的认识,不了解其为什么这么做,大家就根据自己的过去经验"理解"、"推测"、"认识"别人,有这么巨大的认识差距就不足为怪了。
目前,公司在质量体系方面的培训与推行力度的不断加强,印度所经验的不断推广,在很多方面,如流程建设、预测、质量控制、度量系统,我们已经初步了解该怎么做。但我们还要不断地宣传、不停地松土,让所有的人承认自己无知,只有这样,我们才能由"无知"变为"有识"。
"艺低人胆大",今后,我再也不想听这种大胆的豪言壮语:“我们每月代码1万行"!

2008年10月17日星期五

IE与FireFox的js和css(杂记)

png透明 AlphaImageLoader
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=bEnabled,sizingMethod=sSize,src=sURL)

enabled:可选项。布尔值(Boolean)。设置或检索滤镜是否激活。true:默认值。滤镜激活。false:滤镜被禁止。
sizingMethod:可选项。字符串(String)。设置或检索滤镜作用的对象的图片在对象容器边界内的显示方式。crop:剪切图片以适应对象尺寸。image:默认值。增大或减小对象的尺寸边界以适应图片的尺寸。scale:缩放图片以适应对象的尺寸边界。
src:必选项。字符串(String)。使用绝对或相对 url 地址指定背景图像。假如忽略此参数,滤镜将不会作用。

禁止选取网页内容
在IE中一般用js:obj.onselectstart=function(){return false;}
而firefox用CSS:-moz-user-select:none

滤镜的支持(例:透明滤镜)
IE:filter:alpha(opacity=10);
firefox:-moz-opacity:.10;

捕获事件
IE:obj.setCapture() 、obj.releaseCapture()
Firefox:document.addEventListener(”mousemove”,mousemovefunction,true);
document.removeEventListener(”mousemove”,mousemovefunction,true);

获取鼠标位置
IE:event.clientX、event.clientY
firefox:需要事件函数传递事件对象
obj.onmousemove=function(ev){
X= ev.pageX;Y=ev.pageY;
}

DIV等元素的边界问题
比如:设置一个div的CSS::{width:100px;height:100px;border:#000000 1px solid;}
IE中:div的宽度(包括边框宽度):100px,div的高度(包括边框宽度):100px;
而firefox:div的宽度(包括边框宽度):102px,div的高度(包括边框宽度):102px;

判断浏览器类型
var isIE=document.all ? true : false;
我写了一个变量,如果支持document.all语法那么isIE=true,否则isIE=false

在不同浏览器下的CSS处理
一般可以用!important来优先使用css语句(仅firefox支持)
比如:{border-width:0px!important;border-width:1px;}
在firefox下这个元素是没有边框的,在IE下边框宽度是1px

document.formName.item(”itemName”) 问题
问题说明:IE下,可以使用 document.formName.item(”itemName”) 或 document.formName.elements ["elementName"];Firefox下,只能使用document.formName.elements["elementName"]。
解决方法:统一使用document.formName.elements["elementName"]。

集合类对象问题
问题说明:IE下,可以使用()或[]获取集合类对象;Firefox下,只能使用[]获取集合类对象。
解决方法:统一使用 [] 获取集合类对象。

自定义属性问题
问题说明:IE下,可以使用获取常规属性的方法来获取自定义属性,也可以使用 getAttribute() 获取自定义属性;Firefox下,只能使用 getAttribute() 获取自定义属性。
解决方法:统一通过 getAttribute() 获取自定义属性。

eval(”idName”)问题
问题说明:IE下,可以使用 eval(”idName”) 或 getElementById(”idName”) 来取得 id 为 idName 的HTML对象;Firefox下,只能使用 getElementById(”idName”) 来取得 id 为 idName 的HTML对象。
解决方法:统一用 getElementById(”idName”) 来取得 id 为 idName 的HTML对象。

变量名与某HTML对象ID相同的问题
问题说明:IE下,HTML对象的ID可以作为 document 的下属对象变量名直接使用,Firefox下则不能;Firefox下,可以使用与HTML对象ID相同的变量名,IE下则不能。
解决方法:使用 document.getElementById(”idName”) 代替 document.idName。最好不要取HTML对象ID相同的变量名,以减少错误;在声明变量时,一律加上var关键字,以避免歧义。

const问题
问题说明:Firefox下,可以使用const关键字或var关键字来定义常量;IE下,只能使用var关键字来定义常量。
解决方法:统一使用var关键字来定义常量。

input.type属性问题
问题说明:IE下 input.type 属性为只读;但是Firefox下 input.type 属性为读写。
解决办法:不修改 input.type 属性。如果必须要修改,可以先隐藏原来的input,然后在同样的位置再插入一个新的input元素。

window.event问题
问题说明:window.event 只能在IE下运行,而不能在Firefox下运行,这是因为Firefox的event只能在事件发生的现场使用。
解决方法:在事件发生的函数上加上event参数,在函数体内(假设形参为evt)使用 var myEvent = evt?evt:(window.event?window.event:null)
示例:<input onclick="”doSomething(event)”/" type="”button”">
<script language="”javascript”"></script>
function doSomething(evt) {
var myEvent = evt ? evt: (window.event ? window.event : null)

}

event.x与event.y问题
问题说明:IE下,even对象有x、y属性,但是没有pageX、pageY属性;Firefox下,even对象有pageX、pageY属性,但是没有x、y属性。
解决方法:var myX = event.x ? event.x : event.pageX;var myY = event.y ? event.y:event.pageY;
如果考虑第8条问题,就改用myEvent代替event即可。

event.srcElement问题
问题说明:IE下,even对象有srcElement属性,但是没有target属性;Firefox下,even对象有target属性,但是没有srcElement属性。
解决方法:使用srcObj = event.srcElement ? event.srcElement : event.target;
如果考虑第8条问题,就改用myEvent代替event即可。

window.location.href问题
问题说明:IE或者Firefox2.0.x下,可以使用window.location或window.location.href;Firefox1.5.x下,只能使用window.location。
解决方法:使用 window.location 来代替 window.location.href。当然也可以考虑使用 location.replace()方法。

模态和非模态窗口问题
问题说明:IE下,可以通过showModalDialog和showModelessDialog打开模态和非模态窗口;Firefox下则不能。
解决方法:直接使用 window.open(pageURL,name,parameters) 方式打开新窗口。
如果需要将子窗口中的参数传递回父窗口,可以在子窗口中使用window.opener来访问父窗口。如果需要父窗口控制子窗口的话,使用var subWindow = window.open(pageURL,name,parameters);来获得新开的窗口对象。

frame和iframe问题
以下面的frame为例:
<frame src=”xxx.html” id=”frameId” name=”frameName” />
(1)访问frame对象
IE:使用window.frameId或者window.frameName来访问这个frame对象;
Firefox:使用window.frameName来访问这个frame对象;
解决方法:统一使用 window.document.getElementById(”frameId”) 来访问这个frame对象;

(2)切换frame内容
在IE和Firefox中都可以使用window.document.getElementById(”frameId”).src = “xxx.html”或window.frameName.location = “xxx.html”来切换frame的内容;
如果需要将frame中的参数传回父窗口,可以在frame中使用parent关键字来访问父窗口。

body载入问题
问题说明:Firefox的body对象在body标签没有被浏览器完全读入之前就存在;而IE的body对象则必须在body标签被浏览器完全读入之后才存在。
[注] 这个问题尚未实际验证,待验证后再来修改。
[注] 经验证,IE6、Opera9以及FireFox2中不存在上述问题,单纯的JS脚本可以访问在脚本之前已经载入的所有对象和元素,即使这个元素还没有载入完成。

事件委托方法
问题说明:IE下,使用 document.body.onload = inject;其中function inject()在这之前已被实现;在Firefox下,使用 document.body.onload = inject();
解决方法:统一使用 document.body.onload=new Function(”inject()”);或者 document.body.onload = function(){/* 这里是代码 */}
[注意] Function和function的区别

访问的父元素的区别
问题说明:在IE下,使用 obj.parentElement 或 obj.parentNode 访问obj的父结点;在firefox下,使用 obj.parentNode 访问obj的父结点。
解决方法:因为firefox与IE都支持DOM,因此统一使用obj.parentNode 来访问obj的父结点。

cursor:hand VS cursor:pointer
问题说明:firefox不支持hand,但ie支持pointer ,两者都是手形指示。
解决方法:统一使用pointer。

innerText的问题
问题说明:innerText在IE中能正常工作,但是innerText在FireFox中却不行。
解决方法:在非IE浏览器中使用textContent代替innerText。
示例:
if(navigator.appName.indexOf(”Explorer”) >-1){
document.getElementById(”element”).innerText = “my text”;
}else{
document.getElementById(”element”).textContent = “my text”;
}
[注] innerHTML 同时被ie、firefox等浏览器支持,其他的,如outerHTML等只被ie支持,最好不用。

对象宽高赋值问题
问题说明:FireFox中类似 obj.style.height = imgObj.height 的语句无效。
解决方法:统一使用 obj.style.height = imgObj.height + “px”;

Table操作问题
问题说明:ie、firefox以及其它浏览器对于 table 标签的操作都各不相同,在ie中不允许对table和tr的innerHTML赋值,使用js增加一个tr时,使用appendChild方法也不管用。
解决方法:
//向table追加一个空行:
var row = otable.insertRow(-1);
var cell = document.createElement(”td”);
cell.innerHTML = “”;
cell.className = “XXXX”;
row.appendChild(cell);
[注] 由于俺很少使用JS直接操作表格,这个问题没有遇见过。建议使用JS框架集来操作table,如JQuery。

ul和ol列表缩进问题
消除ul、ol等列表的缩进时,样式应写成:list-style:none;margin:0px;padding:0px;
其中margin属性对IE有效,padding属性对FireFox有效。← 此句表述有误,详细见↓
[注] 这个问题尚未实际验证,待验证后再来修改。
[注] 经验证,在IE中,设置margin:0px可以去除列表的上下左右缩进、空白以及列表编号或圆点,设置padding对样式没有影响;在Firefox 中,设置margin:0px仅仅可以去除上下的空白,设置padding:0px后仅仅可以去掉左右缩进,还必须设置list-style:none才 能去除列表编号或圆点。也就是说,在IE中仅仅设置margin:0px即可达到最终效果,而在Firefox中必须同时设置margin:0px、 padding:0px以及list-style:none三项才能达到最终效果。

CSS透明问题
IE:filter:progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=60)。
FF:opacity:0.6。
[注] 最好两个都写,并将opacity属性放在下面。

CSS圆角问题
IE:ie7以下版本不支持圆角。
FF:-moz-border-radius:4px,或者-moz-border-radius-topleft:4px;-moz-border- radius-topright:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius- bottomright:4px;。
[注] 圆角问题是CSS中的经典问题,建议使用JQuery框架集来设置圆角,让这些复杂的问题留给别人去想吧。

推荐30个国外优秀的设计教程网站

1.Good-Tutorials

2. Pixel2life

3. Tutorialized

4. Luxa

5. TutorialOutpost

6. Graphic-Design-Links

6.FStutorials

7. PhotoshopRoadmap

8. Tutorial-center

9. TutorialGarden

10. TutorialKit

11. CGtutorials

12. PSlover

13. TotalTutorial

14. TutorialMan

15. Photoshop911

16. PureGraphics

17. PhotoshopTalent

18. TutorialSubmitter

19. CGlinks

20.T-tutorials

21. Tutorial-Inde

22. Tutorial-Mix

23. Tutorio

24. TutorialAdvisor

25. Pixel-Groovy

26. Tutorialing

27. TipClique

28. TutorialToday

29. GFXtuts

30. CapitalTutorials

应用htaccess给网站加上防盗链机制

以前在使用IIS服务器时,曾经使用过防盗链的工具,还算好用,现在转到Dreamhost之后,倒是很久没有用过防盗链了。

这几天Google了一下,最后看到A18制造的这个方法的确有效,目前本站就在使用。

具体的做法比较简单,就是在.htaccess文件中,添加下面这段代码。
然后自己做一张图片,放在网站根目录下,当其它网站盗用本站资源时,会用这张图片替换它所要求的文件,显示提示信息,请用户回到本网站获取更为准确的资讯。

如果你要使用这段代码,请自行修改有关的参数。
不要问我为什么这么写,我不懂,我只会用。
里面的网址都是允许外链的网站,如果要添加的话,请自行添加。

目前不允许外链的文件包括图片,压缩文件,和flash。
盗链不但是盗取内容还是盗取带宽,采取这个方法可以较好的处理这个问题。

RewriteEngine on RewriteCond %{REQUEST_URI} ^/outlink RewriteRule ^.*$ - [L] RewriteCond %{REQUEST_FILENAME} \.(gif|jpeg|png|swf|flv|zip|rar|txt|exe|7z)$ [NC] RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{HTTP_REFERER} !g2soft\.net [NC] RewriteCond %{HTTP_REFERER} !google\.com [NC] RewriteCond %{HTTP_REFERER} !www\.baidu\.com [NC] RewriteCond %{HTTP_REFERER} !image\.baidu\.com [NC] RewriteCond %{HTTP_REFERER} !feedsky\.com [NC] RewriteCond %{HTTP_REFERER} !365bloglink\.com [NC] RewriteCond %{HTTP_REFERER} !yahoo\.com [NC] RewriteCond %{HTTP_REFERER} !msn\.com [NC] RewriteCond %{HTTP_REFERER} !bloglines\.com [NC] RewriteCond %{HTTP_REFERER} !feedburner\.com [NC] RewriteCond %{HTTP_REFERER} !xianguo\.com [NC] RewriteCond %{HTTP_REFERER} !zhuaxia\.com [NC] RewriteRule (.*) /outlink/outlink.png [R,NC,L] RewriteCond %{HTTP_REFERER} !^$ [NC]
RewriteCond %{HTTP_REFERER} !g2soft.net [NC]
RewriteCond %{HTTP_REFERER} !google.com [NC]
RewriteCond %{HTTP_REFERER} !www.baidu.com [NC]
RewriteCond %{HTTP_REFERER} !image.baidu.com [NC]
RewriteCond %{HTTP_REFERER} !yahoo.com [NC]
RewriteCond %{HTTP_REFERER} !msn.com [NC]
RewriteCond %{HTTP_REFERER} !bloglines.com [NC]
RewriteCond %{HTTP_REFERER} !feedburner.com [NC]
RewriteCond %{HTTP_REFERER} !feedsky.com [NC]
RewriteCond %{HTTP_REFERER} !xianguo.com [NC]
RewriteCond %{HTTP_REFERER} !zhuaxia.com [NC]
RewriteRule .(jpg|gif|png|bmp|swf|jpeg)$ http://seo\.g2soft\.net/outlink3.png [R,NC,L]

2008年10月15日星期三

sqlserver数据库:如何在SQL Server数据库中加密数据

为了防止某些别有用心的人从外部访问数据库,盗取数据库中的用户姓名、密码、信用卡号等其他重要信息,在我们创建数据库驱动的解决方案时,我们首先需要考虑的的第一条设计决策就是如何加密存储数据,以此来保证它的安全,免受被他人窥测。

SQL Server中有哪一种支持可以用于加密对象和数据?从一开始就讨论一下SQL Server欠缺什么是明智的,或者是对于SQL Server中的加密部分你不应该做什么。   

首先,SQL Server有两个内置的密码函数——即,pwdencrypt() 和 pwdcompare()。同时,还有两个SQL Server用来管理密码哈希的没有正式记录的函数:pwdencrypt() 将密码哈希过后进行存储; pwdcompare()将提供的字符串与哈希后的字符串进行比较。不幸的是,这个哈希函数不是非常安全,它可以通过字典攻击算法被破解(类似命令行应用 程序!)。

这些函数随着SQL Server的版本发展而不断进行修改,这也是另一个没有使用它们的原因。早期版本的SQL Server对密码进行的哈希,在后来的版本中无法解密,所以如果你依赖一个版本中的函数,那么当升级的时候,所有你的加密数据就都没有用了,除非你可以 首先对其解密——这也就违背了加密的最初的目的。   

第二,你可能会尝试去创建一个针对你的数据库的自制的加密解决方案,但是有以下三个理由说明你不要这样做:

除非你是加密专家,否则胡乱编写的加密系统只会提供非常低级的价值不高的保护。新鲜的是,单向密码哈希或者 "ROTx "形式的加密几乎不需要费事就可以被轻松打败。

如果由于你自己的能力的缺乏而导致加密被破解,那么你的数据就完蛋了。你需要将所有的东西进行没有加密的备份,是吗?(即使你加密了,那里有没有安全漏洞?)

当市面上提供有专业级别的,具有工业强度的加密解决方案的时候,你就不值得花费时间去自己做。把你的时间用于构建一个好的,坚固的数据库,而不是再重新发明一次车轮。

那么,什么才是好的加密数据的方式呢?

对于新手,微软提供了一个自己生成的加密解决方案,CryptoAPI 。对于轻量级的加密,军用级别的安全就不在考虑范围之内,它具有相对容易实现的优势:管理员可以安装一个名为CAPICOM 的ActiveX 控制,它可以在T-SQL存储过程中提供CryptoAPI 功能。CAPICOM 支持各种类型的双向加密和单向哈希算法,所以管理员可以挑选最适合应用程序的问题的部分。   

如果你对使用微软的解决方案不感兴趣,还有一些很好的第三方的方案可以使用。一家名为ActiveCrypt 的软件有限责任公司制造了XP_CRYPT ,它是SQL Server的插件,可以在视图、程序和触发器中通过扩展存储过程和用户自定义函数(在SQL Server 2000中)来完成加密。你可以下载一个支持无线的MD5,DES ,以及SHA1哈希的免费版本的应用程序; 其他的加密模型就是在比特深度上进行的。(完全版本是无限的。)在你自己的代码中,你可以使用XP_CRYPT,与ActiveX 控制一样(在受限的免费版本中)。对于ASP程序员来说,一个名为AspEncrypt 的组件提供了一种将高级加密整合到你的代码中的简单方式。

对数据库文件自身进行加密或者提供传输层上的安全保护怎么样?对于前者,大家可以在Windows系统中持续使用加密文件系统。然而,你必须保存加 密密钥的备份,在出现问题的时候,这个数据有可能会丢失。对于后者,有IPSec和SQL Server自己的SSL加密,都是SQL Server和Windows自带的大家的主要精力应该放在避免以明文存储敏感数据,因为从数据库中抽取没有加密的数据同样是最容易受到攻击的薄弱环节。

2008年10月13日星期一

马云语录:最大的失败就是放弃

*在创业的道路上,我们没有退路,最大的失败就是放弃。

*在我刚开始创业的那个时候,有人说如果阿里巴巴能够成功,无疑是把一艘万吨巨轮从喜马拉雅山脚下抬到珠穆朗玛峰顶,我就要让他们看看我是如何把这艘万吨巨轮从珠穆朗玛峰顶抬到山脚下。

*今天很残酷,明天更残酷,后天很美好,但是绝大多数人死在明天晚上,见不着后天的太阳

*1999至今在杭州设立研究开发中心,以香港为总部,创办阿里巴巴网站(Alibaba.com)孙正义跟我有同一个观点,一个方案是一流的Idea加三流的实施;另外一个方案,一流的实施,三流的Idea,哪个好?我们俩同时选择一流的实施,三流的Idea。

*如何把每一个人的才华真正地发挥作用,我们这就像拉车,如果有的人往这儿拉,有的人往那儿拉,互相之间自己给自己先乱掉了。当你有一个傻 瓜时,很傻的,你很会很痛苦;你有50个傻瓜是最幸福的,吃饭、睡觉、上厕所排着队去的;你有一个聪明人时很带劲,你有50个聪明人实际上是最痛苦的,谁 都不服谁。我在公司里的作用就象水泥,把许多优秀的人才粘合起来,使他们力气往一个地方使。

*网络公司将来要判断两个:第一它的team;第二,它有technology;第三它的concept,拥有这些东西,才是存在的必要。

*Judge一个人,一个公司是不是优秀,不要看他是不是Harvard,是不是Stanford.不要judge里面有多少名牌大学毕业生,而要judge这帮人干活是不是发疯一样干,看他每天下班是不是笑眯眯回家。

*30%的人永远不可能相信你。不要让你的同事为你干活,而让我们的同事为我们的目标干活,共同努力,团结在一个共同的目标下面,就要比团结在你一个企业家底下容易的多。所以首先要说服大家认同共同的理想,而不是让大家来为你干活。

*我认为,员工第一,客户第二。没有他们,就没有这个网站。也只有他们开心了,我们的客户才会开心。而客户们那些鼓励的言语,鼓励的话,又会让他们像发疯一样去工作,这也使得我们的网站不断地发展。

*看见10只兔子,你到底抓哪一只?有些人一会儿抓这个兔子,一会儿抓那个兔子,最后可能一只也抓不住。CEO的主要任务不是寻找机会而是对机会说NO。机会太多,只能抓一个。我只能抓一只兔子,抓多了,什么都会丢掉.

*我们公司是每半年一次评估,评下来,虽然你的工作很努力,也很出色,但你就是最后一个,非常对不起,你就得离开。在两个人和两百人之间,我只能选择对两个人残酷。

*您能用一句话概括您认为员工应该具备的基本素质吗?今天阿里巴巴的员工我们要求诚信,学习能力,乐观精神,和拥抱变化的态度!

*互联网是四乘一百米接力赛,你再厉害,只能跑一棒,应该把机会给年轻人。

*在前一百米的冲刺中,谁都不是对手,是因为跑的三千米的长跑。你跑着跑着,跑了四五百米后才能拉开距离的。

*我们花了两年的时间打地基,我们要盖什么样的楼,图纸没有公布过,但有些人已经在评论我们的房子怎么不好。有些公司的房子很好看,但地基不稳,一有大风就倒了。

*我们与竞争对手最大的区别就是我们知道他们要做什么,而他们不知道我们想做什么。我们想做什么,没有必要让所有人知道。
*网络上面就一句话,光脚的永远不怕穿鞋的。

*今天要在网上发财,概率并不是很大,但今天的网络,可以为大家省下很多成本。这个世界没有人能替你发财,只有你自己才能替你发财,你需要 的是投资和投入,spendtime,investtime,ontheinternet,把自己的时间投资在网络上面,网络一定会给大家省钱,但不一定 今天就能赚多少钱,赚钱是明天的事,省钱,你今天就看得到。

*电子商务最大的受益者应该是商人,我们该赚钱因为我们提供工具,但让我们做工具的人发了大财,而使用工具的人还糊里糊涂,这是不正常 的。所谓新经济,就是传统企业利用好网络这个工具,去创造出更大的经济效益,使其成几十倍地增长,这才是真的新经济的到来。今天新旧经济是两张皮。

*互联网上失败一定是自己造成的,要不就是脑子发热,要不就是脑子不热,太冷了。

*我觉得网络公司一定会犯错误,而且必须犯错误,网络公司最大的错误就是停在原地不动,最大的错误就是不犯错误。关键在于总结我们反思各种各样的错误,为明天跑的更好,错误还得犯,关键是不要犯同样的错误

*我们是教人钓鱼,而不是给人鱼。

*企业家是在现在的环境,改善这个环境,光投诉,光抱怨有什么用呢?国家现在要处理的事情太多了,失败只能怪你自己,要么大家都失败,现在有人成功了,而你失败了,就只能怪自己。就是一句话,哪怕你运气不好,也是你不对。

*中国电子商务的人必须要站起来走路,而不是老是手拉手,老是手拉着手要完蛋。

*我们知道当时可以敲几个锣,就可以围那么多人的时候,锣都敲得好,把戏还能不好?敲锣都敲出花来了。

*我是说阿里巴巴发现了金矿,那我们绝对不自己去挖,我们希望别人去挖,他挖了金矿给我一块就可以了。

*我深信不疑我们的模式会赚钱的,亚马逊是世界上最长的河,8848是世界上最高的山,阿里巴巴是世界上最富有的宝藏。一个好的企业靠输血是活不久的,关键是自己造血。

*我们说上市就像我们的加油站,不要到了加油站,就停下来不走,还得走,继续走。

*互联网是影响人类未来生活30年的3000米长跑,你必须跑得像兔子一样快,又要像乌龟一样耐跑。

*我为什么能活下来?第一是由于我没有钱,第二是我对INTERNET一点不懂,第三是我想得像傻瓜一样。

*发令枪一响,你是没时间看你的对手是怎么跑的。只有明天是我们的竞争对手。

*如果早起的那只鸟没有吃到虫子,那就会被别的鸟吃掉。

*If not now,when? If not me, who?

*互联网像一杯啤酒,有沫的时候最好喝。

*听说过捕龙虾富的,没听说过捕鲸富的。

*我们不能企求于灵感。灵感说来就来,就像段誉的六脉神剑一样。

*阿里巴巴的六脉神剑就是阿里巴巴的价值观:诚信、敬业、激情、拥抱变化、团队合作、客户第一。

*我永远相信只要永不放弃,我们还是有机会的。最后,我们还是坚信一点,这世界上只要有梦想,只要不断努力,只要不断学习,不管你长得如 何,不管是这样,还是那样,男人的长相往往和他的的才华成反比。今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今 天。

*男人的长相往往和他的的才华成反比

*在我看来有三种人,生意人:创造钱;商人:有所为,有所不为。企业家:为社会承担责任。企业家应该为社会创造环境。企业家必须要有创新的精神。

*三年以前我送一个同事去读MBA,我跟他说,如果毕业以后你忘了所学的东西,那你已经毕业了。如果你天天还想着所学的东西,那你就还没有毕业。学习MBA的知识,但要跳出MBA的局限。

*对所有创业者来说,永远告诉自己一句话:从创业得第一天起,你每天要面对的是困难和失败,而不是成功。我最困难的时候还没有到,但有一天一定会到。困难不是不能躲避,不能让别人替你去抗。九年创业的经验告诉我,任何困难都必须你自己去面对。创业者就是面对困难。

*ebay是大海里的鲨鱼,淘宝则是长江里的鳄鱼,鳄鱼在大海里与鲨鱼搏斗,结果可想而知,我们要把鲨鱼引到长江里来。

*一个公司在两种情况下最容易犯错误,第一是有太多的钱的时候,第二是面对太多的机会,一个CEO看到的不应该是机会,因为机会无处不在,一个CEO更应该看到灾难,并把灾难扼杀在摇篮里。

*淘宝网的主业决不该放在与对手的竞争上,而是把眼睛盯在提升客户体验上。

*上世纪80年代挣钱靠勇气,90年代靠关系,现在必须靠知识能力!

2008年10月12日星期日

工作中的十不要(适用于工作不久的同事)

第一:不要认为停留在心灵的舒适区域内是可以原谅的。
  
  每个人都有一个舒适区域,在这个区域内是很自我的,不愿意被打扰,不愿意被push,不愿意和陌生的面孔交谈,不愿意被人指责,不愿意按照规定的时限做事,不愿意主动的去关心别人,不愿意去思考别人还有什么没有想到。这在学生时代是很容易被理解的,有时候这样的同学还跟“冷酷”“个性”这些字眼沾边,算作是褒义。然而相反,在工作之后,你要极力改变这一现状。否则,你会很快变成鸡尾酒会上唯一没有人理睬的对象,或是很快因为压力而内分泌失调。但是,如果你能很快打破之前学生期所处的舒适区域,比别人更快的处理好业务、人际、**之间的关系,那就能很快的脱颖而出。
  
  在会议上,一个停留在心灵舒适区域的人会消极的听取领导的话语,消极的待命,很死的完成上级交给的事情,但从来不关心此事以外的任何事情,更不会想到多做一步,让接下来的别人的工作更加容易上手。而敢于打破这个舒适区域的人,敢于在适当的时候提出自己的看法和不理解,并在得到上级认可和指点之后把手头的工作尽快的完成,并随时接受别人的批评和调整。(注意:永远不要等待别人把你的想法说出来,这是典型的前者)
  
  在工作上,当前者遇到一名新的同事,他会装作没有看见,继续自己的工作。殊不知新来的同事不久就变成了自己的上司。而后者则大方客气的自我介绍,并了解对方和自己的关系。
  
  在聚会上,前者总是等待别人发言,并喜欢私下里评论对方的言语;如果这个桌子上没有人发言,那直到用餐结束,也没有人认识你。而后者是勇敢的和一同吃饭的开始介绍和闲谈,这看起来很困难,有时候会有失面子,但往往你会发现,对方是多么希望能和你说几句话。
  
  以上只是很小的几个例子,但是要说明的是,大学生在走出校园的同时就要在工作上把校园中的“随意性”从身边赶走,尽早的冲出自己的舒适区域,开始做好和这个社会交流的准备。
  

  第二:不要把“好像”;“有人会……”;“大概”;“晚些时候”;“或者”;“说不定”之类放在嘴边。尤其是和上级谈论工作的时候。
  
  我十分痛恨听到的一句话是:“我晚些时候会把这个文件发给所有的人”;因为这往往预示着我必须时刻提醒他不要忘记。同样,以下这些言辞也会让人觉得厌恶至极:
  “到时候有人会把那些东西都准备好”
  “大概是明天”
  “明天或者后天客户会过来拜访”
  “好像他说……”
  
  一般是人都会这样说话的,因为这样第一给自己留下了广阔的余地,第二也不会给别人造成很大的压迫感,好像什么事情一定要弄个水落石出似的。说实话大学里面再用功的人都有一半是混的。一个人要么是在课堂上是混的,要么下课之后是混的。两个都没有带有混的色彩的人,要么是超级牛人,要么是神经病。所以,就因为人人都在混的,所以校园是一个浪漫的地方,校园也容易让人单纯。所以学生社团的工作往往是效率很低的,我现在回想起学校里做的工作,当时还觉得挺卖力的,但工作了之后才开始感觉到什么是效率。当你进入了用金钱计算时间的地方之后,你要尽可能的避免在学校里养成的这种习惯。如果上级问你什么时候能实施你给他的承诺,而你回答“今晚或者明天早上”这样的答案对于他来说完全等同于你没有回答,并且还给他留下了一个坏印象。(当然,这样的回答往往在学校社团,学生会工作中是常见的)
  
  有一个寓言故事,一只小老鼠刚刚出世不久,老鼠妈妈问小老鼠:你现在能看见了吗? 小老鼠说:能。 老鼠妈妈说:那你能看到那块红薯吗? 小老鼠说:是的。老鼠妈妈说:那是一块石头,这说明你不但还看不见东西,你连嗅觉都还没有。
  
  似是而非的应答往往一样会暴露出你更多的弱点。可能是以下中的一个或几个:
  1.你之前没有想到这个工作,或者一直在拖延。
  2.你没有责任心,认为这些并不重要。
  3.你应付上级。
  4.你不敢说真话。
  5.你喜欢逞能,答应一些做不到的事情。
  6.你不能独立工作。
  
  当你的上级在以上选项中怀疑的时候,潜意识中你已经同时具备了以上所有的弱点了。
  
  相反的看来,这样的回答,总是让上司恼火。
  第一,他的问题没有得到回答,只是起到了提醒你的作用。
  第二,他依然需要记住提醒你,因为他不知道你是否真正已经落实了工作。
  第三,他不知道有多少你已经做了的事情中,都是这样没有落实的。(这点非常致命)
  第四,往往因为没有得到满意的答案,上司自己的计划不得不被耽搁或推迟或不能给出明朗的结束时间。
  
  所以---------
  甲问:你什么时候能把要这个漏洞修好?
  乙说:我已经通知他们了,他们大概明天就会来修的。
  一天后
  甲问:维修公司什么时候回来,你找的是哪家维修公司?
  乙说:好像他们说安排不出人来,如果可以的话,今天晚上或者明天下午就能过来。
  一天后
  甲问:漏洞怎么还没有修好?
  乙说:我晚点再问问他们。
  甲说:今天下午之前不解决,明天不用来上班了。
  
  
  第三:不要拖延工作
  
  很多人喜欢在学习和玩耍之间先选择后者,然后在最后时间一次性赶工把考试要复习的东西突击完成。但是在工作中请不要养成这样的习惯,因为工作是永远做不完的,容不得你“突击”。又或者,当你在徘徊和彷徨如何实施的时候,你的领导已经看不下去,自己去做了。----这是一个危险的信号。
  
  往往我们总是想把事情从头到尾全部想好了,才开始走第一步-----就摔倒了。
  
  举个例子:我小学的时候第一次给我一个喜欢的女孩子打电话的时候,想象了各种情况-------1,她接电话的时候在做作业。2,她在做作业,她妈妈接的电话。3. 她也很无聊,很想找人说话。4.她正在被父母训斥。 5.她正在想另外一个男孩。6.她父亲接电话。 7.她家正好来了什么亲戚,亲戚接了电话。 8.她接了电话,但父母就在身边,说话不方便。。。。。等等等等。我整整想了一个下午,想好了各种情况的心理准备和应对的策略。然后勇敢的拿起电话机,按下了那几个按钮。结果-------她不在家。
  
  所以,当你徘徊不前而手足无措的时候,你要意识到你正在拖延工作。徘徊是因为害怕这个事情可能发生的后果需要自己承担或应付。工作的时候需要一种起码的自信,相信自己有能力,不管下一步是什么状况,我都能把它引导到我需要的那条线上去的。另外,告诉自己,不要想太多时间,如果不知道,就赶快求助,或想办法,苦恼和忧虑会给你更多的压力也会把剩下的时间蚕食殆尽。
  
  
  另外,警告一下:永远不要想,我知道了,先把上级派的事情放一下,等这集《越狱》看完再说。----90%的情况下,你会忘记,或者来不及,因为这件事需要比你原先想象要更多的时间。说做就做,一直是很好的习惯。
  
  
  第四:不要认为理论上可以实施就大功告成了!
  
  这点太重要了,往往当真正实施的人开始做了才会发现计划完全等于鬼话。如果不亲自实践,做计划的人会早晚被实施的鄙视。永远需要提升自己的办实事的能力,而不是空谈。
  
  首先,如果你是做办公室工作的,或者做策划和计划的。请千万不要把你自己都认为不太可能或者很难做到的事情,让别人试试看。比如,用一个下午的时间在人流量很少的地方举办露天歌唱会。这会让执行的人觉得你在玩他,拿他做实验。没错,理论上,在任何地方都能举办歌唱会,但是,在不同的地方,执行的人的心情是不一样的。
  
  其次,和执行的人讨论你的安排。比如,新来的你的下属,你可以安排她坐在任何地方,但是如果那是一个很难和大家接触的角落,这可能比你什么都不安排更差。的确,理论上一个人要坐下来,需要的只是空间。但事实上远远不止那些。
  
  再次,不要奢望一切会随着你的计划进行。理论上这个会议会持续两个小时,但是,这是“不考虑在开场后的30分钟全场都在调试话筒”,或者“场下没有提出如此尖锐的问题”的前提下的状态。 大学生已经习惯了把事情做到 "理论上看上去很美"的程度了。 论文,ppt讲演,考试,辩论赛…… 这些校园智商大比拼,都是教我们如何完美的做好“纸上谈兵”的功夫。 你一定要相信自己能“搞定”事情的能力比想象的弱。
  
  如果你是在学校的学生,测试一下自己,能否能搞定以下这些状况:
  1.学校要制作一套校服,由你去寻找供应商,砍价,至少有三家公司的报价。
  2.学校保安抓住一个学生偷窃,怎么处理?
  3.学校的一个很重要路段的路灯坏了,你能否让它三天内继续亮起来。
  4.食堂需要请一位专门烧清真菜的厨师,一周内到岗位。
  
  当你开始思考以上这样的问题的时候,你会发现,他的思路和“看过去两年这个公司的业绩趋向,做出一个下个季度的市场策划方案”要相差极大。你会发现后者只要你做到“看上去很完美”,没有人知道按照你这样做结果会怎样。而上述的工作你只要一想,就会体会到不少的压力。因为你不处理好,结果就是明显的失败更大的问题就会相继发生。
  对了,这种感觉就是“工作”给你的感觉!这就是“工作”和“纸上谈兵”的差别!
  
  
  第五:不要让别人等你
  
  在任何情况下都不要让别人放下手头的工作来等你。在大学中可能只是同寝室的人的几句半开玩笑的抱怨,在工作上很可能导致你的潜在合作伙伴的丢失。
  
  你在做一个工作的同时要知道别人的进度,而永远不要落后。
  这不像是在考试,你比别人做的慢,别人可以先交卷,你到时间了做不完你自己承受扣分。在工作中的情况是这样的:这是一场没有人能做完的考试,所有的人,都分配做一张试卷的不同部分,有的人分到的是阅读理解,有的人做的是完形填空,有的人做的是语法…… 然后大家做完了相互抄,这样,所有人都做完了。如果大家都把各自的部分做完了,而你却还在没有做完,那么做得快的别人会开始做你的那部分题目,然后也是相互抄。慢慢地,大家会发现你的工作量完全可以由另外人来代替,整个团队中可以不需要你,这个时候,没有人从你这里得到试卷的答案,也没有人会给你他们的答案--------很不幸,你已经没有利用价值了。
  
  请一定记住这个例子。
  第六:不要认为细节不重要
  
  在大学里,往往做事粗枝大叶,看看差不多就行了。相反,在企业里管理的精髓就在于将简单的事情做到细节。一个慌忙寻找保险箱钥匙的动作就很有可能丧失你晋升财务主管的机会。
  
  公司的管理,其实需要的并不是把很难的事情做到90%----比如,优化管理层的核心工作流程、改变公司在当地政府面前的形象,提高产品质量,改善工作环境…… 而管理要做的是把每个简单的事情做到100%-----比如,把公司的每个人的档案都按照一定的规律整齐的存放起来、在门卫设立一个外来人员的签到台、把会议室多余的椅子拿走、和电视台讲好下个礼拜三来公司做采访、把试用装送到客户手里、在生产的咖啡上加一个口子、给下一期的封面人物拍照……等等如此。如果你能把所有细节的问题都如实做到,那你才有开口升职的本钱。
  
  很多人在毕业的时候不知道自己将来要做什么,于是就和自己说:我以后做管理吧!做管理?问一下自己,如果,公司资产被偷窃了,所有员工士气低下,办公室杂乱无章,公司电梯又坏了,打印机没墨了,采购计划超支了,产品滞销了,客户迟到了……你愿意解决这样的问题,并从小事开始做起吗?想好了这些再考虑是否把管理看得太空洞了。
  

  第七:不要表现得消极,仅仅因为你所做的事情不是你的兴趣所在。
  
  很显然,在学生时代,当做到自己喜欢的时候,我们会pay200%的精力去创造,但如果是枯燥的事务,我们便懒得理睬,最好能有办法应付过去。但在工作上80%你所做的事情都是繁琐而看似机械的,如果仅仅为此而表现的闷闷不乐,那么你会郁闷更久。要知道你的上司已经为这个项目够烦恼了,你还想让他看到你的表情吗?
  
  学会喜欢自己的工作,并把注意力放在日常工作能学到些什么上去。如果现在你努力的抱怨工作,那么接下来你就是努力的寻找工作。尽量少用“有趣”,“好奇”之类的词语来描述自己想要的工作,而是“充实”,“有成就感”,“乐意”
  之类。
  想想以下职位,你会发现生活中很多工作不是在等你有很好的状态下让你做的很有趣的事情:
  1.高速公路收费口的收费员:一天都是面对一个小窗口,把一张卡片送出去,这样要持续好几年。
  2.学校食堂厨师:永远在烧大排和鸡腿。烧一年。
  3.作家:交稿期要到了,我还在孕育灵感,两个星期没吃早饭了。
  4.外科医生:刚刚睡着,马上叫我做一个3小时的手术。这样至少一周一次。
  5.门市部销售:产品不好卖,8点上班来就坐在店门口,一个人,坐到晚上6点,今天没有一个人来,和昨天一样。
  6.公交司机:我开车不用你指挥。这条线路我开了三年了。
  7.宠物商店店员:生意不好,还要一早就过来听着20条狗的叫声一整天,听一年。
  8.公司职员:晚上两点下班,第二天还要8点上班。关键是路上还要一小时。这样已经一个月了。
  
  再想想自己是不是只是接触了这个工作一个月或者才碰到没几个困难,这个时候抱怨的声音最大。
  千万不要想着去选择一个有趣的职业,因为没有那样的工作存在。没有哪一“种”行业是开心的,因为如果有,那所有人都去干那个了。最多试着问问自己本身的兴趣吧。self exploration。
  
  
  第八:绝对不要把改善工作能力仅寄托在公司培训上
  
  人绝对不可能经过一次培训就脱胎换骨。相反,集体培训上学到的东西往往是最用不上的信息。 就像食堂烧大锅菜一样,总没有你最想吃的菜,因为这样做容易,并且不容易得罪人。
  
  很多学生很看重所选的公司有没有培训,这说明,你不但不知道这个公司做什么,你甚至不知道怎样学习这些技能。
  我的感悟是如果你不知道怎么学你想要的知识,也不知道你想要的知识是什么,你只会做出两种行为:1。等待别人来教你,并且等待别人发现你不知道的地方。2.寻找现成的答案并且拷贝。期待公司培训的人,就很大概率上是第一种人(不排除极少真正优秀的公司培训)
  
  许多的同学有这样的习惯思维:
  因为,这个公司的培训能结束达到多少多少的程度
  又因为,这个程度正好是我想达到的
  所以我尽力进这家公司
  因为我进了这家公司
  所以它自然会使我达到了这个期望的程度。
  
  我们把参加培训和达到效果很幼稚的画上了等号。其实往往集体培训上所得到的信息是最没有实际操作价值的。永远不要期望单靠听课,靠老师把同样的东西给所有的人,你会得到比别人更多。把更多的心思放在观察和思考自己的需要上,找到问题的所在再通过观察和实践得到的答案才是真正的知识。
  
  所以,刚刚开始工作,什么都不会,不要认为那样是正常的,因为公司还没有培训过呢!等我接受培训了之后,我就全都会了。如果你一无所知还等待别人会可怜你的无知而施舍你知识,那你会为你的无知而付出更多的智商。
  
  
  第九:不要推卸责任
  
  推卸责任是害怕的条件反射。不要认为别人看不出这点。
  
  我记得我小学里的一件事情。我一次作业没有带来,老师要训斥我,说:你怎么老是作业不带?
  我当时说:不是。。。。 当我正要支支吾吾时候,老师说:什么不是?你带来了没有?
  我说:没有
  老师说:那不就是没有带!什么不是!就是!
  
  之后我就发现,我只是害怕承担责任而条件反射似的就说了“不是”,仔细观察一下周围,你会发现,身边有无数的人在用“不是”作为被责问之后的第一反应。
  其实现在很多人面对工作也是这样,当上级责问的时候,很条件反射的就做出了推卸动作,然而这样的动作,接下来往往是无力的辩解,以及一些很粗糙的借口。这样会让上司感到你这个人很难沟通,并且很不真实。
  
  
  另外一种情况,就是无论什么情况下,我指责一个人,他永远是强调客观。其实这点才是学生最典型的特征。这说明他太容易受到其他事物的影响,并受它们决定。如果你和上司之间会出现以下类型的对话,想想是不是需要改一下你的处事方法。
  
  甲:为什么到现在还没有给副总看你的报告!
  乙:刚才c在打印,我在等他结束,现在他大概好了吧,我去看看
  乙:还有点东西要修改
  乙:b也要把东西给副总,我因为等他
  乙:a他说我报告不用给副总看(a是乙的同级同事)
  乙:不知道副总在不在哦,他的门关着。
  乙:d他叫我帮他打印文件!怪他!(d是乙的同级同事)
  乙:我的杯子突然找不到了,在找杯子。
  
  
  不愿意负责任的人的不利在于他会让上司怀疑他的忠诚程度,因为上司给他的命令往往会因为一个小事情而被搁置或者打折执行,转而被他人的意识所改变。
  
  
  第十:不要对自己说“我是大学生”
  
  这点包涵了很多信息。
  1.不要认为自己有多清高
  2.不要仍然以学生的标准要求自己
  3.不要感觉低人一等
  4.不要等待别人的关怀
  5.不要把这个作为犯错误自我安慰的借口
  6.不要忘记搞清楚,公司究竟给自己的待遇是多少,老练些,这不是在做志愿者。
  
  品格是处理好人际关系的基础,也是确保人际关系质量的关键。除此之外,人际交往的技巧也是尤为重要的。有些人做好事会让人感激一辈子,而有些人帮了别人却可能费力不讨好,不但得不到感激和回报,还让人心存嫉恨。将同样的产品以相同的价格推销给同一个客户,有些业务员可能被粗暴地赶出门,有些业务员却可能签到大单,甚至被客户奉为上宾。
  人际交往的技巧是一个非常庞杂的话题,囿于篇幅,在这里只能结合我的切身体会做一些简单的列举,挂一漏万在所难免了。
  1. 多给别人鼓励和表扬,尽量避免批评、指责和抱怨,不要逼别人认错。
  2. 要学会倾听。不要说得太多,想办法让别人多说。
  3. 如果你要加入别人的交谈,先要弄清楚别人究竟在说什么。
  4. 交谈之前尽量保持中立、客观。表明自己的倾向之前先要弄清楚对方真实的倾向。
  5. 注意对方的社交习惯并适当加以模仿。
  6. 不要轻易打断、纠正、补充别人的谈话。
  7. 别人有困难时,主动帮助,多多鼓励。
  8. 不要因为对方是亲朋好友而不注意礼节。
  9. 尽可能谈论别人想要的,教他怎样去得到他想要的。
  10. 始终以微笑待人。
  11. 做一个有幽默感的人。但是在讲笑话的时候千万不要只顾着自己笑。
  12. 做一个脱离低级趣味的人。
  13. 跟别人说话的时候尽量看着对方的眼睛,不管你是在说还是在听。
  14. 转移话题要尽量不着痕迹。
  15. 要学会聆听对方的弦外之音。也要学会通过弦外之音来委婉地表达自己的意思。
  16. 拜访别人一定要事先通知。
  17. 不要在别人可能忙于工作或者休息的时候打电话过去。除非是非常紧急的事情。
  18. 给别人打电话的时候,先问对方是否方便通话。
  19. 一件事情让两个人知道就不再是秘密。
  20. 你在背后说任何人的坏话都迟早有一天传入这个人的耳朵。
  21. 不要说尖酸刻薄的话。
  22. 牢记他人的名字。养成偶尔翻看名片簿、电话本的习惯。
  23. 尝试着跟你讨厌的人交往。
  24. 一定要尊重对方的隐私,不管是朋友还是夫妻。
  25. 很多人在一起的时候,当你与其中某个人交谈,请不要无视其他人的存在。
  26. 要勇于认错。
  27. 以谦卑的姿态面对身边的每一个人。
  28. 给予他人同情和谅解。
  29. 尽可能用“建议”取代“命令”。
  30. 不要轻易做出承诺。承诺的事情就一定要尽可能做到。

2008年10月10日星期五

YouTube Architecture

Update: YouTube: The Platform. YouTube adds a new rich set of APIs in order to become your video platform leader--all for free. Upload, edit, watch, search, and comment on video from your own site without visiting YouTube. Compose your site internally from APIs because you'll need to expose them later anyway.

YouTube grew incredibly fast, to over 100 million video views per day, with only a handful of people responsible for scaling the site. How did they manage to deliver all that video to all those users? And how have they evolved since being acquired by Google?

Information Sources

# Google Video

Platform

# Apache
# Python
# Linux (SuSe)
# MySQL
# psyco, a dynamic python->C compiler
# lighttpd for video instead of Apache

What's Inside?

The Stats

# Supports the delivery of over 100 million videos per day.
# Founded 2/2005
# 3/2006 30 million video views/day
# 7/2006 100 million video views/day
# 2 sysadmins, 2 scalability software architects
# 2 feature developers, 2 network engineers, 1 DBA

Recipe for handling rapid growth


while (true)
{
identify_and_fix_bottlenecks();
drink();
sleep();
notice_new_bottleneck();
}

This loop runs many times a day.

Web Servers

# NetScalar is used for load balancing and caching static content.
# Run Apache with mod_fast_cgi.
# Requests are routed for handling by a Python application server.
# Application server talks to various databases and other informations sources to get all the data and formats the html page.
# Can usually scale web tier by adding more machines.
# The Python web code is usually NOT the bottleneck, it spends most of its time blocked on RPCs.
# Python allows rapid flexible development and deployment. This is critical given the competition they face.
# Usually less than 100 ms page service times.
# Use psyco, a dynamic python->C compiler that uses a JIT compiler approach to optimize inner loops.
# For high CPU intensive activities like encryption, they use C extensions.
# Some pre-generated cached HTML for expensive to render blocks.
# Row level caching in the database.
# Fully formed Python objects are cached.
# Some data are calculated and sent to each application so the values are cached in local memory. This is an underused strategy. The fastest cache is in your application server and it doesn't take much time to send precalculated data to all your servers. Just have an agent that watches for changes, precalculates, and sends.

Video Serving

# Costs include bandwidth, hardware, and power consumption.
# Each video hosted by a mini-cluster. Each video is served by more than one machine.
# Using a a cluster means:
- More disks serving content which means more speed.
- Headroom. If a machine goes down others can take over.
- There are online backups.
# Servers use the lighttpd web server for video:
- Apache had too much overhead.
- Uses epoll to wait on multiple fds.
- Switched from single process to multiple process configuration to handle more connections.
# Most popular content is moved to a CDN (content delivery network):
- CDNs replicate content in multiple places. There's a better chance of content being closer to the user, with fewer hops, and content will run over a more friendly network.
- CDN machines mostly serve out of memory because the content is so popular there's little thrashing of content into and out of memory.
# Less popular content (1-20 views per day) uses YouTube servers in various colo sites.
- There's a long tail effect. A video may have a few plays, but lots of videos are being played. Random disks blocks are being accessed.
- Caching doesn't do a lot of good in this scenario, so spending money on more cache may not make sense. This is a very interesting point. If you have a long tail product caching won't always be your performance savior.
- Tune RAID controller and pay attention to other lower level issues to help.
- Tune memory on each machine so there's not too much and not too little.

Serving Video Key Points

# Keep it simple and cheap.
# Keep a simple network path. Not too many devices between content and users. Routers, switches, and other appliances may not be able to keep up with so much load.
# Use commodity hardware. More expensive hardware gets the more expensive everything else gets too (support contracts). You are also less likely find help on the net.
# Use simple common tools. They use most tools build into Linux and layer on top of those.
# Handle random seeks well (SATA, tweaks).

Serving Thumbnails

# Surprisingly difficult to do efficiently.
# There are a like 4 thumbnails for each video so there are a lot more thumbnails than videos.
# Thumbnails are hosted on just a few machines.
# Saw problems associated with serving a lot of small objects:
- Lots of disk seeks and problems with inode caches and page caches at OS level.
- Ran into per directory file limit. Ext3 in particular. Moved to a more hierarchical structure. Recent improvements in the 2.6 kernel may improve Ext3 large directory handling up to 100 times, yet storing lots of files in a file system is still not a good idea.
- A high number of requests/sec as web pages can display 60 thumbnails on page.
- Under such high loads Apache performed badly.
- Used squid (reverse proxy) in front of Apache. This worked for a while, but as load increased performance eventually decreased. Went from 300 requests/second to 20.
- Tried using lighttpd but with a single threaded it stalled. Run into problems with multiprocesses mode because they would each keep a separate cache.
- With so many images setting up a new machine took over 24 hours.
- Rebooting machine took 6-10 hours for cache to warm up to not go to disk.
# To solve all their problems they started using Google's BigTable, a distributed data store:
- Avoids small file problem because it clumps files together.
- Fast, fault tolerant. Assumes its working on a unreliable network.
- Lower latency because it uses a distributed multilevel cache. This cache works across different collocation sites.
- For more information on BigTable take a look at Google Architecture, GoogleTalk Architecture, and BigTable.

Databases

# The Early Years
- Use MySQL to store meta data like users, tags, and descriptions.
- Served data off a monolithic RAID 10 Volume with 10 disks.
- Living off credit cards so they leased hardware. When they needed more hardware to handle load it took a few days to order and get delivered.
- They went through a common evolution: single server, went to a single master with multiple read slaves, then partitioned the database, and then settled on a sharding approach.
- Suffered from replica lag. The master is multi-threaded and runs on a large machine so it can handle a lot of work. Slaves are single threaded and usually run on lesser machines and replication is asynchronous, so the slaves can lag significantly behind the master.
- Updates cause cache misses which goes to disk where slow I/O causes slow replication.
- Using a replicating architecture you need to spend a lot of money for incremental bits of write performance.
- One of their solutions was prioritize traffic by splitting the data into two clusters: a video watch pool and a general cluster. The idea is that people want to watch video so that function should get the most resources. The social networking features of YouTube are less important so they can be routed to a less capable cluster.
# The later years:
- Went to database partitioning.
- Split into shards with users assigned to different shards.
- Spreads writes and reads.
- Much better cache locality which means less IO.
- Resulted in a 30% hardware reduction.
- Reduced replica lag to 0.
- Can now scale database almost arbitrarily.

Data Center Strategy

# Used manage hosting providers at first. Living off credit cards so it was the only way.
# Managed hosting can't scale with you. You can't control hardware or make favorable networking agreements.
# So they went to a colocation arrangement. Now they can customize everything and negotiate their own contracts.
# Use 5 or 6 data centers plus the CDN.
# Videos come out of any data center. Not closest match or anything. If a video is popular enough it will move into the CDN.
# Video bandwidth dependent, not really latency dependent. Can come from any colo.
# For images latency matters, especially when you have 60 images on a page.
# Images are replicated to different data centers using BigTable. Code
looks at different metrics to know who is closest.

Lessons Learned

# Stall for time. Creative and risky tricks can help you cope in the short term while you work out longer term solutions.

# Prioritize. Know what's essential to your service and prioritize your resources and efforts around those priorities.

# Pick your battles. Don't be afraid to outsource some essential services. YouTube uses a CDN to distribute their most popular content. Creating their own network would have taken too long and cost too much. You may have similar opportunities in your system. Take a look at Software as a Service for more ideas.

# Keep it simple! Simplicity allows you to rearchitect more quickly so you can respond to problems. It's true that nobody really knows what simplicity is, but if you aren't afraid to make changes then that's a good sign simplicity is happening.

# Shard. Sharding helps to isolate and constrain storage, CPU, memory, and IO. It's not just about getting more writes performance.

# Constant iteration on bottlenecks:
- Software: DB, caching
- OS: disk I/O
- Hardware: memory, RAID

# You succeed as a team. Have a good cross discipline team that understands the whole system and what's underneath the system. People who can set up printers, machines, install networks, and so on. With a good team all things are possible.

Flickr Architecture

Update: Flickr hits 2 Billion photos served. That's a lot of hamburgers.

Flickr is both my favorite bird and the web's leading photo sharing site. Flickr has an amazing challenge, they must handle a vast sea of ever expanding new content, ever increasing legions of users, and a constant stream of new features, all while providing excellent performance. How do they do it?

Site: http://www.flickr.com/

Information Sources

# Flickr and PHP (an early document)
# Capacity Planning for LAMP
# Federation at Flickr: Doing Billions of Queries a Day by Dathan Pattishall.
# Building Scalable Web Sites by Cal Henderson from Flickr.
# Database War Stories #3: Flickr by Tim O'Reilly
# Cal Henderson's Talks. A lot of useful PowerPoint presentations.

Platform

# PHP
# MySQL
# Shards
# Memcached for a caching layer.
# Squid in reverse-proxy for html and images.
# Linux (RedHat)
# Smarty for templating
# Perl
# PEAR for XML and Email parsing
# ImageMagick, for image processing
# Java, for the node service
# Apache
# SystemImager for deployment
# Ganglia for distributed system monitoring
# Subcon stores essential system configuration files in a subversion repository for easy deployment to machines in a cluster.
# Cvsup for distributing and updating collections of files across a network.

The Stats

# More than 4 billion queries per day.
# ~35M photos in squid cache (total)
# ~2M photos in squid’s RAM
# ~470M photos, 4 or 5 sizes of each
# 38k req/sec to memcached (12M objects)
# 2 PB raw storage (consumed about ~1.5TB on Sunday
# Over 400,000 photos being added every day

The Architecture

# A pretty picture of Flickr's architecture can be found on this slide . A simple depiction is:
-- Pair of ServerIron's
---- Squid Caches
------ Net App's
---- PHP App Servers
------ Storage Manager
------ Master-master shards
------ Dual Tree Central Database
------ Memcached Cluster
------ Big Search Engine

- The Dual Tree structure is a custom set of changes to MySQL that allows scaling by incrementally adding masters without a ring architecture. This allows cheaper scaling because you need less hardware as compared to master-master setups which always requires double the hardware.
- The central database includes data like the 'users' table, which includes primary user
keys (a few different IDs) and a pointer to which shard a users' data can be found on.

# Use dedicated servers for static content.
# Talks about how to support Unicode.
# Use a share nothing architecture.
# Everything (except photos) are stored in the database.
# Statelessness means they can bounce people around servers and it's easier to make their APIs.
# Scaled at first by replication, but that only helps with reads.
# Create a search farm by replicating the portion of the database they want to search.
# Use horizontal scaling so they just need to add more machines.
# Handle pictures emailed from users by parsing each email is it's delivered in PHP. Email is parsed for any photos.
# Earlier they suffered from Master-Slave lag. Too much load and they had a single point of failure.
# They needed the ability to make live maintenance, repair data, and so forth, without taking the site down.
# Lots of excellent material on capacity planning. Take a look in the Information Sources for more details.
# Went to a federated approach so they can scale far into the future:
- Shards: My data gets stored on my shard, but the record of performing action on your comment, is on your shard. When making a comment on someone else's’ blog
- Global Ring: Its like DNS, you need to know where to go and who controls where you go. Every page view, calculate where your data is, at that moment of time.
- PHP logic to connect to the shards and keep the data consistent (10 lines of code with comments!)
# Shards:
- Slice of the main database
- Active Master-Master Ring Replication: a few drawbacks in MySQL 4.1, as honoring commits in Master-Master. AutoIncrement IDs are automated to keep it Active Active.
- Shard assignments are from a random number for new accounts
- Migration is done from time to time, so you can remove certain power users. Needs to be balanced if you have a lot of photos… 192,000 photos, 700,000 tags, will take about 3-4 minutes. Migration is done manually.
# Clicking a Favorite:
- Pulls the Photo owners Account from Cache, to get the shard location (say on shard-5)
- Pulls my Information from cache, to get my shard location (say on shard-13)
- Starts a “distributed transaction” - to answer the question: Who favorited the photo? What are my favorites?
# Can ask question from any shard, and recover data. Its absolutely redundant.
# To get rid of replication lag…
- every page load, the user is assigned to a bucket
- if host is down, go to next host in the list; if all hosts are down, display an error page. They don’t use persistent connections, they build connections and tear it down. Every page load thus, tests the connection.
# Every users reads and writes are kept in one shard. Notion of replication lag is gone.
# Each server in shard is 50% loaded. Shut down 1/2 the servers in each shard. So 1 server in the shard can take the full load if a server of that shard is down or in maintenance mode. To upgrade you just have to shut down half the shard, upgrade that half, and then repeat the process.
# Periods of time when traffic spikes, they break the 50% rule though. They do something like 6,000-7,000 queries per second. Now, its designed for at most 4,000 queries per second to keep it at 50% load.
# Average queries per page, are 27-35 SQL statements. Favorites counts are real time. API access to the database is all real time. Achieved the real time requirements without any disadvantages.
# Over 36,000 queries per second - running within capacity threshold. Burst of traffic, double 36K/qps.
# Each Shard holds 400K+ users data.
- A lot of data is stored twice. For example, a comment is part of the relation between the commentor and the commentee. Where is the comment stored? How about both places? Transactions are used to prevent out of sync data: open transaction 1, write commands, open transaction 2, write commands, commit 1st transaction if all is well, commit 2nd transaction if 1st committed. but there still a chance for failure when a box goes down during the 1st commit.
# Search:
- Two search back-ends: shards 35k qps on a few shards and Yahoo!’s (proprietary) web search
- Owner’s single tag search or a batch tag change (say, via Organizr) goes to the Shards due to real-time requirements, everything else goes to Yahoo!’s engine (probably about 90% behind the real-time goodness)
- Think of it such that you’ve got Lucene-like search
# Hardware:
- EMT64 w/RHEL4, 16GB RAM
- 6-disk 15K RPM RAID-10.
- Data size is at 12 TB of user metadata (these are not photos, this is just innodb ibdata files - the photos are a lot larger).
- 2U boxes. Each shard has~120GB of data.
# Backup procedure:
- ibbackup on a cron job, that runs across various shards at different times. Hotbackup to a spare.
- Snapshots are taken every night across the entire cluster of databases.
- Writing or deleting several huge backup files at once to a replication filestore can wreck performance on that filestore for the next few hours as it replicates the backup files. Doing this to an in-production photo storage filer is a bad idea.
- However much it costs to keep multiple days of backups of all of your data, it's worth it. Keeping staggered backups is good for when you discover something gone wrong a few days later. something like 1, 2, 10 and 30 day backups.
# Photos are stored on the filer. Upon upload, it processes the photos, gives you different sizes, then its complete. Metadata and points to the filers, are stored in the database.
# Aggregating the data: Very fast, because its a process per shard. Stick it into a table, or recover data from another copy from other users shards.
# max_connections = 400 connections per shard, or 800 connections per server & shard. Plenty of capacity and connections. Thread cache is set to 45, because you don’t have more than 45 users having simultaneous activity.
# Tags:
- Tags do not fit well with traditional normalized RDBMs schema design. Denormalization or heavy caching is the only way to generate a tag cloud in milliseconds for hundreds of millions of tags.
- Some of their data views are calculated offline by dedicated processing clusters which save the results into MySQL because some relationships are so complicated to calculate it would absorb all the database CPU cycles.
# Future Direction:
- Make it faster with real-time BCP, so all data centers can receive writes to the data layer (db, memcache, etc) all at the same time. Everything is active nothing will ever be idle.

Lessons Learned

# Think of your application as more than just a web application. You'll have REST APIs, SOAP APIs, RSS feeds, Atom feeds, etc.

# Go stateless. Statelessness makes for a simpler more robust system that can handle upgrades without flinching.

# Re-architecting your database sucks.

# Capacity plan. Bring capacity planning into the product discussion EARLY. Get buy-in from the $$$ people (and engineering management) that it’s something to watch.

# Start slow. Don’t buy too much equipment just because you’re scared/happy that your site will explode.

# Measure reality. Capacity planning math should be based on real things, not abstract ones.

# Build in logging and metrics. Usage stats are just as important as server stats. Build in custom metrics to measure real-world usage to server-based stats.

# Cache. Caching and RAM is the answer to everything.

# Abstract. Create clear levels of abstraction between database work, business logic, page logic, page mark-up and the presentation layer. This supports quick turn around iterative development.

# Layer. Layering allows developers to create page level logic which designers can use to build the user experience. Designers can ask for page logic as needed. It's a negotiation between the two parties.

# Release frequently. Even every 30 minutes.

# Forget about small efficiencies, about 97% of the time. Premature optimization is the root of all evil.

# Test in production. Build into the architecture mechanisms (config flags, load balancing, etc.) with which you can deploy new hardware easily into (and out of) production.

# Forget benchmarks. Benchmarks are fine for getting a general idea of capabilities, but not for planning. Artificial tests give artificial results, and the time is better used with testing for real.

# Find ceilings.
- What is the maximum something that every server can do ?
- How close are you to that maximum, and how is it trending ?
- MySQL (disk IO ?)
- SQUID (disk IO ? or CPU ?)
- memcached (CPU ? or network ?)

# Be sensitive to the usage patterns for your type of application.
- Do you have event related growth? For example: disaster, news event.
- Flickr gets 20-40% more uploads on first work day of the year than any previous peak the previous year.
- 40-50% more uploads on Sundays than the rest of the week, on average

# Be sensitive to the demands of exponential growth. More users means more content, more content means more connections, more connections mean more usage.

# Plan for peaks. Be able to handle peak loads up and down the stack.