关于项目过程中的设计的一点思考

从3年前的第一份工作期,就被告知,项目和产品的区别,所以,项目的一要素是满足需求;

这一点从广义上来讲,大概意思就是:项目架构,技术选型,项目进度,code质量等等一切,只要较好的满足需求即可,如果能在较小的代价下满足客户的需求扩展当然更好;
在这里,我不会讨论太多,作为一名编码人员,只是想就编码实现方面做一些粗浅的思考;
案例来自工作的一个项目:
对象:一个对象:object,2年量预计数据量:1W,5年预计数据量:10W;
            两种属性:attribute_1,有13种不同的值;attribute_2,有5中不同的值;
           属性数以及每个属性可能的值的数量长期内变化可能性很小,浮动不超过5;
业务:系统管理员会在后台编辑object的属性,每种属性,可以选择多个值;全选可能性很小,属性值覆盖率大概40%;
搜索:以上的object,以及其attributes要通过solr建立索引,以实现通过索引,按照attribute值来搜索object对象;
以上业务和需求被如下实现:
object一张单独的表:
objctID objectName ObjectOtherField…
long string
object_attribtue表:
objctID
attribute_1 attribute_2
long
string
string
外键(业务维护) 如果含有多个attribute_1值,则用逗号隔开
如果含有多个attribute_1值,则用逗号隔开
两个枚举类型:
维护attribute的值;分别都觉有<String,Integer>,String为属性的中文名称;Integer为属性的值,在数据库中使用;
搜索:将两个表的数据联合成一个大对象发送到solr建索引,然后根据attribute 逗号分隔的‘特性’,构造复杂的solr检索表达式来检索数据;
以上设计:
object_attribtue表的数据量与object相同;数据量很小;
每次后台编辑,只需要直接对object_attribtue做一次update即可;
问题:1.如何添加一个新的属性:attribute_3?object_attribtue表直接面临add column的问题;并且需要重新设计一个枚举;
             2.如何新添加属性值:修改枚举类;
             3.页面展示:如果展示新的属性类型以及其值?需要修改展示等等;
             4.solr检索太复杂,而且solr肯定是支持多值字段的。


[ps.object_attribtue表中attribute_1,attribute_2的string类型值,同事用枚举的Integer构造的时候,多加入了一个空格,成了:"1, 2, 3, 4, 10"的形式,导致“1,2”这样的搜索无法成功;折腾半天啊!]


设计改进:
object表不变,新增attribte表,attribte_value表,因为数据浮动不超过5,所以不提供数据维护的管理后台,直接将现有数据放到数据库,以提供给属性编辑业务使用。
object_attribtue 表如下:
objctID
attributeID
attributeValue
long int int


改进后的设计:abject_attribtue2年数据量:1W×13×5×40%=26W,百万级以下;
                              后台编辑修改object的属性的时候比较麻烦:3步:查出旧的,标记删除的,插入新的;


对于之前的问题:
1&2.对于属性及值这类元数据修改,直接修改数据库中的数据即可,代码和数据库结构都不需要变动;
3.页面展示是直接展示查询元数据得到的list,所以不要修改页面展示;有新值,就可以立即展示;
4.构建solr的multivalue字段,搜索很容易;


额外的好处:如果需要添加对属性的编辑功能,在新的设计下,只是添加一个页面的问题;数据表都已经有了;
新的solr逻辑,和  object_attribtue表也更容易理解,这是非常好的;



从上面的案例想到一些额外的:
1.第二个方案为什么没有执行?满足需求和更优系统的选择谁来决定和争取?
2.近些年流行的敏捷开发,提到敏捷就是要构造一个容易扩展的系统,代码容易扩展,框架容易扩展;
3.年会上北京这边的老大提到:2012,要做到极致,迅速;我的理解:养成极致的习惯,速度应该就有了;


最近写工作的状态

工作上,现在的量比在以前的公司小了很多很多,
通常我有一个多星期甚至更久的时间去完成一个功能,一个没有技术难点的功能点;
在这边,所有的都走着所谓的流程(暂且不再这里说这些流程好或是不好,哪里好哪里不好);
或许是因为产品性质的原因吧,上线就会有金钱交易,所以没开发一个功能都有从头到尾的评审和自始至终的测试;虽然不要指望测试发现太多或者一些隐藏很深的问题,但是所有的评审,特别的最后的技术评审,对每一个细节怎么去实现,都有最后确定的方案。我,这个coder要做的,就是将方案尽可能正确无误的用代码实现,并尽可能用合理的方式处理好所有异常;
觉得在一些地方能学习到很多:[以下是我一个作为coder的高到低排序]

技术方案评审:

大家在一起讨论一个功能的每一个细节,应该怎么去处理;大数据量,异常业务,外部异常(数据库,网络等不可空)等;这让我慢慢积累看问题的深度;不再是问题的表面,还有问题的周围:这个问题最终要做什么?需要什么支持?会有哪些问题?必须可靠的依赖如果不可靠了怎么处理等等。例如:如果你的程序使用网络,那么网络不可用的时候,你程序的表现你想好了吗?有听说过离线应用吗?googe mail 离线版使用过吗?对于这一点,我还想多说几句。上次找工作面试的时候,面试的朋友问我,每30分钟到一个百万级别的数据库中抽出前30分钟的数据,怎么去做?着一个怎么去做,其实是问我你用什么方法去做,以及要解决那些问题?[当然这是后来聊才知道的,我当时一直把思路放在大数据量上面了]

code:

我想说的是我还是一个毛躁的coder,我以为一些问题很容易,对我来说简直是小case!事实却不是那么简单。能尽可能完美的解决一个问题,在很大程度上取决于你对于上面 1 中的问题以及周边的理解和思考认识程度,当然还有一如既往的细心和稳重;

写文档和回邮件:

我们写代码的人,可能从一开始就被教导,你的代码要有可读性;但是到底有多重要我目前还不知[没有体会],code生涯中跟多的情况是:后来人总是大肆渲染说前面的人留下的代码真烂;也曾见过一片文章,说他(开源贡献者)最高兴的事情就是收到邮件,感谢他写的代码,写得太完美了;在这里,且不说代码方面的事情吧,言归正传。现在我偶尔会发一封邮件分享,我会考虑,我如何写,别人会有兴趣和且容易了解甚至入门;我会回复运营产品测试等提出来的问题,然后告诉他们是否真的是问题,是怎么导致的,我们怎么解决的,他们应该注意写什么;甚至,我会附上例子;鉴于问题,或者某一句话的重要性,我会采用强调的手法,让大家注意到应该被注意的地方;
这些天的工作还比较轻松,我尽可能思考好每一个细节,然后一个点一个点的写代码。可以用从容来说我的心态吧,现在每一个部分都已经完成,并以一次性通过我的测试;感觉很好;写代码的过程也很爽,思路很清晰;我采用的方式是在电脑的第二个屏幕上面放一个TODO列表,我要完成的功能的每一步骤都在上面,我只需要一个一个完成即可,我无需担心会有问题[写代码还是要思考的,并不是完全不像,可能还会有新的问题哦]

同事分享的几个小哲学故事

【和尚与屠夫】

从前有一个和尚跟一个屠夫是好朋友。和尚天天早上要起来念经,而屠夫天天要起来杀猪。为了不耽误他们早上的工作,是他们约定早上互相叫对方起床。
多年以后,和尚与屠夫相继去世了。屠夫去上天堂了,而和尚却下地狱了。
Why?
因为屠夫天天作善事,叫和尚起来念经,相反地,和尚天天叫屠夫起来杀生……

小哲理:

你做的东西是不是都是你认为对的,却不一定是对的。

【一道终身受用的测试题】

你开着一辆车。
在一个暴风雨的晚上。
你经过一个车站。
有三个人正在焦急的等公共汽车。
一个是快要临死的老人,他需要马上去医院。
一个是医生,他曾救过你的命,你做梦都想报答他。
还有一个女人/男人,她/他是你做梦都想嫁/娶的人,也许错过就没有了。
但你的车只能在坐下一个人,你会如何选择?
我不知道这是不是一个对你性格的测试, 因为每一个回答都有他自己的原因。
老人快要死了,你首先应该先救他。
你也想让那个医生上车,因为他救过你,这是个好机会报答他。
还有就是你的梦中情人。错过了这个机会。你可能永远不能遇到一个让你这么心动的人了。
在200个应征者中,只有一个人被雇佣了,他并没有解释他的理由,他只是说了以下的话:’给医生车钥匙,让他带着老人去医院,而我则留下来陪我的梦中情人一起等公车!’
每个人我认识的人都认为以上的回答是最好的,但没有一个人(包括我在内)一开始就想到。

小哲理:

是否是因为我们从未想过要放弃我们手中已经拥有的优势(车钥匙)?
有时,如果我们能放弃一些我们的固执,狭隘,和一些优势的话,我们可能会得到更多。

【皮鞋的来历】

很久很久以前,人类都还赤着双脚走路。
有一位国王到某个偏远的乡间旅行,因为路面崎岖不平,有很多碎石头,刺得他的脚又痛又麻。回到王宫后,他下了一道命令,要将国内的所有道路都铺上一层牛皮。他认为这样做,不只是为自己,还可造福他的人民,让大家走路时不再受刺痛之苦。
但即使杀尽国内所有的牛,也筹措不到足够的皮革,而所花费的金钱、动用的人力,更不知凡几。虽然根本做不到,甚至还相当愚蠢,但因为是国王的命令,大家也只能摇头叹息。
一位聪明的仆人大胆向国王提出建言:「国王啊!为什么您要劳师动众,牺牲那么多头牛,花费那么多金钱呢?您何不只用两小片牛皮包住您的脚呢?」国王听了很惊讶,但也当下领悟,于是立刻收回成命,改采这个建议。据说,这就是「皮鞋」的由来。

小哲理:

想改变世界,很难;要改变自己,则较为容易。与其改变全世界,不如先改变自己–「将自己的双脚包起来」。改变自己的某些观念和作法,以抵御外来的侵袭。当自己改变后,眼中的世界自然也就跟着改变了。如果你希望看到世界改变,那么第一个必须改变的就是自己。
「心若改变,态度就会改变;态度改变,习惯就改变;习惯改变,人生就会改变。」

【生意就是这样做成的】

爹对儿子说,我想给你找个媳妇。
儿子说,可我愿意自己找!
爹说,但这个女孩子是比尔盖茨的女儿!
儿子说,要是这样,可以。
然后他爹找到比尔盖茨,说,我给你女儿找了一个老公。
比尔盖茨说,不行,我女儿还小!
爹说,可是这个小伙子是世界银行的副总裁!
比尔盖茨说,啊,这样,行!
最后,爹找到了世界银行的总裁,说,我给推荐一个副总裁!
总裁说,可是我有太多副总裁了,多余了!
爹说,可是这个小伙子是比尔盖茨的女婿!
总裁说,这样 ,行!——生意就是这样做成的。

人生十大须知:

  1. 所谓铁饭碗,不是在一个地方吃一辈子饭,而是一辈子到哪里都有饭吃。
  2. 把每一件简单的事做好,就不简单;把每一件平凡的事做好,就是不平凡。
  3. 生活的最高境界是宽容,相处的最高境界是尊重。
  4. 从崇高到荒唐只有一步,从荒唐到崇高却没有路。
  5. 何谓生老病死?生的要好,老的要慢,病的要晚,死的要快。
  6. 傲不可长,欲不可纵,乐不可极,志不可移。
  7. 不与富交我不贫,不与贵交我不贱。
  8. 世上只有想不通的人,没有走不通的路。
  9. 能力就像一张支票,除非把它兑成现金,否则毫无价值。
  10. 人生在世,无非是让别人笑笑,也偶尔笑笑别人。

JavaScript处理HTML 元素作为文本展示

问题背景

公司的项目的一个页面,有一个淡出框,需要展示的数据是从事件元素的一些属性上获得的

示例源代码:

<a id ="id" href="javascript:showTip()" data-name="<input />" >TEXT</a>
<!--弹出窗口:-->
<div style="display:none" id="J_Tip"></div>
<script type="text/javascript">
function showTip() {
	var text = document.getElementById('id').getAttribute('data-name');
	var tip = document.getElementById('J_Tip');
	tip.innerHTML=text;
	tip.style.display='block';
	};
</script>

在我们实际项目中,a标签的data-name是通过vm模板输出scope变量来做的;由于框架(vm以及webx)的原因,变量如果直接卸载vm里面,html标签是可以转义的;如果输写在element的属性里面则无法转移;通过下面的例子或许能让你更好理解我的意思:

			<!--直接输出-->
			<p>$!{param}</p>
			<!--属性输出-->
			<p data-name="$!{param}"></p>
			

从页面源代码来看,效果就是:

			<!--直接输出-->
			<p>&lt;input /&gt;</p>
			<!--属性输出-->
			<p data-name="<input />"></p>
			

解决方案

借助上面的原因:前端想到如下的方案:

				<a id ="id" href="javascript:showTip()">TEXT</a><span style="display:none">$!{param}</span>
				<!--- <a id ="id" href="javascript:showTip()">TEXT</a><span  style="display:none">&lt;input /&gt;</span> -->
				<!--弹出窗口:-->
				<div style="display:none" id="J_Tip">
				</div>
				<script type="text/javascript">
                                function showTip() {
						var textNode = Y.one(document.getElementById('id')).next()['_node'];//通过YUI的一个方法获得相邻兄弟节点
						var tip = document.getElementById('J_Tip');
						tip.innerHTML=textNode.innerHTML;
						tip.style.display='block';
					};</script>
			

代价

  1. 页面大小增加:多添加了一个<span>元素
  2. 依赖YUI的js方法:虽然很不可能以后不提供支持
  3. 修改JS:这个不可避免

问题扩展

  1. 对于文本型参数的传递:
    用类似:

    	    		<p data-name="$!{param}"></p>
    	    		

    的方式,如果参数param里含有单引号或者双引号,将发生惨痛的悲剧!

  2. javascript是否有内置方法做html转移字符的处理:也就是说能替我们完成<input value=’hello’/< –》 &lt;input value=’hello’/&gt; 这件事情。

总结

对于上面的问题1:通常的解决方案或许是想到用ParseUtil之类的静态方法在JSP/vm/asp页面或者干脆是后台,将param字符串做一次转换;另外一个方法就是将param参数不做任何处理,直接交给js方法,那么就依赖于问题2的解决方法了。

对于上面的问题2:由于这样那样的原因,我向前端提出过使用innerText和appedn 一个TextNode的两个方案;第一个方案:innertText有兼容性的问题;第二方案:他们没有去做测试,因为他们想到如上添加兄弟节点的方法;并做了艰难的调试,不过最终成功了;
经过我今天的测试,appedn 一个TextNode的方案是可行的:

	    	tip.appendChild(document.createTextNode('<input />'));
	    	

这是在放飞梦想QQ群讨论之后,我去做的测试,是成功的;热心的好友们给了还有jQuery的方案:

	    	$('id').text('<input />')
	    	

基于jQuery,也是很可行,且简洁的;

不过,我还是想,html转义字符处理应该也是一个问题:好友JavaChen给了我他从spring sample中研究的代码:

	    	xmlencode : function(xml) {
							return window.ActiveXObject ? xml.xml : (new XMLSerializer())
							.serializeToString(xml);
						};

			xmlEscape : function(xml) {
							return this.xmlencode(xml).replace(/\&/g, '&' + 'amp;').replace(/</g,
							'&' + 'lt;').replace(/>/g, '&' + 'gt;').replace(/\'/g,
							'&' + 'apos;').replace(/\"/g, '&' + 'quot;');
						};
	    	

在某些情况或许我们需要手动的去做这正转化,上面的regex 匹配提供了一些思路;虽然我想开源的茫茫java世界,现在估计已经存在这种工具;

数据库索引

为什么要有索引

引用sybas emanuals的话如下:

From Heaps of Pages to Fast Performance

Indexes are the most important physical design element in improving database performance:

  • Indexes help prevent table scans. Instead of reading hundreds of data pages, a few index pages and data pages can satisfy many queries.
  • For some queries, data can be retrieved from a nonclustered index without ever accessing the data rows.
  • Clustered indexes can randomize data inserts, avoiding insert “hot spots” on the last page of a table.
  • Indexes can help avoid sorts, if the index order matches the order of columns in an order by clause.

In addition to their performance benefits, indexes can enforce the uniqueness of data.

Indexing requires trade-offs. Although indexes speed data retrieval, they can slow down data modifications, since most changes to the data also require updating the indexes. Optimal indexing demands:

  • An understanding of the behavior of queries that access unindexed heap tables, tables with clustered indexes, and tables with nonclustered indexes
  • An understanding of the mix of queries that run on your server
  • An understanding of the Adaptive Server optimizer

索引的实现

B Tree

我们常见的数据库系统,其索引使用的数据结构多是B-Tree或者B+Tree。例如,MsSql使用的是B+TreeOracleSysbase使用的是B-Tree。所以在最开始,简单地介绍一下B-Tree

B-Tree不同于Binary Tree(二叉树,最多有两个子树),一棵M阶的B-Tree满足以下条件:
1)每个结点至多有M个孩子;
2)除根结点和叶结点外,其它每个结点至少有M/2个孩子;
3)根结点至少有两个孩子(除非该树仅包含一个结点);
4)所有叶结点在同一层,叶结点不包含任何关键字信息;
5)有K个关键字的非叶结点恰好包含K+1个孩子;

另外,对于一个结点,其内部的关键字是从小到大排序的。以下是B-TreeM=4)的样例:

  

对于每个结点,主要包含一个关键字数组Key[],一个指针数组(指向儿子)Son[]。在B-Tree内,查找的流程是:使用顺序查找(数组长度较短时)或折半查找方法查找Key[]数组,若找到关键字K,则返回该结点的地址及KKey[]中的位置;否则,可确定K在某个Key[i]Key[i+1]之间,则从Son[i]所指的子结点继续查找,直到在某结点中查找成功;或直至找到叶结点且叶结点中的查找仍不成功时,查找过程失败。

接着,我们使用以下图片演示如何生成B-TreeM=4,依次插入1~6):
从图可见,当我们插入关键字4时,由于原结点已经满了,故进行分裂,基本按一半的原则进行分裂,然后取出中间的关键字2,升级(这里是成为根结点)。其它的依类推,就是这样一个大概的过程。

  

数据库索引

索引

在数据库中,索引的含义与日常意义上的“索引”一词并无多大区别(想想小时候查字典),它是用于提高数据库表数据访问速度的数据库对象。
A)索引可以避免全表扫描。多数查询可以仅扫描少量索引页及数据页,而不是遍历所有数据页。
B)对于非聚集索引,有些查询甚至可以不访问数据页。
C)聚集索引可以避免数据插入操作集中于表的最后一个数据页。
D)一些情况下,索引还可用于避免排序操作。

当然,众所周知,虽然索引可以提高查询速度,但是它们也会导致数据库系统更新数据的性能下降,因为大部分数据更新需要同时更新索引。

存储

一条索引记录中包含的基本信息包括:键值(即你定义索引时指定的所有字段的值)+逻辑指针(指向数据页或者另一索引页)。

当你为一张空表创建索引时,数据库系统将为你分配一个索引页,该索引页在你插入数据前一直是空的。此页此时既是根结点,也是叶结点。每当你往表中插入一行数据,数据库系统即向此根结点中插入一行索引记录。当根结点满时,数据库系统大抵按以下步骤进行分裂:
A)创建两个儿子结点
B)将原根结点中的数据近似地拆成两半,分别写入新的两个儿子结点
C)根结点中加上指向两个儿子结点的指针

 

通常状况下,由于索引记录仅包含索引字段值(以及4-9字节的指针),索引实体比真实的数据行要小许多,索引页相较数据页来说要密集许多。一个索引页可以存储数量更多的索引记录,这意味着在索引中查找时在I/O上占很大的优势,理解这一点有助于从本质上了解使用索引的优势。

类型

A)聚集索引,表数据按照索引的顺序来存储的。对于聚集索引,叶子结点即存储了真实的数据行,不再有另外单独的数据页。
B)非聚集索引,表数据存储顺序与索引顺序无关。对于非聚集索引,叶结点包含索引字段值及指向数据页数据行的逻辑指针,该层紧邻数据页,其行数量与数据表行数据量一致。

在一张表上只能创建一个聚集索引,因为真实数据的物理顺序只可能是一种。如果一张表没有聚集索引,那么它被称为“堆集”(Heap)。这样的表中的数据行没有特定的顺序,所有的新行将被添加的表的末尾位置。

聚集索引

在聚集索引中,叶结点也即数据结点,所有数据行的存储顺序与索引的存储顺序一致。

1)聚集索引与查询操作

如上图,我们在名字字段上建立聚集索引,当需要在根据此字段查找特定的记录时,数据库系统会根据特定的系统表查找的此索引的根,然后根据指针查找下一个,直到找到。例如我们要查询“Green”,由于它介于[Bennet,Karsen],据此我们找到了索引页1007,在该页中“Green”介于[Greane, Hunter]间,据此我们找到叶结点1133(也即数据结点),并最终在此页中找以了目标数据行。

此次查询的IO包括3个索引页的查询(其中最后一次实际上是在数据页中查询)。这里的查找可能是从磁盘读取(Physical Read)或是从缓存中读取(Logical Read),如果此表访问频率较高,那么索引树中较高层的索引很可能在缓存中被找到。所以真正的IO可能小于上面的情况。

2)聚集索引与插入操作

最简单的情况下,插入操作根据索引找到对应的数据页,然后通过挪动已有的记录为新数据腾出空间,最后插入数据。

如果数据页已满,则需要拆分数据页(页拆分是一种耗费资源的操作,一般数据库系统中会有相应的机制要尽量减少页拆分的次数,通常是通过为每页预留空间来实现):

A)在该使用的数据段(extent)上分配新的数据页,如果数据段已满,则需要分配新段。
B)调整索引指针,这需要将相应的索引页读入内存并加锁。
C)大约有一半的数据行被归入新的数据页中。
D)如果表还有非聚集索引,则需要更新这些索引指向新的数据页。

特殊情况:

A)如果新插入的一条记录包含很大的数据,可能会分配两个新数据页,其中之一用来存储新记录,另一存储从原页中拆分出来的数据。
B)通常数据库系统中会将重复的数据记录存储于相同的页中。
C)类似于自增列为聚集索引的,数据库系统可能并不拆分数据页,页只是简单的新添数据页。

3)聚集索引与删除操作

删除行将导致其下方的数据行向上移动以填充删除记录造成的空白。

如果删除的行是该数据页中的最后一行,那么该数据页将被回收,相应的索引页中的记录将被删除。如果回收的数据页位于跟该表的其它数据页相同的段上,那么它可能在随后的时间内被利用。如果该数据页是该段的唯一一个数据页,则该段也被回收。

对于数据的删除操作,可能导致索引页中仅有一条记录,这时,该记录可能会被移至邻近的索引页中,原索引页将被回收,即所谓的“索引合并”。

非聚集索引

非聚集索引与聚集索引相比:
A)叶子结点并非数据结点
B)叶子结点为每一真正的数据行存储一个“键-指针”对
C)叶子结点中还存储了一个指针偏移量,根据页指针及指针偏移量可以定位到具体的数据行。
D)类似的,在除叶结点外的其它索引结点,存储的也是类似的内容,只不过它是指向下一级的索引页的。

聚集索引是一种稀疏索引,数据页上一级的索引页存储的是页指针,而不是行指针。而对于非聚集索引,则是密集索引,在数据页的上一级索引页它为每一个数据行存储一条索引记录。

对于根与中间级的索引记录,它的结构包括:

A)索引字段值
B)RowId(即对应数据页的页指针+指针偏移量)。在高层的索引页中包含RowId是为了当索引允许重复值时,当更改数据时精确定位数据行。
C)下一级索引页的指针

对于叶子层的索引对象,它的结构包括:

A)索引字段值
B)RowId

1)非聚集索引与查询操作

针对上图,如果我们同样查找“Green”,那么一次查询操作将包含以下IO:3个索引页的读取+1个数据页的读取。同样,由于缓存的关系,真实的IO实际可能要小于上面列出的。

2)非聚集索引与插入操作

如果一张表包含一个非聚集索引但没有聚集索引,则新的数据将被插入到最末一个数据页中,然后非聚集索引将被更新。如果也包含聚集索引,该聚集索引将被用于查找新行将要处于什么位置,随后,聚集索引、以及非聚集索引将被更新。

3)非聚集索引与删除操作

如果在删除命令的Where子句中包含的列上,建有非聚集索引,那么该非聚集索引将被用于查找数据行的位置,数据删除之后,位于索引叶子上的对应记录也将被删除。如果该表上有其它非聚集索引,则它们叶子结点上的相应数据也要删除。

如果删除的数据是该数所页中的唯一一条,则该页也被回收,同时需要更新各个索引树上的指针。

由于没有自动的合并功能,如果应用程序中有频繁的随机删除操作,最后可能导致表包含多个数据页,但每个页中只有少量数据。

索引覆盖

索引覆盖是这样一种索引策略:当某一查询中包含的所需字段皆包含于一个索引中,此时索引将大大提高查询性能。

包含多个字段的索引,称为复合索引。索引最多可以包含31个字段,索引记录最大长度为600B。如果你在若干个字段上创建了一个复合的非聚集索引,且你的查询中所需Select字段及Where,Order By,Group By,Having子句中所涉及的字段都包含在索引中,则只搜索索引页即可满足查询,而不需要访问数据页。由于非聚集索引的叶结点包含所有数据行中的索引列值,使用这些结点即可返回真正的数据,这种情况称之为“索引覆盖”。

在索引覆盖的情况下,包含两种索引扫描:

A)匹配索引扫描
B)非匹配索引扫描

1)匹配索引扫描

此类索引扫描可以让我们省去访问数据页的步骤,当查询仅返回一行数据时,性能提高是有限的,但在范围查询的情况下,性能提高将随结果集数量的增长而增长。

针对此类扫描,索引必须包含查询中涉及的的所有字段,另外,还需要满足:Where子句中包含索引中的“引导列”(Leading Column),例如一个复合索引包含A,B,C,D四列,则A为“引导列”。如果Where子句中所包含列是BCD或者BD等情况,则只能使用非匹配索引扫描。

2)非配置索引扫描

正如上述,如果Where子句中不包含索引的导引列,那么将使用非配置索引扫描。这最终导致扫描索引树上的所有叶子结点,当然,它的性能通常仍强于扫描所有的数据页。

索引的使用

关于聚集索引和非聚集索引的使用,有如下的一些规则:

参考/来源

  1. cnblogs 漫谈数据库索引 http://www.cnblogs.com/KissKnife/archive/2009/03/30/1425534.html
  2. CSDNblog-数据库索引 http://blog.csdn.net/wangjiafeng2008/article/details/4528501
  3. SybaseManuals-Chapter4 http://manuals.sybase.com/onlinebooks/group-asarc/asg1200e/aseperf/@Generic__BookTextView/3358
  4. IBM帮助系统MasterIndex http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.adref.doc/adref235.htm

动态编程语言之Erlang介绍

erlangErlang

是一种通用的平行导向编程语言,它由瑞典电信设备制造商爱立信所辖的计算机科学研究室开发,目的是创造一种可以应付大规模开发活动的编程语言和执行环境。Erlang问世于1987年,经过十年的发展,于1998年发表开放源码版本。Erlang是运作于虚拟机直译式语言,但是现在也包含有乌普萨拉大学高性能Erlang计划(HiPE)[1]开发的原生程式码编译器,自R11B-4版本开始,Erlang也支持脚本直译器。在程式设计典范上,Erlang属于多重典范编程语言,涵盖函数式平行式分布式。循序执行的Erlang是一个及早求值单次赋值动态资料形态函数式编程语言

开发及演变历史

Erlang得名于丹麦数学家统计学家Agner Krarup Erlang,同时Erlang还可以表示Ericsson Language。Erlang语言由瑞典爱立信电信公司的Joe Armstrong开始设计,开始于公元一九八零年代。最初是以Prolog编程语言为基础,几度改版之后,改成以Joe’s Abstract Machine为基础的独立语言执行环境。虽然语言风格仍与Prolog相近,不过因Erlang语言设计的走向,Erlang成为具备函数语言特色的编程语言[2]

发行版本

1998年起,Erlang发布开放源码版本,称为开源电信平台开源电信平台采用修改过的Mozilla公共许可证协议发放,同时爱立信仍然提供商业版本的技术支持。目前,Erlang最大的商业用户是爱立信,其他知名用户有北电网络亚玛逊以及T-Mobile[3]

语言特色

  • 平行导向程式设计 在语言中,可以借由spawn/*函数,将特定的函数设定为独立的行程,之后可以做跨行程通讯。
  • 函数式程式设计 由于Erlang早期以Prolog开发制成,受语言特性影响,即成为函数式语言。
  • 单次赋值 每个变量只能跟资料绑一次,所以,不像一般编程语言的变量可以多次指定为不同的值。单次赋值的好处是状态单纯,使程式容易阅读。
  • 及早求值或严格求值 Erlang基本求值策略为电脑语言中及早求值之特性。而且,可以借由明确使用无参数的λ演算式,将特定函数设定为惰性求值策略。
  • 动态资料型态与类型系统 有编译时期的型态检查系统支援。
  • 错误先发 在执行时期发生的错误,会由错误位置送出讯息,发生错误的行程立刻停止动作。借由行程链通机制,可以自动传递错误、捕捉错误,使其他行程能够帮助处理错误。
  • 程式码热更新 由于Erlang是函数语言,可以撰写特定的程式结构,制作即时更换新版函数的机制。
  • 脚本语言 Erlang实作提供了脚本执行方式。

语言构成

Erlang程式结构以函数定义为主。函数是一组将输入分别对应到输出的规则,对应方式遵守数学函数的惯例。此外,Erlang语言由几项构句要素所组成,包括文字(或称原子)、数字、列表、值组、字符、字串、二进制资料、模组、与特定用途的关键字如fun … end, if … end, case … of … end, spawn, !, receive … end等等。以下段落分别列示并举例说明Erlang程式的基本构成部份,涵盖资料格式表达式格式内建函数

函数式程式设计

Erlang支持函数式程式设计的一般特色,特色包括单次赋值递回定义、λ演算高阶函数等等。Erlang函数大致写法如下,以整数阶乘模组为例:

-module(fact).
-export([fac/1]).

fac(N) when N > 1 ->
    N * fac(N-1);
fac(1) ->
    1.

以下是快速排序算法的Erlang实作:

%% quicksort:qsort(List)
%% Sort a list of items
-module(quicksort).
-export([qsort/1]).

qsort([]) -> [];
qsort([Pivot|Rest]) ->
    qsort([ X || X <- Rest, X <= Pivot]) ++ [Pivot] ++ qsort([ Y || Y <- Rest, Y > Pivot]).

以下是费氏数列求解函数:

-module(example).
-export([fibo/1]).

fibo(N) when N > 1 ->
    fibo(N-1) + fibo(N-2);
fibo(1) ->
    1;
fibo(0) ->
    0.
> c(example).
{ok,example}
> lists:map(fun(X)->test:fibo(X) end, lists:seq(1,10)).
[1,1,2,3,5,8,13,21,34,55]

函数式程式设计难免以递回计算,而消耗了大量递回堆栈空间。为了克服这个问题,一般使用累积参数尾端递回等技巧节省递回数目:如以下例子。

-module(test).
-export([fibo_accu/1]).

fibo_accu(N) ->
    fibo(N, 0, 1).
fibo(N, C1, C2) when N > 2 ->
    fibo(N-1, C2, C1+C2);
fibo(0, _, _) ->
    0;
fibo(1, _, _) ->
    1;
fibo(_, C1, C2) ->
    C1+C2.
> c(example).
{ok,test}
> lists:map(fun(X)->test:fibo_accu(X) end, lists:seq(1,10)).
[1,1,2,3,5,8,13,21,34,55]

函数式程式设计容许使用高阶函数求解。以下例子说明Erlang实做复合函数。 ( f o g ,念作 f after g 。)

'After'(F, G) ->
     fun(X) ->
         erlang:apply(F,

)])
end.

  • 请注意after是Erlang关键字。因此,以上函数命名为′After′避开关键字。
> (example:'After'(fun test:show/1, fun test:parse/1))(3.1416).
Real number 3.141600 is met.
ok

平行式程式设计

Erlang最主要的特色是平行导向程式设计,强调多程序平行运作,并且以讯息对彼此沟通。Erlang提供了spawn函数和 ! 、 receive … end 等关键字,可以描述在Erlang/开源电信平台中的如何启动一些程序、并且如何让程序传递讯息。此外,平行导向程式设计的精神还强调程序的容错处理,借由程序发生错误时的讯息传递,使其他程序可以得知错误的发生,使方便于后续处理。以下分别介绍平行导向程式设计的一般程式撰写方式,以及错误处理的使用方式。

容错处理

Erlang容错处理机制,由二个步骤实现:一是将二个程序连接起来,二者之间存在一道通讯管道,可提供错误讯息的传递 ── 在此使用link/1函数;二是将程序回报错误的机制打开 ── 在此使用process_flag/2函数。

  • 使用link(Pid)让程序连接到另一个程序。
-module(example).
-compile(export_all).
hello() ->
    Pid = spawn(?MODULE, world, []),
    link(Pid),
    ... .

執行時,以 Pid = spawn(example, hello, []) 啟動程序,此程序將啟動另一個程序,並且與它連接。
但以上程式还不会有错误讯息的传递机制,因为回报错误的开关还没有打开。
  • 开启程序回报错误机制。
以上 hello/0 函數前段使用process_flag/2函數,將trap_exit標籤打開,即可開啟程序回報錯誤機制。
hello() ->
    process_flag(trap_exit, true),
    Pid = spawn(?MODULE, world, []),
    link(Pid),
    ... .

于是,当程序结束时,会送出{‘EXIT’, FromReason}资料。程序正常结束时,Reasonnormal

另外,spawn函数另外有程序连接版本,spawn_link函数,同时启动并连接到新程序。

分布式程式设计

Erlang提供分布式机制,能在另一台电脑启动一些Erlang程序,并由本机电脑对其他电脑的Erlang程序传递讯息。

  • 当启动Erlang环境时,加上一个网络节点名称,就进入分布式Erlang模式。节点可以使用埠号与其他节点通讯。
$> erl -name node_1
  • 在同一个网域中,网络节点名称可以使用短名。
$> erl -sname node_1

启动新的网络节点时,Erlang使用epmd (Erlang埠号对应管理系统) 指派埠号,提供节点使用。

当知道一个网络节点名称时,可以在该节点产生新程序。

  • 在指定节点RemoteNode启动一个程序,spawn启动参数依序为节点名称、模组名称、函数名称、函数的参数列。
% create a remote process and call the function web:start_server(Port, MaxConnections)
% on machine RemoteNode
RemoteProcess = spawn(RemoteNode, web, start_server, [Port, MaxConnections]),

在遠端節點產生新程序之後,可以使用平行式程式設計的技巧,與遠端程序通訊。

Erlang / 开源电信平台提供的程式库,于分布式程式设计可以使用net_admnet_kernelslave、… 等模组,做网络通讯[5]

其他程式设计典范

惰性求值

Erlang程式员可以使用惰性求值。不过,必须使用λ演算式,才能做到惰性求值。

以下是惰性求值的一例:假設有個剖析器程式如下,由於及早求值特徵,本程式將不會求解。
expr() -> alt(then(factor(), then(literal($+), factor())),
              then(factor(), then(literal($-), factor()))).
factor() -> alt(then(term(), then(literal($*), term())),
                then(term(), then(literal($/), term()))).
term() -> alt(number(),
              xthen(literal($(), thenx(expr(), literal($))))).
此處使用λ演算式及適當使用函數名稱表示,就能進行求值。示例如下。
expr() ->
    fun () ->
          alt(then(fun factor/0, then(literal($+), fun factor/0)),
              then(fun factor/0, then(literal($-), fun factor/0)))
    end.
factor() ->
    fun () ->
            alt(then(fun term/0, then(literal($*), fun term/0)),
                then(fun term/0, then(literal($/), fun term/0)))
    end.
term() ->
    fun () ->
          alt(number(),
              xthen(literal($(), thenx(expr(), literal($)))))
    end.

应用

参考资料

  1. ^ High Performance Erlang [2008-04-13].
  2. ^ Coders At Work. Book introduction [2010-08-30].见Coders At Work一书对Joe Armstrong的口述记录。
  3. ^ Who uses Erlang for product development?. Frequently asked questions about Erlang [2008-04-13]. “The largest user of Erlang is Ericsson. Ericsson use it to write software used in telecommunications systems. Many (dozens) projects have used it, a particularly large one is the extremely scalable AXD301 ATM switch.” FAQ中列出的其他用户包括: Nortel、Deutsche Flugsicherung、T-Mobile等
  4. ^ http://en.wikipedia.org/wiki/Open_Telecom_Platform
  5. ^ 参考分布式Erlang, http://www.erlang.org/doc/reference_manual/distributed.html

外部链接

参考/来源

  1. Erlang – 维基百科,自由的百科全书. http://zh.wikipedia.org/wiki/Erlang

蓝精灵 The Smurfs -2011 3D穿越暑期银幕

写这篇博客,完全是因为昨天网上去电影院看了之后,很喜欢;我想,蓝精灵必将是我电影收藏库里面的又一绝对经典了;

蓝精灵名片:

2011索尼动画出品电影

漫画蓝精灵是1958年由比利时漫画家沛优(Peyo)及其夫人共同创作。1981年美国国家广播公司购买版权,制作并播放美国版的《蓝精灵》动画片。2011年索尼动画由出品了这部漫画的电影版。在这部电影中邪恶的格格巫突然闯进精灵村庄,受惊的蓝精灵慌失失走避,误闯神秘石洞,在奇异的蓝月亮照耀下竟然穿越结界来到纽约中央公园。一众蓝精灵只好寄居在一对年轻夫妇家中,他们百厌活泼反应快,搞到屋主晕头转向又无计可施;精灵们首要的任务就是避开格格巫的追捕返回精灵村庄。2011年8月10日,《蓝精灵》登陆中国院线。

中文名: 蓝精灵
外文名: The Smurfs
其它译名: 蓝色小精灵(台湾译名)
出品时间: 2010年3月26日 – 2010年6月21日
出品公司: 索尼动画,哥伦比亚影片公司
制片地区: 美国
导演: 拉加·高斯内尔
类型: 动画/ 奇幻 / 家庭
评级: PG
对白语言: 英语

剧情大纲

这群可爱的蓝精灵们因为被格格巫追杀而逃出村庄,笨笨误将大家带进了禁地石窟,由于当时是蓝月,所以大伙都被传送到了进入了我们的世界,当今世界的纽约中央公园。在这里他们一方面要赶在格格巫和阿兹猫(Azrael)找到他们之前回到自己的蘑菇村庄,另一方面只有三个苹果那么高的他们掉进了大苹果(纽约)的中央公园。因此他们要在纽约这座大苹果之城展开冒险,同时蓝精灵们要在格格巫找到他们之前回到村庄里……天真无邪的蓝精灵与愤世嫉俗的都市人碰到一起将擦出怎样的火花?

中国上映

2011年8月10日,《蓝精灵》中国上映。

这部怀旧 影片从一开拍就吸引了不少蓝精灵的粉丝们,尤其是一些80后对此部影片更是备加期待,因为这代表了他们的少时岁月。《蓝精灵》北美票房一直走高,但是口碑却出现两极化,一面是美国媒体对该片的批评,一面却是一些观众的力挺。不过对于大部分人而言,蓝精灵们在8月10日的到来就是一场怀旧感受。

《蓝精灵》北美上映两周,累计票房达6110万美元。但是口碑却不如票房这般傲人,尤其是影评界对此影片评价十分尖刻,《好莱坞报道》的迈克尔称为“电 影嘈杂难看,这位曾经执导过史努比的导演在拍《蓝精灵》的时候肯定睡着了!”《华盛顿邮报》的肖恩语气稍微缓和,“一飞冲天的蓝精灵们骑在鸟背上的场景还 不错,一时间可以让人忘记那不好看的故事。不过对于青少年来说还是不错的电影。”

不少观众对影片的评价还不错,“我去看的首映,电影院里挤满了人,还有人不得不坐在地板上。所有年龄段的观众都在哈哈大笑。”还有网友说,“这真的是小孩会非常喜欢的电 影,我与丈夫以及5岁的儿子一起观看,儿子一直咯咯直笑。周围也充满了孩子的笑声。”
也有80后说,“最大的败笔可能在于新增加的人类,格蕾丝和派克人物设计都过于简单了,一个一味的甜蜜,一个从反对到友好都缺乏真诚。没有那种人类与动画人物之间亲密的互动,不感染人。

可爱的蓝精灵:

 

蓝精灵相关:

  1. 蓝精灵歌曲
  2. 蓝精灵动画片全集

Google doodle – 2011-七夕情人节快乐!

又是一年来到,任何一个节日的到来都表示着一年又过去了,离我们的死期又近了一年,生命就是时间,时间是宝贵的,生命无价,可又有多少人能彻底的明白,有人自己浪费时间,有人随意作践别人的生命。

芸芸众生皆平等,多赚点棺材本,买口好棺木,我们不都是在这样做么。不要谈什么人生价值、世界观,那是老师对年轻人懵懂的欺骗,实际上定性一个人的价值和整个社会氛围、社会所处的时代有关。太平盛世,来个出头鸟是很困难的。

 

七夕:

每年农历七月初七这一天是我国汉族的传统节日七夕节。因为此日活动的主要参与者是少女,而节日活动的内容又是以乞巧为主,故而人们称这天为“乞巧节”或“少女节”、“女儿节”。七夕节是我国传统节日中最具浪漫色彩的一个节日,也是过去姑娘们最为重视的日子。在这一天晚上,妇女们穿针乞巧,祈祷福禄寿活动,礼拜七姐,仪式虔诚而隆重,陈列花果、女红,各式家具、用具都精美小巧、惹人喜爱。2006年5月20日,七夕节被国务院列入第一批国家非物质文化遗产名录。现又被认为是“中国情人节”。

NoSQL之Redis初体验篇

  Introduction to Redis

Redis is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain stringshasheslistssets and sorted sets.

You can run atomic operations on these types, like appending to a stringincrementing the value in a hashpushing to a listcomputing set intersectionunion and difference; or getting the member with highest ranking in a sorted set.

In order to achieve its outstanding performance, Redis works with an in-memory dataset. Depending on your use case, you can persist it either by dumping the dataset to disk every once in a while, or by appending each command to a log.

Redis also supports trivial-to-setup master-slave replication, with very fast non-blocking first synchronization, auto-reconnection on net split and so forth.

Other features include a simple check-and-set mechanismpub/sub and configuration settings to make Redis behave like acache.

You can use Redis from most programming languages out there.

Redis is written in ANSI C and works in most POSIX systems like Linux, *BSD, OS X and Solaris without external dependencies. There is no official support for Windows builds, although you may have some options.

对于以上的介绍应该很好看东,主要是介绍了Redis支持的数据类型,操作;Redis工作在内存上以达到显著的执行性能,但是也支持将数据持久化到disk;以及介绍了Redis的分布式特性;

在 most programming languages页面,我们可以看到Redis支持的语言相当丰富,完全可以应用到绝大部分的开发场景中。

下面是关于Redis的初次体验:

关于服务器的安装,可以在linux环境中执行 apt-cache search redis 搜索Redis的相关包,然后执行安装;

在Redis的官方网站下载 最新的gz包,然后解压缩,执行make install是推荐的做法。更详细的安装说明可以在 这里 获取;

更有意思的是在 Redis 官方上提供了一个 在线RedisDB,您可以在下方的输入符 > 后输入redis命令,以操作数据。

服务启动:

./redis-server

客户端:

./redis-cli

执行会话:

set name phoenix

get name

就可以key/value的方式存入phoniex

并且通过key name获取vlalue的值phoenix

远程telnet方式测试安装是否成功:

telnet redishost 6379


这种方式访问数据库是我很喜欢的,我不需要在自己的机器上做任何操作,就能顺利的访问远程机器上的 Redis  数据库实例

我用以下的程序生成长度为254的字符串序列:


'''
create
@author: phoenix
'''
import string
import random
charLib = string.ascii_letters

count = 1;
a = ''
while count < 255 :
a += random.choice(charLib)
count=count+1
print(a)

性能测试类,实现语言Java;虽然由于java自己在性能上的限制,不能把基于java client的测试结果作为Redis性能的结论依据,但是作为在java平台应用,测试数据还是具有借鉴意义的。

package org.phoenix.common.redis;

import redis.clients.jedis.Jedis;

public class App {
Jedis jedis = new Jedis("localhost");
private static final String TESTVALUE = "QaDlYBSvAuSiqPQxzefjqFClVmiKmiWopiFIKwgBYVgdptFMbsdvqGuKmxTidWsEEYTGeFWgXngfJagGlJeNpaxVdPMJgTIZFbGdyuFcKqyFShhyhuYhBWnqWIYrWFCbRcfQprkhIKGLhjdfizNAmMmkWrsGYCAghxzGGZQFWQvaHnPfmUgsYywktwzAHuJCHisJpDoZTaFUdyqEsEHvVoKjQfijUUpkZYJvMFKNJHHzpQfJtLIiSUTWFkDDT";

public void putRedis(String key, String value) {
jedis.set(key, value);
}

public String getRedis(String key) {
return jedis.get(key);
}

public static void main(String[] args) {
App app = new App();
app.putRedis("firstName", "Wu");
app.putRedis("lastName", "Yimin");

System.out
.println(app.getRedis("firstName") + app.getRedis("lastName"));

System.out.println("单挑记录254个字符,总插入10w条,统计时间:");
long current = System.currentTimeMillis();
for (int i = 1; i < 100000; i++) {
app.putRedis("" + i, TESTVALUE);
}
System.out.println("used " + (System.currentTimeMillis() - current)
+ " milliseconds");
}
}

测试结果:

单条记录254个字符,总插入10w条,统计时间:used 4541 milliseconds
测试环境:
主机:32位,WindowXP,4G,Core(TM)2 Duo Eb400 3.0GHz 双核
虚拟机:32位 Ubuntu
以上测试是在我的Ubuntu 11.0.4的虚拟机上面,硬件环境有限,所有测试结果在这里不提供参考;
感觉很好的一点是,Redis提供了非常友好的方式让我们去链接DB,除了redis-cli,还有telnet,这样我们本机基本不用做任何事情,就可以连接到你可以访问的任何主机上面的Redis DB了;telnet命令在Windows和linux上都是有的,非常方便。
除此之外,还有更多;期待!

Facebook 的系统架构

根据我现有的阅读和谈话,我所理解的今天Facebook的架构如下:

  • Web 前端是由 PHP 写的。Facebook 的 HipHop [1] 会把PHP转成 C++ 并用 g++编译,这样就可以为模板和Web逻贺业务层提供高的性能。
  • 业务逻辑以Service的形式存在,其使用Thrift [2]。这些Service根据需求的不同由PHP,C++或Java实现(也可以用到了其它的一些语言……)
  • 用Java写的Services没有用到任何一个企业级的应用服务器,但用到了Facebook自己的定制的应用服务器。看上去好像是重新发明轮子,但是这些Services只被暴露给Thrift使用(绝大所数是这样),Tomcat太重量级了,即使是Jetty也可能太过了点,其附加值对Facebook所需要的没有意义。
  • 持久化由MySQL, Memcached [3], Facebook 的 Cassandra [4], Hadoop 的 HBase [5] 完成。Memcached 使用了MySQL的内存Cache。Facebook 工程师承认他们的Cassandra 使用正在减少,因为他们更喜欢HBase,因为它的更简单的一致性模型,以到其MapReduce能力。
  • 离线处理使用Hadoop 和 Hive。
  • 日志,点击,feeds数据使用Scribe [6],把其聚合并存在 HDFS,其使用Scribe-HDFS [7],因而允许使用MapReduce进行扩展分析。
  • BigPipe [8] 是他们的定制技术,用来加速页面显示。
  • Varnish Cache [9]用作HTTP代理。他们用这个的原因是高速和有效率。 [10].
  • 用来搞定用户上传的十亿张照片的存储,其由Haystack处理,Facebook自己开发了一个Ad-Hoc存储方案,其主要做了一些低层优化和“仅追加”写技术 [11].
  • Facebook Messages 使用了自己的架构,其明显地构建在了一个动态集群的基础架构上。业务逻辑和持久化被封装在一个所谓的’Cell’。每个‘Cell’都处理一部分用户,新的‘Cell’可以因为访问热度被添加[12]。 持久化归档使用HBase [13]。
  • Facebook Messages 的搜索引擎由存储在HBase中的一个倒置索引的构建。 [14]
  • Facebook 搜索引擎实现细节据我所知目前是未知状态。
  • Typeahead 搜索使用了一个定制的存储和检索逻辑。 [15]
  • Chat 基于一个Epoll 服务器,这个服务器由Erlang 开发,由Thrift存取 [16]

关于那些供给给上述组件的资源,下面是一些信息和数量,但是有一些是未知的:

  • Facebook估计有超过60,000 台服务器[16]。他们最新的数据中心在俄勒冈州的Prineville,其基于完全自定设计的硬件[17] 那是最近才公开的 Open Compute 项目[18]。
  • 300 TB 的数据存在 Memcached 中处理 [19]
  • 他们的Hadoop 和 Hive 集群由3000 服务器组成,每台服务器有8个核,32GB的内存,12TB的硬盘,全部有2万4千个CPU的核,96TB内存和36PB的硬盘。 [20]
  • 每天有1000亿的点击量,500亿张照片, 3 万亿个对象被 Cache,每天130TB的日志(2010年7月的数据) [21]

参考引用

[1] HipHop for PHPhttp://developers.facebook.com/blog/post/358
[2] Thrifthttp://thrift.apache.org/
[3] Memcachedhttp://memcached.org/
[4] Cassandrahttp://cassandra.apache.org/
[5] HBasehttp://hbase.apache.org/
[6] Scribehttps://github.com/facebook/scribe
[7] Scribe-HDFShttp://hadoopblog.blogspot.com/2009/06/hdfs-scribe-integration.html
[8] BigPipehttp://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919
[9] Varnish Cachehttp://www.varnish-cache.org/
[10] Facebook goes for Varnishhttp://www.varnish-software.com/customers/facebook
[11] Needle in a haystack: efficient storage of billions of photos:http://www.facebook.com/note.php?note_id=76191543919
[12] Scaling the Messages Application Back Endhttp://www.facebook.com/note.php?note_id=10150148835363920
[13] The Underlying Technology of Messageshttps://www.facebook.com/note.php?note_id=454991608919
[14] The Underlying Technology of Messages Tech Talk:http://www.facebook.com/video/video.php?v=690851516105
[15] Facebook’s typeahead search architecturehttp://www.facebook.com/video/video.php?v=432864835468
[16] Facebook Chathttp://www.facebook.com/note.php?note_id=14218138919
[17] Who has the most Web Servers?:http://www.datacenterknowledge.com/archives/2009/05/14/whos-got-the-most-web-servers/
[18] Building Efficient Data Centers with the Open Compute Project:http://www.facebook.com/note.php?note_id=10150144039563920
[19] Open Compute Projecthttp://opencompute.org/
[20] Facebook’s architecture presentation at Devoxx 2010http://www.devoxx.com
[21] Scaling Facebook to 500 millions users and beyondhttp://www.facebook.com/note.php?note_id=409881258919

(全文完)

 

英文原文:http://www.quora.com/What-is-Facebooks-architecture
中文来源:http://coolshell.cn/articles/4549.html

« 上一页

无觅相关文章插件,快速提升流量