回忆未来推荐的文章
来自:陈成的博客  作者:chencheng  2008-10-29

看到这个需求的时候就在暗爽,又可以搞定一个知识点了。哈哈,一天的奋斗之后,果然有所收获,而且经过怿飞的指点,在跨域问题解决上还有所突破(不通过hash)。

Demo,兼容IE,FF,Safari。

方案说明:

需求是:A页面(taobao.com)要嵌入B页面(alibaba.com),因为不能确定B页面的高度,所以要求高度自适应。

解决方法:简单来说就是在B页面里创建一个和A同域的iframe C,让C和A之间可以通讯,以把B的高度传过去。

那么怎么传过去呢?以前的方法是在C里改变parent.parent(即A)的location.hash,但是改hash会生成浏览器历史记录,点后退前进按钮用户体验不佳。我们试了下在A页面直接取frames[b].frames[c].location.hash,居然可以取到。

剩下的就简单了,在A里指定iframe B装载完成后获取C的hash,然后通过hash设置iframe B的高度。

具体代码:

A页面:(基于YUI)

/**
 * 待iframe载入后执行函数
 *
 * @param {Element} el
 * @param {Function} func
 */
var onIframeLoad = function(el, func) {
	var cb = function() {
		try {
			func.call(this);
		} catch (e) {}
	}
	if (TB.bom.isIE) {
		el.onreadystatechange = function(){
			if (el.readyState == 'complete') {
				setTimeout(cb, 0);
				el.onreadystatechange = null;
			}
		}
	} else {
		el.onload = function() {
			setTimeout(cb, 0);
			el.onload = null;
		}
	}
};
/**
 * 跨域iframe高度自适应封装
 *
 * @param {String} name
 */
var crossDomainIframe = function(name) {
	var iframe = YAHOO.util.Dom.get(name);
	var xclient = 'xclient';
	onIframeLoad(iframe, function(){
		try {
			var h = frames[name].frames[xclient].location.hash.substring(1);
			if (h == '') {
				var func = arguments.callee;
				setTimeout(function(){ func(); }, 20);
				return;
			}
			iframe.style.height = h+'px';
		} catch (e) {}
	});
};
// 执行
crossDomainIframe('frame_content');

B页面:

(function(){
function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			oldonload();
			func();
		}
	}
}
function adjust() {
	var h = document.documentElement.scrollHeight || document.body.scrollHeight;
	try {
		if (document.getElementById('xclient')) {
			var divEl = document.getElementById('xclient').parentNode;
			console.log(document.getElementById('xclient').parentNode);
			divEl.parentNode.removeChild(divEl);
		}
		var el = document.createElement('div');
		el.innerHTML = '';
		document.body.appendChild(el);
	} catch(e) {}
}
addLoadEvent(adjust);
})();

C页面:空页面,有个文件避免404发生即可

扩展阅读:

来自:扶凯  作者:admin  2009-02-23

真麻烦,一个机器有4个7T的存储中有二个存储有问题,用fsck修复了三次,都没有反应。使用使用着就提示下面的出错

#dmesg

EXT3-fs error (device sdh1): ext3_journal_start_sb: Detected aborted journal
Remounting filesystem read-only
EXT3-fs error (device sdh1): ext3_lookup: unlinked inode 67584015 in dir #6758401

然后使用着那个挂的分区就变成只读read-only.

后来找到了e2fsck,还是蛮不错的。最少他能修复.

#umount  /dev/sdg1
#e2fsck       -y          /dev/sdg1

e2fsck 1.39 (29-May-2006)
/data: recovering journal
/data contains a file system with errors, check forced.
Pass 1: Checking inodes, blocks, and sizes
Inode 286556161, i_size is 512000, should be 520192.  Fix? yes

Inode 286556161, i_blocks is 984, should be 1024.  Fix? yes

Pass 2: Checking directory structure
Entry '[M-fM-^IM-^QM-eM-^EM-^KM-gM-^NM-^KM-oM-<M-^MM-gM->M-^NM-eM-^FM-^[M-fM-4M-;M-fM-^MM-^IM-hM-^PM-(M-hM->M->M-eM-'M-^FM-eM-.M-^^M-eM-=M-^U].Ace.In.The.Hole.2005.DVDRip.XviD-LAJH.AC3.CD-1.avi' in /mldonkey1/M-fM-^IM-^QM-eM-^EM-^KM-gM-^NM-^KM-oM-<M-^MM-gM->M-^NM-eM-^FM-^[M-fM-4M-;M-fM-^MM-^IM-hM-^PM-(M-hM->M->M-eM-'M-^FM-eM-.M-^^M-eM-=M-^U (820150293) has deleted/unused inode 820150302.  Clear? yes

Problem in HTREE directory inode 286556161: node (122) has bad min hash
Problem in HTREE directory inode 286556161: node (122) referenced twice
Problem in HTREE directory inode 286556161: node (123) referenced twice
Problem in HTREE directory inode 286556161: node (124) referenced twice
Invalid HTREE directory inode 286556161 (/rss/xinhuanet/video/20092).  Clear? yes
 

 

这样,但1T的文件大约需要1个小时。。。我花了6个小时才检查修复完6T .

象这样的文件系统坏,出现问题,要从二个方面入手,一个是软件,一个是硬件。

1.查看日志,dmesg和tail -f /var/log/messages
2.要看日志检查相关的内容和软硬件
3.还没有结果就google看看有没有人和你一样出现这个问题。看看别人是怎么处理。
4.换硬件。比如RAID卡之类。
5.还搞不定,打电话给厂家。骂他们无能。

说白了,就二样事情,替换大法和排除大法。解决世上一切烦恼.

17fav 收藏本文
来自:Think IN CODE  作者:blankyao  2009-02-19

php中好多函数都被我(们)给忽略掉了,昨天看程序时看到的var_export这个函数(忘了是啥程序了),从前还真没注意过这个函数呢。

和var_dump差不多这个函数返回的是变量的结构信息,不同的是var_export返回的是合法的PHP代码。如下例子

<?php
$array = array(
‘id’    =>  ‘1′,
‘name’  =>  ‘blankyao’
);
var_export($array);

会返回

array ( ‘id’ => ‘1′, ‘name’ => ‘blankyao’, )

这有啥用呢?我能想到的一点就是生成缓存文件,看如下例子

<?php
$array = array(
‘id’    =>  ‘1′,
‘name’  =>  ‘blankyao’
);
$a = ‘$blank = ‘.var_export($array, TRUE);
file_put_contents(’blankyao.txt’, $a);

这样就直接生成了缓存数据,不用自己一步步的来分解数组了。


© blankyao for Think-IN-CODE, 2009. | Permalink | 7 comments | Add to del.icio.us
Post tags: , ,
欢迎访问Planet of CODE

来自:SpawN  作者:SpawN  2009-02-17
该文件显示了系统当前的平均负载和进程状况。 0.12 0.11 0.04 1/120 4622 前三列分别为前1分钟、5分钟、15分钟内的平均负载。 第四列为正在执行的进程数和系统的总进程数。 第五列为上次执行的进程id。
来自:神仙的仙居  作者:神仙  2009-01-29

有时候做监控或者别的什么的需要发带附件的邮件,mail 命令不能直接这么做,好在多数系统都自带了 mutt ,这个工具可以做到。

echo "mail content" | mutt -s "subject" -a "/path/to/attachment" to@domain.com

今天用到了,搜了好一会才发现这个办法。这里笔记一下。

mutt 是一个很强大的字符界面的邮件终端,貌似好多牛人都用这个来收发邮件。

另:
经济危机果然影响深远,今年除夕和初五接财神的鞭炮烟花都少了好多好多。

 

来自:SpawN  作者:SpawN  2009-01-05
escape对0-255以外的unicode值进行编码时输出%u****格式,其它情况下escape,encodeURI,encodeURIComponent编码结果相同。 最多使用的应为encodeURIComponent,它是将中文、韩文等特殊字符转换成utf-8格式的url编码,所以如果给后台传递参数需要使用encodeURIComponent时需要后台解码对utf-8支持(form中的编码方式和当前页面编码方式相同) escape不编码字符有69个:*,+,-,.,/,@,_,0-9,a-z,A-Z encodeURI不编码字符有82个:!,#,$,&,’,(,),*,+,,,-,.,/,:,;,=,?,@,_,~,0-9,a-z,A-Z encodeURIComponent不编码字符有71个:!, ‘,(,),*,-,.,_,~,0-9,a-z,A-Z
来自:Taobao DBA Team  作者:丁原  2008-12-13

通常我们会有一些时间的转换需求,比如要统计某个时间段的收入,比如要截取某个时间的年份,比如要根据某个日期推算出是星期几等个,这些都可以通过Mysql自带的时间函数很容易实现。因为我对Mysql的函数还不熟,而通常又会调用这些时间函数,这边稍加总结以便查询。
–返回当前时间

mysql> select now(),date(now()),sysdate();
+---------------------+-------------+---------------------+
| now()               | date(now()) | sysdate()           |
+---------------------+-------------+---------------------+
| 2008-12-02 10:11:36 | 2008-12-02  | 2008-12-02 10:11:36 |
+---------------------+-------------+---------------------+
1 row in set (0.00 sec)
mysql> select curdate(),curdate()+0,curtime(),curtime()+0;       
+---------------------+-------------+---------------------+
| curdate()  | curdate()+0 | curtime() | curtime()+0   |
+---------------------+-------------+---------------------+
| 2008-12-02 | 20081202    | 10:00:33  | 100033.000000 |
+---------------------+-------------+---------------------+

–返回日期当月最后一天

mysql> select last_day('2008-12-02');
+------------------------+
| last_day('2008-12-02') |
+------------------------+
| 2008-12-31             |
+------------------------+
1 row in set (0.00 sec)

–返回日期的星期几

mysql> select dayname('2008-12-02'),dayofweek('2008-12-02');
+-----------------------+-------------------------+
| dayname('2008-12-02') | dayofweek('2008-12-02') |
+-----------------------+-------------------------+
| tuesday               |                       3 |
+-----------------------+-------------------------+
1 row in set (0.00 sec)

–返回日期的年,月,日

mysql> select month('2008-12-02'),year('2008-12-02'),day('2008-12-02');
+---------------------+--------------------+-------------------+
| month('2008-12-02') | year('2008-12-02') | day('2008-12-02') |
+---------------------+--------------------+-------------------+
|                  12 |               2008 |                 2 |
+---------------------+--------------------+-------------------+
1 row in set (0.00 sec)

–返回日期的小时,分,秒

mysql> select hour('10:05:03'),minute('10:05:03'),second('10:05:03');       
+------------------+--------------------+--------------------+
| hour('10:05:03') | minute('10:05:03') | second('10:05:03') |
+------------------+--------------------+--------------------+
|               10 |                  5 |                  3 |
+------------------+--------------------+--------------------+
1 row in set (0.00 sec)

1.subdate(d,t):起始时间加上一段时间(year,month,day…)

mysql> select date_add('1998-01-02', interval 31 day),adddate('1998-01-02', 31);     
+-----------------------------------------+---------------------------+
| date_add('1998-01-02', interval 31 day) | adddate('1998-01-02', 31) |
+-----------------------------------------+---------------------------+
| 1998-02-02                              | 1998-02-02                |
+-----------------------------------------+---------------------------+
1 row in set (0.00 sec)
mysql> select date_add('1998-01-02',interval 2 year);
+-----------------------------------------------------+
| date_add('1998-01-02', interval 2 year)
+-----------------------------------------------------+
| 2000-01-02                                 
+-----------------------------------------------------+
1 row in set (0.00 sec)
mysql> select date_add('1998-01-02', interval 2 hour);
+-----------------------------------------------------+
| date_add('1998-01-02', interval 2 hour)
+-----------------------------------------------------+
| 1998-01-02 02:00:00                   
+-----------------------------------------------------+
1 row in set (0.00 sec)

2.subdate(d,t):起始时间减去一段时间

mysql> select subdate('1998-01-02', interval 31 day),subdate('1998-01-02', 31);
+----------------------------------------+---------------------------+
| subdate('1998-01-02', interval 31 day) | subdate('1998-01-02', 31) |
+----------------------------------------+---------------------------+
| 1997-12-02                             | 1997-12-02                |
+----------------------------------------+---------------------------+
1 row in set (0.00 sec)

3.addtime(d,t):起始时间d加入时间t

mysql> select addtime('1997-12-31 23:59:50','00:00:05'), addtime('23:59:50','00:00:05') ;
+-------------------------------------------+--------------------------------+
| addtime('1997-12-31 23:59:50','00:00:05') | addtime('23:59:50','00:00:05') |
+-------------------------------------------+--------------------------------+
| 1997-12-31 23:59:55                       | 23:59:55                       |
+-------------------------------------------+--------------------------------+
1 row in set (0.00 sec)

4.subtime(d,t):起始时间d减去时间t

mysql> select subtime('1997-12-31 23:59:50','00:00:05'), subtime('23:59:50','00:00:05');     
+-------------------------------------------+--------------------------------+
| subtime('1997-12-31 23:59:50','00:00:05') | subtime('23:59:50','00:00:05') |
+-------------------------------------------+--------------------------------+
| 1997-12-31 23:59:45                       | 23:59:45                       |
+-------------------------------------------+--------------------------------+
1 row in set (0.00 sec)

5.datediff(d1,d2):返回起始时间d1和结束时间d2之间的天数

mysql> select datediff('1997-12-31 23:59:59','1997-12-30');
+----------------------------------------------+
| datediff('1997-12-31 23:59:59','1997-12-30') |
+----------------------------------------------+
|                                            1 |
+----------------------------------------------+
1 row in set (0.00 sec)

6.date_format(date,format):根据format字符串显示date值的格式

mysql> select date_format('2008-12-02 22:23:00', '%y %m %m %h:%i:%s');
+---------------------------------------------------------+
| date_format('2008-12-02 22:23:00', '%y %m %m %h:%i:%s') |
+---------------------------------------------------------+
| 2008 12 12 22:23:00                                     |
+---------------------------------------------------------+
1 row in set (0.00 sec)

7.str_to_date(str,format) 字符串转化为时间

mysql> select str_to_date('04/31/2004', '%m/%d/%y %h:%i:s');
+-----------------------------------------------+
| str_to_date('04/31/2004', '%m/%d/%y %h:%i:s') |
+-----------------------------------------------+
| 2004-04-31 00:00:00                           |
+-----------------------------------------------+
1 row in set (0.00 sec)

8.timestamp(expr) , timestamp(expr,expr2) :
对于一个单参数,该函数将日期或日期时间表达式 expr 作为日期时间值返回.对于两个参数, 它将时间表达式 expr2添加到日期或日期时间表达式 expr 中,将theresult作为日期时间值返回

mysql> select timestamp('2003-12-31'), timestamp('2003-12-31 12:00:00','12:00:00');
+-------------------------+---------------------------------------------+
| timestamp('2003-12-31') | timestamp('2003-12-31 12:00:00','12:00:00') |
+-------------------------+---------------------------------------------+
| 2003-12-31 00:00:00     | 2004-01-01 00:00:00                         |
+-------------------------+---------------------------------------------+
1 row in set (0.00 sec)

9.取当天0点0分,下一天0点0分

mysql> select timestamp(date(sysdate())),timestamp(adddate(date(sysdate()),1));     
+----------------------------+---------------------------------------+
| timestamp(date(sysdate())) | timestamp(adddate(date(sysdate()),1)) |
+----------------------------+---------------------------------------+
| 2008-12-02 00:00:00        | 2008-12-03 00:00:00                   |
+----------------------------+---------------------------------------+
1 row in set (0.00 sec)
来自:Alibaba DBA Team  作者:sky  2008-12-05

在 MySQL 中,只有一种 Join 算法,就是大名鼎鼎的 Nested Loop Join,他没有其他很多数据库所提供的 Hash Join,也没有 Sort Merge Join。顾名思义,Nested Loop Join 实际上就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。如果还有第三个参 与 Join,则再通过前两个表的 Join 结果集作为循环基础数据,再一次通过循环查询条件到第三个表中查询数据,如此往复。

还是通过示例和图解来说明吧,后面将通过我个人数据库测试环境中的一个 example(自行设计,非MySQL 自己提供) 数据库中的三个表的 Join 查询来进行示例。

注意:由于这里有些内容需要在MySQL 5.1.18之后的版本中才会体现出来,所以本测试的MySQL 版本为5.1.26

表结构:

sky@localhost : example11:09:32&gt; showcreatetableuser_group\G
***************************
1.row ***************************
Table: user_group
CreateTable: CREATETABLE`user_group`(
`user_id`int(11)NOTNULL,
`group_id`int(11)NOTNULL,
`user_type`int(11)NOTNULL,
`gmt_create`datetimeNOTNULL,
`gmt_modified`datetimeNOTNULL,
`status`varchar(16)NOTNULL,
KEY`idx_user_group_uid`(`user_id`)
)ENGINE=MyISAMDEFAULTCHARSET=utf8
1rowinset(0.00sec)sky@localhost : example11:10:32&gt; showcreatetablegroup_message\G
***************************
1.row ***************************
Table: group_message
CreateTable: CREATETABLE`group_message`(
`id`int(11)NOTNULLAUTO_INCREMENT,
`gmt_create`datetimeNOTNULL,
`gmt_modified`datetimeNOTNULL,
`group_id`int(11)NOTNULL,
`user_id`int(11)NOTNULL,
`author`varchar(32)NOTNULL,
`subject`varchar(128)NOTNULL,
PRIMARYKEY(`id`),
KEY`idx_group_message_author_subject`(`author`,`subject`(16)),
KEY`idx_group_message_author`(`author`),
KEY`idx_group_message_gid_uid`(`group_id`,`user_id`)
)ENGINE=MyISAMAUTO_INCREMENT=97DEFAULTCHARSET=utf8
1rowinset(0.00sec)sky@localhost : example11:10:43&gt; showcreatetablegroup_message_content\G
***************************
1.row ***************************
Table: group_message_content
CreateTable: CREATETABLE`group_message_content`(
`group_msg_id`int(11)NOTNULL,
`content`textNOTNULL,
KEY`group_message_content_msg_id`(`group_msg_id`)
)ENGINE=MyISAMDEFAULTCHARSET=utf8
1rowinset(0.00sec)

使用Query如下:

selectm.subjectmsg_subject, c.contentmsg_content
fromuser_groupg,group_messagem,group_message_contentc
whereg.user_id = 1
andm.group_id = g.group_id
andc.group_msg_id = m.id

看看我们的 Query 的执行计划:

sky@localhost : example11:17:04&gt; explainselectm.subjectmsg_subject, c.contentmsg_content
-&
gt; fromuser_groupg,group_messagem,group_message_contentc
-&
gt; whereg.user_id = 1
-&
gt; andm.group_id = g.group_id
-&
gt; andc.group_msg_id = m.id\G
***************************
1.row ***************************
id: 1
select_type: SIMPLE
table: g
type: ref
possible_keys: user_group_gid_ind,user_group_uid_ind,user_group_gid_uid_ind
key: user_group_uid_ind
key_len: 4
ref: const
rows: 2
Extra:
***************************
2.row ***************************
id: 1
select_type: SIMPLE
table: m
type: ref
possible_keys: PRIMARY,idx_group_message_gid_uid
key: idx_group_message_gid_uid
key_len: 4
ref: example.g.group_id
rows: 3
Extra:
***************************
3.row ***************************
id: 1
select_type: SIMPLE
table: c
type: ref
possible_keys: idx_group_message_content_msg_id
key: idx_group_message_content_msg_id
key_len: 4
ref: example.m.id
rows: 2
Extra:

我们可以看出,MySQL Query Optimizer 选择了 user_group 作为驱动表,首先利用我们传入的条件 user_id 通过 该表上面的索引 user_group_uid_ind 来进行 const 条件的索引 ref 查找,然后以 user_group 表中过滤出来的结果集的 group_id 字段作为查询条件,对 group_message 循环查询,然后再通过 user_group 和 group_message 两个表的结果集中的  group_message 的 id 作为条件 与 group_message_content 的 group_msg_id 比较进行循环查询,才得到最终的结果。没啥特别的,后一个引用前一个的结果集作为条件,实现过程可以通过下图表示:

下面的我们调整一下 group_message_content 去掉上面的 idx_group_message_content_msg_id 这个索引,然后再看看会是什么效果:

sky@localhost : example11:25:36&gt; dropindexidx_group_message_content_msg_idongroup_message_content;
QueryOK, 96rowsaffected(0.11sec)sky@localhost : example10:21:06&gt; explain
-&
gt; selectm.subjectmsg_subject, c.contentmsg_content
-&
gt; fromuser_groupg,group_messagem,group_message_contentc
-&
gt; whereg.user_id = 1
-&
gt; andm.group_id = g.group_id
-&
gt; andc.group_msg_id = m.id\G
***************************
1.row ***************************
id: 1
select_type: SIMPLE
table: g
type: ref
possible_keys: idx_user_group_uid
key: idx_user_group_uid
key_len: 4
ref: const
rows: 2
Extra:
***************************
2.row ***************************
id: 1
select_type: SIMPLE
table: m
type: ref
possible_keys: PRIMARY,idx_group_message_gid_uid
key: idx_group_message_gid_uid
key_len: 4
ref: example.g.group_id
rows: 3
Extra:
***************************
3.row ***************************
id: 1
select_type: SIMPLE
table: c
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 96
Extra: Usingwhere; Usingjoinbuffer

我们看到不仅仅 group_message_content 表的访问从 ref 变成了 ALL,此外,在最后一行的 Extra信息从没有任何内容变成为  Using where; Using join buffer,也就是说,对于从 ref 变成 ALL 很容易理解,没有可以使用的索引的索引了嘛,当然得进行全表扫描了,Using where 也是因为变成全表扫描之后,我们需要取得的 content 字段只能通过对表中的数据进行 where 过滤才能取得,但是后面出现的 Using join buffer 是一个啥呢?

我们知道,MySQL 中有一个供我们设置的参数 join_buffer_size ,这里实际上就是使用到了通过该参数所设置的 Buffer 区域。那为啥之前的执行计划中没有用到呢?

实际上,Join Buffer 只有当我们的 Join 类型为 ALL(如示例中),index,rang 或者是 index_merge 的时候 才能够使用,所以,在我们去掉 group_message_content 表的 group_msg_id 字段的索引之前,由于 Join 是 ref 类型的,所以我们的执行计划中并没有看到有使用 Join Buffer。

当我们使用了 Join Buffer 之后,我们可以通过下面的这张图片来表示 Join 完成过程:

原文出自:Sky.Jian 朝阳的天空MySQL 中 Join 的基本实现原理

来自:Alibaba DBA Team  作者:sky  2008-11-26

在此之前曾经写过一篇介绍 “Innodb 索引结构了解 - Innodb Index Structure” 的文章,这次再接着分析一下 MyISAM 存储引擎索引的基本存储结构。

从索引基本的存放数据结构来说,MyISAM 的索引不论是 Primary Key 还是普通 Index,存储结构都基本一样,基本结构都是 Balance Tree (简称为 B-Tree),所有的键值详细信息和行“指针”信息都存放于 B-Tree 的 Leaf Nodes 上面。这个基本的数据结构和 MySQL 的其他存储引擎如 Innodb 也基本相同。但是,MyISAM 的索引并不像 Innodb 存储引擎那样 Primary Key 和 Secondary Index 中存放的数据存在较大区别。在 MyISAM 存储引擎中,Primary Key 和其他的普通 Index 的主要区别仅仅在于 Primary Key 的索引键需要满足是非空的唯一值而已,另外一个区别其实也是每一个普通索引之间都存在的区别,就是整个索引树的键值排列顺序不太一样。

由于 MyISAM 存储引擎中数据行的存储分为固定长度和动态长度两种,所以在 MyISAM 存储引擎的数据文件中定位一行数据所需要信息也存在两种方式。一种是直接通过行号(row number)来定位固定长度表数据的行,另外一种是通过其他一些相对的文件位置标识信息来定位动态长度表数据的行,这里我们姑且将两种方式统称为 RID(Row ID)吧。

下面这张图片展示了 MyISAM 索引的基本存储方式:

myisam index structure

原文出自:Sky.Jian 朝阳的天空 MyISAM 索引结构了解 - MyISAM Index Structure

来自:车东[Blog^2]  2008-11-25

图片服务的特点就是:不修改,少量新增/极少删除,存储量大,需要尽量避免迁移和复制;旧的集群锁定后:对于原来的文件基本上就只删不增了;虽然目前有很多开源的分布式文件系统,但是目前比较便宜的解决方法还是本地硬盘服务器不断一组一组的增加,相互备份的一组服务器作为基础存储,然后前端使用缓存服务器;通过LVS或者CDN进行负载/分布的均衡

目前一台服务器配上T的存储也相对比较便宜;关键是如何尽量避免使用NFS进行使用;目前我们选择的办法是:图片服务器一组使用2台,一组服务器之间使用NFS相互mount用于备份;另外有上传文件服务器会NFS访问;对外服务文件使用Web服务器负载均衡。而在2台服务器上,会给予基于ID将用户的图片进行存储,存储的分布化会遇到一个问题:固定存储空间随着时间增加再次达到系统的空间/负载的瓶颈。观察了一下Flickr的图片存储地址:好像是在定期启用新的集群,各个时期的域名分布如下:

http://farm1.static.flickr.com 2006年中以前;
http://farm2.static.flickr.com 2006年底;
http://farm3.static.flickr.com 2007年底;
http://farm4.static.flickr.com 2008年底;

《构建可扩展的Web站点》上没有提到这个策略,猜测Flickr应该是不断在启用新的服务器集群,当地一个集群用到90%的时候,开始启用下一个集群。一个用户的所有图片地址则存储在数据库中:记录会包含当时的存储所在的集群:这个策略可以学习一下;
user_foo - farm1.static....../20060124_003.jpg
\ farm1.static....../20060324_005.jpg
\ farm1.static....../20060824_021.jpg
\ farm2.static....../20070124_006.jpg
\ farm3.static....../20080124_002.jpg
\ farm4.static....../20081124_001.jpg

另外如果希望前端存储使用的域名一直保持不变,通过目录规则进行rewrite的方式也是可以的,比如:将要发布的内容,后端按时间建立一个域名进行存储;

200711.foo.example.com
200712.foo.example.com
200801.foo.example.com
...
200811.foo.example.com

而前端则通过前端目录规则,将请求rewrite访问后台不同的存储服务器上:
foo.example.com/200711/ >> 200711.foo.example.com
foo.example.com/200712/ >> 200712.foo.example.com
...
foo.example.com/200811/ >> 200811.foo.example.com

这样就简单的实现了图片存储随时间增加而扩展的,每隔一定时间将上传服务器指向到新的服务器集群;

Berryline Logo
本页面由鲜果网创建,点击此处去鲜果尝尝鲜

在鲜果还可以:
不用反复刷新博客,鲜果帮你第一时间获取更新。
发现好文章,可以收藏起来,或与朋友分享。
阅读众多读者推荐的热门文章。
更多精彩的功能鲜果期待你来体验。