三个月了,第一次吃的那么香,那么饱…

周围提供的情报会带来幸运。像是工作上的伙伴与朋友为你带来好运的可能。对他们提供的机会和情报可多多留意、重视。而且一旦遇到机会可要积极一点行动,才 能追得上好运的波潮。尤其是平日较为保守的人在动作上不妨夸张一点、引人注目一点,不但不会惹人讨厌,相反的,幸运的时候可要比平常多。

看了双子座今天的运程(20110329),爱情指数:48%,工作指数:91%,财运指数:74%,健康指数:62%.失真之余又有点准确…

以前不大相信星座,也没怎么看过,在与一个很久以前就离职的同事的聊天中,开始对星座产生了点兴趣,不过还是没有去看过…

年前年后到现在,心情一直那么沉重,家里的事情,工作的事情,更重要的是跟你的事情,一波未平一波又起,喘也喘不过气来.于是有了看星座的习惯…

还好麻烦的,琐碎的事都处理得七七八八了,还剩下我俩,感情的那点事儿,一直在心里占着一大块的空间,说小事,却放不下,说大事,对一些人来说却是那么丁点的芝麻绿豆的琐碎.真遗憾,各位,那对我来说是件大事了.既然牵手了,就不会那么容易放手,既然选择了你,就不会那么容易放弃你.感情上的不成熟,做错了一些事情,在你最需要我的时候,我确不在你身边,一直都在为此事感到万分悔恨.那2500分,已经打折,只剩下1500,甚至更低的分数了… :(

想起离职那天晚上,劝了好久,你还是没陪我一起去参加聚餐,想在同事面前介绍一下你,虽然你们也相互认识,但这次的身份不同了,你是我的女朋友.在送你去坐车的路上,是这俩三个月来,跟你走得最近,聊得最多的一次了,可惜,我竟然紧张到舌头都全都打结,一句完整的话都没能说出来,一句想说的话都没说好 :( … 那晚,真还怕是因为离职你才跟我走近我,但在潜意识下又有了点星星之火:(… 矛盾,也许这就是双子座的双面性格了…

今晚是那么久以来(多久啊?俩三个月吧),第一次吃得那么香,那么饱,那么有滋味,可能就因为是你亲自下厨的原因吧,不是可能,是肯定了.今天工作了13个小时,全为了这一晚,今晚这一趟,最低的目的就是见一下你,一起走走,聊上几句.离职那晚你说的给我煮饭,我不敢抱太大希望,但今晚你给我了.可,这时,双子座的缺陷又来了,会不会是我们最后的一顿晚餐?欣喜之余又有点痛苦… -_-

双子座兄弟,究竟你们俩谁胜谁负啊?

CSS布局:让页底内容永远固定在底部

我们在设计一些页面内容甚少的网页时(典型应用就是登陆页面),由于显示器的分辨率大,在正常情况下,假如页面内容高度小于浏览器高度时,页面底部以下会留下很大的空间,如:http://www.helloweba.com/demo/cssfooter/demo1.html

不管浏览器的高度怎么变化,我们要想让页底内容始终固定在底部,最终效果如:http://www.helloweba.com/demo/cssfooter/demo2.html

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<title>无标题文档</title>
<style type=”text/css”>
* {margin:0;padding:0;}
html, body {height: 100%;}
#wrap {min-height: 100%;}
#main {overflow:auto;background:#f7f7f7;
padding-bottom: 60px;}  /* 必须使用和footer相同的高度 */
#footer {position: relative;
margin-top: -60px;
height: 60px;
clear:both;
background:#369}

/*Opera Fix*/
body:before {
content:”";
height:100%;
float:left;
width:0;
margin-top:-32767px;
}

</style>
<!–[if !IE 7]>
<style type=”text/css”>
#wrap {display:table;height:100%}
</style>
<![endif]–>
</head>

<body>
<div id=”wrap”>
<div id=”main”>
主体
</div>

</div>

<div id=”footer”>
这里是页底footer内容
</div>

</body>
</html>

mysql替换语句 部分替换

update tabel(表名) set Fields(字段名)=replace( Fields,’原内容’,'替换成的内容’)

UPDATE `cdb_pms`

SET `subject` = REPLACE(`subject`, ‘Welcome to’, ‘欢迎光临’)

WHERE INSTR(`subject`,’Welcome to’) > 0
替换cdb_posts表的message字段,将“viewthread.php?tid=3989”替换成“viewthread.php?tid=16546”

UPDATE `cdb_posts`

SET `message`= REPLACE(`message`, ‘viewthread.php?tid=3989′, ‘viewthread.php?tid=16546′)

WHERE INSTR(`message`,’viewthread.php?tid=3989′) > 0 ;

删除所有的空格

UPDATE `es_product`   SET `pro_pub_time` = TRIM(`pro_pub_time`)

lower或者upper

删除所有饱含’['或者']‘或者’.'的字符

UPDATE `es_product`   SET `pro_pub_time` = REPLACE(`pro_pub_time`, ‘[','')   WHERE INSTR(`pro_pub_time`,'[') > 0

UPDATE `es_product`   SET `pro_pub_time` = REPLACE(`pro_pub_time`, ']‘,”)   WHERE INSTR(`pro_pub_time`,’]') > 0

UPDATE `es_product`   SET `pro_pub_time` = REPLACE(`pro_pub_time`, ‘.’,'-’)   WHERE INSTR(`pro_pub_time`,’.') > 0

替换所有含中文’-'的为英文’-’

UPDATE `es_product`   SET `pro_pub_time` = REPLACE(`pro_pub_time`, ‘-’,'-’)   WHERE INSTR(`pro_pub_time`,’-’) > 0

将所有的年月都替换成’-’

UPDATE `es_product`   SET `pro_pub_time` = REPLACE(`pro_pub_time`, ‘年’,'-’)   WHERE INSTR(`pro_pub_time`,’年’) > 0

UPDATE `es_product`   SET `pro_pub_time` = REPLACE(`pro_pub_time`, ‘月’,'-’)   WHERE INSTR(`pro_pub_time`,’月’) > 0

将所有’2005-04-’这种类型的替换成’2005-04-01′

UPDATE `es_product`   SET `pro_pub_time` = CONCAT( `pro_pub_time`, ’01′)   WHERE SUBSTRING_INDEX( `pro_pub_time`, ‘-’, -1) = ” AND LENGTH(`pro_pub_time`) > 0 AND LENGTH(`pro_pub_time`) > 5

将所有’2005-’这种类型替换成’2005-01-01′

UPDATE `es_product`   SET `pro_pub_time` = CONCAT( `pro_pub_time`, ’01-01′) WHERE INSTR(`pro_pub_time`,’-') > 0 AND   LENGTH(`pro_pub_time`) = 5

将所有 饱含’-',但是位数小于8的改成追加’-01′

UPDATE `es_product`   SET `pro_pub_time` = CONCAT( `pro_pub_time`, ‘-01′) WHERE INSTR(`pro_pub_time`,’-') > 0 AND   LENGTH(`pro_pub_time`) < 8

将所有’2005′这样的改成’2005-01-01′

UPDATE `es_product`   SET `pro_pub_time` = CONCAT(`pro_pub_time`,’-01-01′) WHERE INSTR(`pro_pub_time`,’-') = 0 AND   LENGTH(`pro_pub_time`) = 4

最后将所有’2005-01-01′格式化成’2005年01月’

UPDATE `es_product`   SET `pro_pub_time` = DATE_FORMAT(`pro_pub_time`,’%Y年%m月’) WHERE INSTR(`pro_pub_time`,’-') > 0

批量替换 MySQL 指定字段中的字符串是数据库mysql替换语句 部分替换应用中很常见的需求,但是有很多初学者在遇到这种需求时,通常都是用脚本来实现;其实,MySQL 内置的有批量替换语法,效率也会高很多;想了解具体方法mysql替换语句 部分替换,继续阅读本文吧 :)

批量替换的具体语法是:

Code:

UPDATE 表名 SET

指定字段 = replace(指定字段, ’要替换的字符串’, ’想要的字符串’)

WHERE 条件;

如果你想把 article 表中 ID 小于5000的记录,content 字段中“解决”替换成“解放”,那么语法就是:

Code:

UPDATE article SET

content = replace(content, ’解决’, ’解放’)

WHERE ID<5000;

UPDATE `fengsh_shoplist`

SET `s_clickurl`= REPLACE(`s_clickurl`, ’15252835′, ’10190773′)

如何使用Sphinx来实现全文检索(搜索)功能

前年(2009)在参与开发CMSTOP系统时,就知道此CMS使用Sphinx实现进行全文检索功能。但那时候自己并没有这功能的开发。不过了解了Sphinx的全文搜索的强大功能。这次,在新的公司,也要做一个全文搜索功能。第一时间就想到了Sphinx来进行功能的实现。

当然在实际上,Sphinx对中文的分词功能并不好。可是很庆幸地是,Coreseek很好地帮我们解决了这一个问题。在这里很感谢此团队为开源事业做出的贡献。Sphinx能得到很多人的认同与用使用,很大一部分功劳和这团队关系。关于此团队更多信息可查看Coreseek首页。

下面我就基本地简介一下如何使用Sphinx来实现全文检索功能,当然大部分安装信息都是在Coreseek主站上直接copy下来,因为他们写的实在太详细了。让我没有任何可发挥的地方。

1.下载Sphinx 支持中文分词Coreseek  http://www.coreseek.cn/news/11/52/

2.进行安装:参考http://www.coreseek.cn/products-install/install_on_bsd_linux/
##下载coreseek:coreseek 3.2.14:点击下载、coreseek 4.0.1:点击下载

$ wget http://www.coreseek.cn/uploads/csft/3.2/coreseek-3.2.14.tar.gz
$ 或者 http://www.coreseek.cn/uploads/csft/4.0/coreseek-4.0.1-beta.tar.gz
$ tar xzvf coreseek-3.2.14.tar.gz 或者 coreseek-4.0.1-beta.tar.gz
$ cd coreseek-3.2.14 或者 coreseek-4.0.1-beta

##安装mmseg

$ cd mmseg-3.2.14
$ ./bootstrap    #提示中如无error可以不用理会
$ ./configure --prefix=/usr/local/mmseg3
$ make && make install
$ cd ..

##安装coreseek,需提前安装mysql依赖库及操作系统基础开发库以支持mysql数据源和xml数据源

$ cd csft-3.2.14 或者 cd csft-4.0.1
$ sh buildconf.sh    #提示中如无error可以不用理会
$ ./configure --prefix=/usr/local/coreseek  --without-unixodbc --with-mmseg --with-mmseg-includes=/usr/local/mmseg3/include/mmseg/
--with-mmseg-libs=/usr/local/mmseg3/lib/ --with-mysql    ##如果提示mysql问题,可以查看MySQL数据源安装说明
$ make && make install
$ cd ..

##测试mmseg分词,coreseek搜索(需要预先设置好字符集为zh_CN.UTF-8,确保正确显示中文)

$ cd testpack
$ cat var/test/test.xml    #此时应该正确显示中文
$ /usr/local/mmseg3/bin/mmseg -d /usr/local/mmseg3/etc var/test/test.xml
$ /usr/local/coreseek/bin/indexer -c etc/csft.conf --all

 

3.增加Sphinx增量索引

a.先建立一个计数表

CREATE TABLE sph_counter(
  		counter_id INTEGER PRIMARY KEY NOT NULL,
  		max_doc_id INTEGER NOT NULL
     );

b.修改sphinx.conf

#主要数据源
      source main
	{
    	type                    = mysql

    	sql_host                = localhost
    	sql_user                = oophp
    	sql_pass                = oophp.cn
    	sql_db                    = oophp
    	sql_port                = 3306
    	sql_query_pre            = SET NAMES utf8
    	sql_query_pre	    =REPLACE INTO sph_counter SELECT 1, MAX(id) FROM dede_archives
    	sql_query                = Select  *  From article where channel=3 AND id<=( SELECT max_doc_id FROM sph_counter WHERE counter_id=1 )
                                                              	#sql_query第一列id需为整数
                                                              	#title、content作为字符串/文本字段,被全文索引
    	#sql_attr_uint            =id           #从SQL读取到的值必须为整数
    	#sql_attr_timestamp        =pubdata_attr #从SQL读取到的值必须为整数,作为时间属性

    	sql_query_info_pre      = SET NAMES utf8                                        #命令行查询时,设置正确的字符集
    	sql_query_info = Select * From article WHERE channel=3  AND id=$id
	}

       #增量数据源
	source delta : main
	{
		sql_query_pre =SET NAMES utf8
        	sql_query = Select * From article  where  channel=3 AND \
	id>( SELECT max_doc_id FROM sph_counter WHERE counter_id=1 )
	}

	#主索引生成
	index main
	{
    	source            = main             #对应的source名称
    	path            = /usr/local/coreseek/data/main/ #请修改为实际使用的绝对路径,例如:/usr/local/coreseek/var/...
    	docinfo            = extern
    	mlock            = 0
    	morphology        = none
    	min_word_len        = 1
    	html_strip                = 0
    	ngram_len=0
    	#中文分词配置,详情请查看:http://www.coreseek.cn/products-install/coreseek_mmseg/
    	charset_dictpath = /usr/local/mmseg3/etc/   #BSD、Linux环境下设置,/符号结尾
    	#charset_dictpath = etc/                             #Windows环境下设置,/符号结尾,最好给出绝对路径,例如:C:/usr/local/coreseek/etc/...
    	charset_type        = zh_cn.utf-8
    	#charset_type        = utf-8
    	#charset_table        = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F
    	#ngram_chars        = U+3000..U+2FA1F

	}

       #增量索引
	index delta : main
	{
    		source            = delta             #对应的source名称
    		path            = /usr/local/coreseek/data/delta/ #请修改为实际使用的绝对路径,例如:/usr/local/coreseek/var/...
	}
	#全局index定义
	indexer
	{
    		mem_limit            = 128M
	}

	#searchd服务定义
	searchd
	{
    		listen                  =   9312
    		read_timeout        = 5
    		max_children        = 30
    		max_matches            = 1000
    		seamless_rotate        = 0
    		preopen_indexes        = 0
    		unlink_old            = 1
    		pid_file = /var/log/searchd.pid  #请修改为实际使用的绝对路径,例如:/usr/local/coreseek/var/...
    		log = /var/log/searchd_mysql.log        #请修改为实际使用的绝对路径,例如:/usr/local/coreseek/var/...
    		query_log = /var/log/query_mysql.log #请修改为实际使用的绝对路径,例如:/usr/local/coreseek/var/...
    		binlog_path =                                #关闭binlog日志
	}

 

c.启动sphinx服务,并生成主索引

#/usr/local/coreseek/bin/searchd
 # /usr/local/coreseek/bin/indexer -c /usr/local/coreseek/etc/sphinx.conf main --rotate

d.建立生成主索引和增量索引shell脚本

build_main_index.sh脚本:
		#!/bin/sh
		#/usr/local/coreseek/bin/searchd --stop
		/usr/local/coreseek/bin/indexer -c /usr/local/coreseek/etc/sphinx.conf main --rotate 

build_delta_index.sh脚本:
		#!/bin/sh
		#/usr/local/coreseek/bin/searchd --stop
		/usr/local/coreseek/bin/indexer  -c /usr/local/coreseek/etc/sphinx.conf  delta --rotate
		/usr/local/coreseek/bin/indexer  -c /usr/local/coreseek/etc/sphinx.conf --merge main delta --merge-dst-range deleted 0 0 --rotate
		#/usr/local/coreseek/bin/searchd

e.写入cron计划任务中,生成增量索引,并重新建立主索引

//每10分钟生成一次索引
*/10 * * * *  /bin/sh /usr/local/coreseek/build_delta_index.sh >/dev/null 2>&1  

//每天凌晨3点过5分,重新建立一次主索引
5 3 * * *  /bin/sh /usr/local/coreseek/build_main_index.sh > /dev/null 2>&1

参考网站:

http://sphinxsearch.com/

http://www.coreseek.cn/

http://www.sphinxsearch.org/archives/category/sphinx

http://blog.c1gstudio.com/archives/730

MYSQL查询多余重复的记录

(一)
1、查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断
select * from people
where peopleId in (select  peopleId  from  people  group  by  peopleId  having  count(peopleId) > 1)

2、删除表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断,只留有rowid最小的记录
delete from people
where peopleId  in (select  peopleId  from people  group  by  peopleId    having  count(peopleId) > 1)
and rowid not in (select min(rowid) from  people  group by peopleId  having count(peopleId )>1)

3、查找表中多余的重复记录(多个字段)
select * from vitae a
where (a.peopleId,a.seq) in  (select peopleId,seq from vitae group by peopleId,seq  having count(*) > 1)

4、删除表中多余的重复记录(多个字段),只留有rowid最小的记录
delete from vitae a
where (a.peopleId,a.seq) in  (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1)
and rowid not in (select min(rowid) from vitae group by peopleId,seq having count(*)>1)

5、查找表中多余的重复记录(多个字段),不包含rowid最小的记录
select * from vitae a
where (a.peopleId,a.seq) in  (select peopleId,seq from vitae group by peopleId,seq having count(*) > 1)
and rowid not in (select min(rowid) from vitae group by peopleId,seq having count(*)>1)

(二)
比方说
在A表中存在一个字段“name”,
而且不同记录之间的“name”值有可能会相同,
现在就是需要查询出在该表中的各记录之间,“name”值存在重复的项;
Select Name,Count(*) From A Group By Name Having Count(*) > 1

如果还查性别也相同大则如下:
Select Name,sex,Count(*) From A Group By Name,sex Having Count(*) > 1

(三)
方法一

declare @max integer,@id integer

declare cur_rows cursor local for select 主字段,count(*) from 表名 group by 主字段 having count(*) >; 1

open cur_rows

fetch cur_rows into @id,@max

while @@fetch_status=0

begin

select @max = @max -1

set rowcount @max

delete from 表名 where 主字段 = @id

fetch cur_rows into @id,@max

end

close cur_rows

set rowcount 0

方法二

有两个意义上的重复记录,一是完全重复的记录,也即所有字段均重复的记录,二是部分关键字段重复的记录,比如Name字段重复,而其他字段不一定重复或都重复可以忽略。

1、对于第一种重复,比较容易解决,使用

select distinct * from tableName

就可以得到无重复记录的结果集。

如果该表需要删除重复的记录(重复记录保留1条),可以按以下方法删除

select distinct * into #Tmp from tableName

drop table tableName

select * into tableName from #Tmp

drop table #Tmp

发生这种重复的原因是表设计不周产生的,增加唯一索引列即可解决。

2、这类重复问题通常要求保留重复记录中的第一条记录,操作方法如下

假设有重复的字段为Name,Address,要求得到这两个字段唯一的结果集

select identity(int,1,1) as autoID, * into #Tmp from tableName

select min(autoID) as autoID into #Tmp2 from #Tmp group by Name,autoID

select * from #Tmp where autoID in(select autoID from #tmp2)

最后一个select即得到了Name,Address不重复的结果集(但多了一个autoID字段,实际写时可以写在select子句中省去此列)

(四)
查询重复

select * from tablename where id in (

select id from tablename

group by id

having count(id) > 1

)

PHP中跳出多重循环使用break,continue,goto,return,exit的区别

今天在写一段PHP程序时,犯了一个小错误结果耽误了很长时间,后来发现原来是多重循环没有控制好的问题。后来整理了在PHP中跳出循环的各种用法,以及它们的区别,与大家分享。

PHP中的循环结构大致有for循环,while循环,do{} while 循环以及foreach循环几种,不管哪种循环中,在PHP中跳出循环大致有这么几种方式:

continue

continue 是用来用在循环结构中,控制程序放弃本次循环continue语句之后的代码并转而进行下一次循环。continue本身并不跳出循环结构,只是放弃这一次循环。如果在非循环结构中(例如if语句中,switch语句中)使用continue,程序将会出错。

例如在下面的这段PHP代码片段中:
<?php
for($i = 1;$i <= 100; $i++ ){
if($i % 3 == 0 || $i % 7 == 0){
continue;
}
& #160;  else{
echo”$i \n<br/>”;
}
}
?>

PHP的代码片段的作用是输出100以内,既不能被7整除又不能被3整除的那些自然数,循环中先用if条件语句判断那些能被整除的数,然后执行continue;语句,就直接进入了下个循环。不会执行下面的输出语句了。

break

break是被用在上面所提的各种循环和switch语句中的。他的作用是跳出当前的语法结构,执行下面的语句。break语句可以带一个参数n,表示跳出循环的层数,如果要跳出多重循环的话,可以用n来表示跳出的层数,如果不带参数默认是跳出本重循环。

看下面这个多重循环嵌套的例子:
for($i = 1;$i <= 10; $i++ ){
for($j = 1;$j <= 10;$j++){
$m = $i * $i + $j * $j;
echo”$m \n<br/>”;
if($m < 90 || $m > 190) {
break 2;
}
}
}

这里使用了break 2跳出了两重循环,你可以试验一眼,将2去掉,得到的结果是完全不一样的。如果不使用参数,跳出的只是本次循环,第一层循环会继续执行下去。

goto

goto实 际上只是一个运算符,和其他语言一样,PHP中也不鼓励滥用goto,滥用goto会导致程序的可读性严重下降。goto的作用是将程序的执行从当前位置 跳转到其他任意位置,goto本身并没有要结束的循环的作用,但其跳转位置的作用使得其可以作为跳出循环使用。但PHP5.3及以上版本停止了对goto 的支持,所以应该尽量避免使用goto。
下面的是一个使用了goto跳出循环的例子
for($i = 1000;$i >= 1 ; $i– ){
if( sqrt($i) <= 29){
goto a;
}
echo “$i”;
}
a:
echo” this is the end”;

例子中使用了goto来跳出循环,这个例子用来检测1000以内,那些数的平方根大于29。

exit

exit是用来结束程序执行的。可以用在任何地方,本身没有跳出循环的含义。exit可以带一个参数,如果参数是字符串,PHP将会直接把字符串输出,如果参数是integer整形(范围是0-254),那个参数将会被作为结束状态使用。

<?php
for($i = 1000;$i >= 1 ; $i– ){
if( sqrt($i) >= 29){
echo”$i \n<br/>”;
}
else{
exit;
}
}
echo”本行将不会被输出”;
?>

上面这个例子中直接在从循环里结束了代码的运行,这样会导致后面的代码都不会被执行,如果是在一个php web 页面里面,甚至连exit后面的html代码都不会被输出。

return

return 语句是用来结束一段代码,并返回一个参数的。可以从一个函数里调用,也可以从一个include()或者require()语句包含的文件里来调用,也可 以是在主程序里调用,如果是在函数里调用程序将会马上结束运行并返回参数,如果是include()或者require()语句包含的文件中被调用,程序 执行将会马上返回到调用该文件的程序,而返回值将作为include()或者require()的返回值。而如果是在主程序中调用,那么主程序将会马上停 止执行

<?php
for($i = 1000;$i >= 1 ; $i– ){
if( sqrt($i) >= 29){
echo”$i \n<br/>”;
}
else{
return;
}
}
echo”本行将不会被输出”;
?>

这里的例子和上面使用exit的效果是一样的。

在循环结束条件,自然跳出

这个当然是最好理解了,当循环满足循环临界条件时就是自己退出。

以上是PHP中跳出循环的几种方式的简单总结。

MYSQL的COUNT函数

数据库经常用于回答这个问题,“某个类型的数据在表中出现的频度?”例如,你可能想要知道你有多少宠物,或每位主人有多少宠物,或你可能想要对你的动物进行各种类型的普查。

计算你拥有动物的总数目与“在pet表中有多少行?”是同样的问题,因为每个宠物有一个记录。COUNT(*)函数计算行数,所以计算动物数目的查询应为:

mysql> SELECT COUNT(*) FROM pet;
+----------+
| COUNT(*) |
+----------+
|        9 |
+----------+

在前面,你检索了拥有宠物的人的名字。如果你想要知道每个主人有多少宠物,你可以使用COUNT( )函数:

mysql> SELECT owner, COUNT(*) FROM pet GROUP BY owner;
+--------+----------+
| owner  | COUNT(*) |
+--------+----------+
| Benny  |        2 |
| Diane  |        2 |
| Gwen   |        3 |
| Harold |        2 |
+--------+----------+

注意,使用GROUP BY对每个owner的所有记录分组,没有它,你会得到错误消息:

mysql> SELECT owner, COUNT(*) FROM pet;
ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...)
with no GROUP columns is illegal if there is no GROUP BY clause

COUNT( )和GROUP BY以各种方式分类你的数据。下列例子显示出进行动物普查操作的不同方式。

每种动物的数量:

mysql> SELECT species, COUNT(*) FROM pet GROUP BY species;
+---------+----------+
| species | COUNT(*) |
+---------+----------+
| bird    |        2 |
| cat     |        2 |
| dog     |        3 |
| hamster |        1 |
| snake   |        1 |
+---------+----------+

每种性别的动物数量:

mysql> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
+------+----------+
| sex  | COUNT(*) |
+------+----------+
| NULL |        1 |
| f    |        4 |
| m    |        4 |
+------+----------+

(在这个输出中,NULL表示“未知性别”。)

按种类和性别组合的动物数量:

mysql> SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;

+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+

PHP字符串操作入门教程

无论哪种语言,字符串操作都是一个重要的基础,往往是简单而重要。正像人说话一样,一般有形体(图形界面),有语言(print 字符串?),显然字符串能解释更多的东西。PHP提供了大量的字符串操作函数,功能强大,使用也比较简单,详细请参看 http://cn2.php.net/manual/zh/ref.strings.php . 以下将简单的讲述它的功能和特性。
弱类型
PHP是弱类型语言,所以其它类型的数据一般可以直接应用于字符串操作函数里,而自动转换成字符串类型,进行处理,如:

PHP:


echo substr("1234567", 1, 3);

PHP:


echo substr(123456,1, 3);

是一样的

定义
一般用双引号或单引号标识一个字符串。比如

PHP:


$str = "i love u";
$str = 'i love u';

它者两者是有一些区别的。后者将一切单引号的内容都会当作字符处理;前者则不然。比如

PHP:


$test = "iwind";
$str = "i love $test";
$str1 = 'i love $test';
echo $str; //将得到 i love iwind
echo $str1; //将得到 i love $test

同样的以下两个例子的行为也不一样的:

PHP:


echo "i love \test"; // 将得到 i love est,已经将\t视为转义
echo 'i love \test'; // 将得到 i love \test

从而可以简单认为双引号里的内容是经过“解释”过的,单引号的是“所见即所得”的。显而易见,双引号形式的更为灵活一些,当然单引号会适用于一些特殊的场合,这里就不作阐述了。

输出
PHP里的输出最常用的是echo,print.两者都不是真正的函数,而是语言构造,所以调用时不必用双括号(比如echo(“test”);print(“test”)).在输出的时候两者都可以实现赋值:

PHP:


echo $str="test"; //一方面输出test,一方面把"test"赋给字符串变量 $str
print $str="test";

两者除了名字不一样外,还是有其它区别的。print具有返回值,一直返回1,而echo没有,所以echo比print要快一些:

PHP:


$return = print "test";
echo $return; // 输出1

也正因为这个原因,print能应用于复合语句中,而echo不能:

PHP:


isset($str) or print "str 变量未定义"; // 将输出"str 变量未定义"
isset($str) or echo "str 变量未定义";// 将提示分析错误

echo一次可输出多个字符串,而print则不可以:

PHP:


echo "i ","love ","iwind"; // 将输出 "i love iwind"
print "i ","love ","iwind"; // 将提示错误

echo,print还可以输出被称作“文档句法”的字符串,句法如:

PHP:


echo <<< 标签名称
...
字符串内容
...
标签名称;

比如

PHP:


echo <<< test
i love iwind
test;

要注意的是语句开始和结束的两个标签名称是一样的,且后一个标签名称前不能有空白,即要顶格写。文档句法输出的内容识别变量名称和常用符号,大致形同双引号的作用。

输出echo,print外,PHP还提供了一些格式化字符串的函数,比如printf,sprintf,vprintf,vsprintf,在这里不作详解。

连接
两个以上的字符串连接用”.”操作符,依字符串的顺序形成新的字符串。

PHP:


$str = "i " . "love " . "iwind";
这里的$str 就是 "i love iwind";字符串。当然,还可以使用 .= 操作符:
$str = ""; // 初始化
$str .= "i love iwind";

这里用到了初始化,是因为未定义变量在使用时会产生一个notice错误,”"或者null可以简单地代表空字符串。

长度
PHP提供strlen函数来计算字符串的长度:

PHP:


$str = "test";
echo strlen($str); // 将输出 4

有点奇怪的是strlen将中日等汉字以及全角字符都当作两个或四个长度计算。好在mbstring或icon两个函数可以帮助解决这个问题,比如:

PHP:


$len = iconv_strlen($str, "GBK");
$len = mb_strlen($str, "GBK");

注:mbstring模块提供了大量的对含有多字节字符的字符串的处理函数,推荐多加应用,由于这篇文章讲的是字符串入门,所以不打算详细解说。

分隔与连接
PHP允许你把一个字符串按照一个分隔符进行分隔成一个数组,或者将一个数组组合成一个字符串。看下面的例子:

PHP:


$str = "i love iwind";
$array = explode(" ", $str);

上面的explode函数,就把$str字符串按空格字符进行分隔,结果返回一个数组 $array:array(“i”, “love”, “iwind”).与explode函数有类似功能的有:preg_split(), spliti(), split()等函数。

与此相反的,implode和join则能把一个数组结合成一个字符串,他们是具有完全相同功能的函数。

PHP:


$array = array("i", "love", "iwind");
$str = implode(" ", $array);
例中的implode函数将数组$array的每个元素用空格字符进行连接,返回一个字符串 $str: "i love iwind".

裁剪
一个字符串首和尾,可能不是你想要的部分,就可以用trim,rtrim,ltrim等函数,分别去除一个字符串两端空格,一个字符串尾部空格,一个字符串首部空格。

PHP:


echo trim(" i love iwind "); // 将得到 "i love iwind"
echo rtrim(" i love iwind "); // 将得到 " i love iwind"
echo ltrim(" i love iwind "); // 将得到 "i love iwind "

其实这三个参数不仅可以去除字符串首尾的空格,还可以去除它们的第二个参数指定的字符,如:

PHP:


echo trim(",1,2,3,4,", ","); // 将得到 1,2,3,4 两端的","号被裁掉了。

有时还会看到有人使用chop这个函数,其实它是rtrim的同义函数。

大小写
对于英文字母来说,可以用strtoupper,strtolower将其转变成大写或小写。

PHP:


echo strtoupper("i love iwind"); // 将得到 I LOVE IWIND
echo strtolower("I LOVE IWIND"); // 将得到 i love iwind

比较
一般可以用 !=, == 比较两个对象是否相等,只所以说是两个对象,是因为它们不一定全部为字符串,也可以为整型等等。比如

PHP:


$a = "joe";
$b = "jerry";
if ($a != $b)
{
echo "不相等";
}
else
{
echo "相等";
}

如果用 !==,===(可以看到多了一个等号)比较的话,两个对象的类型要严格相等才能返回true;否则用==,!=则会将字符串自动转换成相应的类型,以便进行比较.

PHP:


22 == "22"; // 返回 true
22 === "22"; // 返回false
//正因为这样,所以我们的程序时常会发生一些想不到的"意外":
0 == "我爱你"; // 返回true
1 == "1 我爱你";// 返回true

PHP里还有这样一组用于字符串比较的函数:strcmp,strcasecmp,strncasecmp(), strncmp(),它们都是如果前者比后者大,则返回大于0的整数;如果前者比后者小,则返回小于0的整数;如果两者相等,则返回0.它们比较的原理与其它语言的规则都是一样的。
strcmp是用于区分大小写(即大小写敏感)的字符串比较:

PHP:


echo strcmp("abcdd", "aBcde"); // 返回 1 (>0), 比较的是 "b"和"B"

strcasecmp用于不区分大小写的字符串比较:

PHP:


echo strcasecmp("abcdd", "aBcde"); // 返回 -1 (<0), 比较的是"d"和"e"

strncmp用于比较字符串的一部分,从字符串的开头开始比较,第三个参数,为要比较的长度:

PHP:


echo strncmp("abcdd", "aBcde", 3); // 返回 1 (>0), 比较了 abc 和 aBc

strncasecmp用于不区分大小写的比较字符串的一部分,从字符串的开头开始比较,第三个参数,为要比较的长度:

PHP:


echo strncasecmp("abcdd", "aBcde", 3); // 返回 0, 比较了 abc 和 aBc,

由于不区分大小写,所以两者是相同的。

还有一种情况是单单比较字符串大小,达不到我们预定的要求,比如照常理 10.gif 会比 5.gif 大,但如果应用上面几个函数,就会返回 -1,即表示 10.gif比5.gif,针对这种情况,PHP提供了两个自然对比的函数strnatcmp,strnatcasecmp:

PHP:


echo strnatcmp("10.gif", "5.gif"); // 返回 1 (>0)
echo strnatcasecmp("10.GIF", "5.gif"); // 返回 1 (>0)

替换
替换的意义在于将一个字符串的一部分进行改变,使之成为别外一个新的字符串,以满足新的要求。PHP里通常用str_replace(“要替换的内容”, “要取代原内容的字符串”, “原字符串”)进行替换。

PHP:


echo str_replace("iwind", "kiki", "i love iwind, iwind said"); // 将输出 "i love kiki, kiki said"

即将 原字符串中的所有”iwind”都替换成了”kiki”.

str_replace是大小写敏感的,所以对你不能设想用 str_replace(“IWIND”, “kiki”,…)替换原字符串中的”iwind”.

str_replace还可以实现多对一,多对多的替换,但无法实现一对多的替换:

PHP:


echo str_replace(array("iwind", "kiki"), "people", "i love kiki, iwind said");

将会输出
i love people, people said
第一个参数中的array(“iwind”, “kiki”)都被替换成了”people”

PHP:


echo str_replace(array("iwind", "kiki"), array("gentle man", "ladies"), "i love kiki, iwind said");

输出 i love ladies, gentle man said 。也就是说第一个数组中的元素被第二个数组中的相对应的元素替换掉了,如果有一个数组比另一个数组元素数要少,那么不足的都会当作空来处理。

与此有些类似的是strtr,用法请参阅手册,它们的比较请参阅 http://diary.4kiki.net/index.php?action=info&id=372 .

此外,PHP还提供了substr_replace,实现替换一部分的字符串。语法如下:
substr_replace (原字符串, 要替代的字符串, 开始替换的位置 [, 替换的长度])
其中,开始替换的位置从0开始计算,应该小于原字符串的长度。要替换的长度是可选的。

PHP:


echo substr_replace("abcdefgh", "DEF", 3); // 将输出 "abcDEF"
echo substr_replace("abcdefgh", "DEF", 3, 2); // 将输出 "abcDEFfgh"

第一个例子中,从第三个位置(即”d”)开始替换,从而把 “defgh”都替换成了“DEF”
第二个例子中,也是从第三个位置(即”d”)开始替换,但只能替换2个长度,即到e,所以就把”de”替换成了”DEF”.

PHP还提供了preg_replace,preg_replace_callback,ereg_replace,eregi_replace等函数应用正则表达式来完成字符串替换,用法请参考手册。

查找与匹配
PHP里用于查找或者匹配或者定位的函数非常多,它们都有不同的意义。这里只讲述用得比较多的strstr,stristr.后者与前者的功能,返回值都一样,只是不区分大小写。
strstr(“母字符串”, “子字符串”)用来查找子字符串在母字符串中第一次出现的位置,并返回母字符串中从子字符串开始到母字符串结束的部分。比如
echo strstr(“abcdefg”, “e”); //将输出 “efg”
如果找不到子字符串,则返回空。因为可以用来判断一个字符串中是否含有另外一个字符串:

PHP: [Copy to clipboard]


$needle = "iwind";
$str = "i love iwind";
if (strstr($str, $needle))
{
echo "里面有 iwind";
}
else
{
echo "里面没有 iwind";
}
将会输出"里面有 iwind"

HTML相关
1,htmlspecialchars($string)
这是它的最简单用法,将字符串中的一些特殊字符(顾名思义)&,’,”<,>转换成它们对应的HTML实体形式:

PHP:


$str = "i love <font color=\"red\">kiki</font>, iwind said.";
echo htmlspecialchars($str);

将会输出
i love &lt;font color=&quot;red&quot;&gt;kiki&lt;/font&gt;, iwind said.

2,htmlentities($string)
将所有能转换成实体形式的字符都转换成实体形式。

3,html_entity_decode($string);
PHP4.3.0以后加入的具有与htmlentities($string)相反的功能。

4,nl2br($string)
将字符串中所有换行符转变成<br /> + 换行符。如:

PHP:


$str = "i love kiki,\n iwind said.";
echo nl2br($str);

将会输出
i love kiki,<br />
iwind said.

加密
加密字符串最常用的就是md5了,它将一个字符串转换成一个长32位的唯一的字符串。

PHP:


echo md5("i love iwind"); // 将输出 "2df89f86e194e66dc54b30c7c464c21c"

PHP5给md5加了第二个参数,从而使它可以输出16位的加密后的字符串。

到这里,这篇字符串操作入门教程就算结束了,但上面讲的这些还只是它的冰山一角,特别是PHP5之后增加了大量的新功能,所以需要我们不断的去学习它才有可能很好的应用。

大型网站架构演变

之前也有一些介绍大型网站架构演变的文章,例如LiveJournal的、ebay的,都是非常值得 参考的,不过感觉他们讲的更多的是每次演变的结果,而没有很详细的讲为什么需要做这样的演变,再加上近来感觉有不少同学都很难明白为什么一个网站需要那么 复杂的技术,于是有了写这篇文章的想法,在这篇文章中将阐述一个普通的网站发展成大型网站过程中的一种较为典型的架构演变历程和所需掌握的知识体系,希望 能给想从事互联网行业的同学一点初步的概念,:),文中的不对之处也请各位多给点建议,让本文真正起到抛砖引玉的效果。

架构演变第一步:物理分离webserver和数据库

最开始,由于某些想法,于是在互联网上搭建了一个网站,这个时候甚至有可能主机都是租借的,但由于这篇文章我们只关注架构的演变历程,因此就假 设这个时候 已经是托管了一台主机,并且有一定的带宽了,这个时候由于网站具备了一定的特色,吸引了部分人访问,逐渐你发现系统的压力越来越高,响应速度越来越慢,而 这 个时候比较明显的是数据库和应用互相影响,应用出问题了,数据库也很容易出现问题,而数据库出问题的时候,应用也容易出问题,于是进入了第一步演变阶段: 将应用和数据库从物理上分离,变成了两台机器,这个时候技术上没有什么新的要求,但你发现确实起到效果了,系统又恢复到以前的响应速度了,并且支撑住了更 高的流量,并且不会因为数据库和应用形成互相的影响。

看看这一步完成后系统的图示:

 

 

物理分离webserver和数据库

这一步涉及到了这些知识体系:

这一步架构演变对技术上的知识体系基本没有要求。

架构演变第二步:增加页面缓存

好景不长,随着访问的人越来越多,你发现响应速度又开始变慢了,查找原因,发现是访问数据库的操作太多,导致数据连接竞争激烈,所以响应变慢, 但数据库连 接又不能开太多,否则数据库机器压力会很高,因此考虑采用缓存机制来减少数据库连接资源的竞争和对数据库读的压力,这个时候首先也许会选择采用squid 等类似的机制来将系统中相对静态的页面(例如一两天才会有更新的页面)进行缓存(当然,也可以采用将页面静态化的方案),这样程序上可以不做修改,就能够 很好的减少对webserver的压力以及减少数据库连接资源的竞争,OK,于是开始采用squid来做相对静态的页面的缓存。

看看这一步完成后系统的图示:

 

增加页面缓存

 

增加页面缓存

这一步涉及到了这些知识体系:

前端页面缓存技术,例如squid,如想用好的话还得深入掌握下squid的实现方式以及缓存的失效算法等。

架构演变第三步:增加页面片段缓存

增加了squid做缓存后,整体系统的速度确实是提升了,webserver的压力也开始下降了,但随着访问量的增加,发现系统又开始变的有些 慢了,在尝到了squid之类的动态缓存带来的好处后,开始想能不能让现在那些动态页面里相对静态的部分也缓存起来呢,因此考虑采用类似ESI之类的页面 片段缓存策略,OK,于是开始采用ESI来做动态页面中相对静态的片段部分的缓存。

看看这一步完成后系统的图示:

 

 

增加页面片段缓存

这一步涉及到了这些知识体系:

页面片段缓存技术,例如ESI等,想用好的话同样需要掌握ESI的实现方式等;

架构演变第四步:

在采用ESI之类的技术再次提高了系统的缓存效果后,系统的压力确实进一步降低了,但同样,随着访问量的增加,系统还是开始变慢,经过查找,可 能会发现系统中存在一些重复获取数据信息的地方,像获取用户信息等,这个时候开始考虑是不是可以将这些数据信息也缓存起来呢,于是将这些数据缓存到本地内 存,改变完毕后,完全符合预期,系统的响应速度又恢复了,数据库的压力也再度降低了不少。

看看这一步完成后系统的图示:

 

 

数据缓存

这一步涉及到了这些知识体系:

缓存技术,包括像Map数据结构、缓存算法、所选用的框架本身的实现机制等。

架构演变第五步: 增加webserver

好景不长,发现随着系统访问量的再度增加,webserver机器的压力在高峰期会上升到比较高,这个时候开始考虑增加一台 webserver,这也是为了同时解决可用性的问题,避免单台的webserver down机的话就没法使用了,在做了这些考虑后,决定增加一台webserver,增加一台webserver时,会碰到一些问题,典型的有:

1、如何让访问分配到这两台机器上,这个时候通常会考虑的方案是Apache自带的负载均衡方案,或LVS这类的软件负载均衡方案;

2、如何保持状态信息的同步,例如用户session等,这个时候会考虑的方案有写入数据库、写入存储、cookie或同步session信息等机制等;

3、如何保持数据缓存信息的同步,例如之前缓存的用户数据等,这个时候通常会考虑的机制有缓存同步或分布式缓存;

4、如何让上传文件这些类似的功能继续正常,这个时候通常会考虑的机制是使用共享文件系统或存储等;

在解决了这些问题后,终于是把webserver增加为了两台,系统终于是又恢复到了以往的速度。

看看这一步完成后系统的图示:

 

 

增加webserver

这一步涉及到了这些知识体系:

负载均衡技术(包括但不限于硬件负载均衡、软件负载均衡、负载算法、linux转发协议、所选用的技术的实现细节等)、主备技术(包括但不限于 ARP欺骗、linux heart-beat等)、状态信息或缓存同步技术(包括但不限于Cookie技术、UDP协议、状态信息广播、所选用的缓存同步技术的实现细节等)、共 享文件技术(包括但不限于NFS等)、存储技术(包括但不限于存储设备等)。

架构演变第六步:分库

享受了一段时间的系统访问量高速增长的幸福后,发现系统又开始变慢了,这次又是什么状况呢,经过查找,发现数据库写入、更新的这些操作的部分数 据库连接的 资源竞争非常激烈,导致了系统变慢,这下怎么办呢,此时可选的方案有数据库集群和分库策略,集群方面像有些数据库支持的并不是很好,因此分库会成为比较普 遍 的策略,分库也就意味着要对原有程序进行修改,一通修改实现分库后,不错,目标达到了,系统恢复甚至速度比以前还快了。

看看这一步完成后系统的图示:

 

 

分库

这一步涉及到了这些知识体系:

这一步更多的是需要从业务上做合理的划分,以实现分库,具体技术细节上没有其他的要求;

但同时随着数据量的增大和分库的进行,在数据库的设计、调优以及维护上需要做的更好,因此对这些方面的技术还是提出了很高的要求的。

架构演变第七步:分表、DAL和分布式缓存

随着系统的不断运行,数据量开始大幅度增长,这个时候发现分库后查询仍然会有些慢,于是按照分库的思想开始做分表的工作,当然,这不可避免的会 需要对程序进行一些修改,也许在这个时候就会发现应用自己要关心分库分表的规则等,还是有些复杂的,于是萌生能否增加一个通用的框架来实现分库分表的数据 访问,这个在ebay的架构中对应的就是DAL,这个演变的过程相对而言需要花费较长的时间,当然,也有可能这个通用的框架会等到分表做完后才开始做,同 时,在这个阶段可能会发现之前的缓存同步方案出现问题,因为数据量太大,导致现在不太可能将缓存存在本地,然后同步的方式,需要采用分布式缓存方案了,于 是,又是一通考察和折磨,终于是将大量的数据缓存转移到分布式缓存上了。

看看这一步完成后系统的图示:

 

 

分表、DAL和分布式缓存

这一步涉及到了这些知识体系:

分表更多的同样是业务上的划分,技术上涉及到的会有动态hash算法、consistent hash算法等;

DAL涉及到比较多的复杂技术,例如数据库连接的管理(超时、异常)、数据库操作的控制(超时、异常)、分库分表规则的封装等;

架构演变第八步:增加更多的webserver

在做完分库分表这些工作后,数据库上的压力已经降到比较低了,又开始过着每天看着访问量暴增的幸福生活了,突然有一天,发现系统的访问又开始有 变慢的趋势 了,这个时候首先查看数据库,压力一切正常,之后查看webserver,发现apache阻塞了很多的请求,而应用服务器对每个请求也是比较快的,看来 是请求数太高导致需要排队等待,响应速度变慢,这还好办,一般来说,这个时候也会有些钱了,于是添加一些webserver服务器,在这个添加 webserver服务器的过程,有可能会出现几种挑战:

1、Apache的软负载或LVS软负载等无法承担巨大的web访问量(请求连接数、网络流量等)的调度了,这个时候如果经费允许的话,会采取 的方案是购 买硬件负载,例如F5、Netsclar、Athelon之类的,如经费不允许的话,会采取的方案是将应用从逻辑上做一定的分类,然后分散到不同的软负载 集群中;

2、原有的一些状态信息同步、文件共享等方案可能会出现瓶颈,需要进行改进,也许这个时候会根据情况编写符合网站业务需求的分布式文件系统等;

在做完这些工作后,开始进入一个看似完美的无限伸缩的时代,当网站流量增加时,应对的解决方案就是不断的添加webserver。

看看这一步完成后系统的图示:

 

增加更多的webserver

 

增加更多的webserver

这一步涉及到了这些知识体系:

到了这一步,随着机器数的不断增长、数据量的不断增长和对系统可用性的要求越来越高,这个时候要求对所采用的技术都要有更为深入的理解,并需要根据网站的需求来做更加定制性质的产品。

架构演变第九步:数据读写分离和廉价存储方案

突然有一天,发现这个完美的时代也要结束了,数据库的噩梦又一次出现在眼前了,由于添加的webserver太多了,导致数据库连接的资源还是 不够用,而这个时候又已经分库分表了,开始分析数据库的压力状况,可能会发现数据库的读写比很高,这个时候通常会想到数据读写分离的方案,当然,这个方案 要实现并不容易,另外,可能会发现一些数据存储在数据库上有些浪费,或者说过于占用数据库资源,因此在这个阶段可能会形成的架构演变是实现数据读写分离, 同时编写一些更为廉价的存储方案,例如BigTable这种。

看看这一步完成后系统的图示:

 

 

数据读写分离和廉价存储方案

这一步涉及到了这些知识体系:

数据读写分离要求对数据库的复制、standby等策略有深入的掌握和理解,同时会要求具备自行实现的技术;

廉价存储方案要求对OS的文件存储有深入的掌握和理解,同时要求对采用的语言在文件这块的实现有深入的掌握。

架构演变第十步:进入大型分布式应用时代和廉价服务器群梦想时代

经过上面这个漫长而痛苦的过程,终于是再度迎来了完美的时代,不断的增加webserver就可以支撑越来越高的访问量了,对于大型网站而言, 人气的重要毋庸置疑,随着人气的越来越高,各种各样的功能需求也开始爆发性的增长,这个时候突然发现,原来部署在webserver上的那个web应用已 经非常庞大 了,当多个团队都开始对其进行改动时,可真是相当的不方便,复用性也相当糟糕,基本是每个团队都做了或多或少重复的事情,而且部署和维护也是相当的麻烦, 因为庞大的应用包在N台机器上复制、启动都需要耗费不少的时间,出问题的时候也不是很好查,另外一个更糟糕的状况是很有可能会出现某个应用上的bug就导 致了全站都不可用,还有其他的像调优不好操作(因为机器上部署的应用什么都要做,根本就无法进行针对性的调优)等因素,根据这样的分析,开始痛下决心,将 系统根据职责进行拆分,于是一个大型的分布式应用就诞生了,通常,这个步骤需要耗费相当长的时间,因为会碰到很多的挑战:

1、拆成分布式后需要提供一个高性能、稳定的通信框架,并且需要支持多种不同的通信和远程调用方式;

2、将一个庞大的应用拆分需要耗费很长的时间,需要进行业务的整理和系统依赖关系的控制等;

3、如何运维(依赖管理、运行状况管理、错误追踪、调优、监控和报警等)好这个庞大的分布式应用。

经过这一步,差不多系统的架构进入相对稳定的阶段,同时也能开始采用大量的廉价机器来支撑着巨大的访问量和数据量,结合这套架构以及这么多次演变过程吸取的经验来采用其他各种各样的方法来支撑着越来越高的访问量。

看看这一步完成后系统的图示:

 

 

进入大型分布式应用时代和廉价服务器群梦想时代

这一步涉及到了这些知识体系:

这一步涉及的知识体系非常的多,要求对通信、远程调用、消息机制等有深入的理解和掌握,要求的都是从理论、硬件级、操作系统级以及所采用的语言的实现都有清楚的理解。

运维这块涉及的知识体系也非常的多,多数情况下需要掌握分布式并行计算、报表、监控技术以及规则策略等等。

说起来确实不怎么费力,整个网站架构的经典演变过程都和上面比较的类似,当然,每步采取的方案,演变的步骤有可能有不同,另外,由于网站的业务 不同,会有不同的专业技术的需求,这篇blog更多的是从架构的角度来讲解演变的过程,当然,其中还有很多的技术也未在此提及,像数据库集群、数据挖掘、 搜索等,但在真实的演变过程中还会借助像提升硬件配置、网络环境、改造操作系统、CDN镜像等来支撑更大的流量,因此在真实的发展过程中还会有很多的不 同,另外一个大型网站要做到的远远不仅仅上面这些,还有像安全、运维、运营、服务、存储等,要做好一个大型的网站真的很不容易,写这篇文章更多的是希望能 够引出更多大型网站架构演变的介绍,:)。

禁止网页复制和右键菜单,兼容ff和ie

<script language=”javascript”>
document.oncontextmenu =
document.onselectstart =
new Function(“return false”);
</script>