PlentyOfFish(以下简称POF)是一家在美国广受欢迎的婚介交友网站,平均每月有4千5百万的访问者,每天有3千万的访问量(这是前一段时间的数据了),但你万万想不到的是,这个被估值$1000000000的网站却只有一个人每天只干两小时活。

POF对网友是100%免费的,所有的收入来自于Google广告点击,不像中国有的婚介交友网站广告纷乱,POF只有一个广告通栏,此外没有任何弹出广告,感觉非常的简洁。 它的成功的关键因素可能就是在基本功能方面能很符合用户的需要,在UE方面做的也比较贴心,同时也让用户能够坦然接受这个免费网站的UI的丑陋和服务的不稳定性,而更为愿意通过这个平台来发布一些内容,share一些个人图片,通过这个网站来找靓妞或者帅哥dating了。

我们先暂且不谈他在用户体验上是如何胜出的,光是系统架构上就值得我们好好体味一下了,毕竟一个人花那么少点时间就可以维护如此庞大的系统,由此可见其架构是如此的简单、灵活、高效。那我们就简单来分析他的架构吧。

  1. 用Microsoft Windows操作系统作为服务器
    该网站采用的是Windows x64 Server 2003。采用Windows的原因是并不是站长认为Windows适合POF,而是因为站长本人建站时候的技术很差,完全不会使用Linux和 Unix。他办这个网站的初衷其实是学习ASP。也因为如此,整个网站的标准就是简单、简单、再简单。对于大流量负载均衡的处理,站长目前没有使用 Windows 的负载均衡Network Load Balancing (NLB),他认为NLB不能保持sessions状态。对于不能保持sessions状态,倒也可以存储session状态到数据库,或者共享文件系统。8-12个NLB服务器可以共同放入一个farm,而且farm的数量也是没有限制的。然后将一个 DNS轮转调度策略(round-robin scheme)用在farm之间。其实这样的架构,也曾经一度被用在POF——总计70个前端Web服务器(front end web servers),可以支持30万人的并发访问。NLB也是一个不错的选择。但是这样的软件解决方案显得有点贵,而且很麻烦,最终站长选择了硬件来完成负载均衡任务。
  2. 使用ASP.NET技术
    ASP.NET中的缓存功能完全没有启用。因为该网站的动态特性,往往还没等缓存储存,数据就已经改变或消失了。另外,该站点也没有用ASP.NET开发什么组件,所有的组件都是现成的,一切都以简单出发。
  3. 使用IIS作为Web容器
    由于IIS限制了最大64000的连接数,所以POF不得不添加负载均衡器来处理为数众多的并发连接。站长曾经考虑过添加第二IP,并采用轮转调度(Round-Robin)来解决访问量过大的问题,但是这样太过复杂,有悖于一个人的简单管理,最后被放弃了。其实用多个Web服务器就可以简单解决。
  4. 用Akamai CDN来缓存网页
    该站点部署了Akamai CDN(网页缓存加速),每天处理大约1亿幅图片的缓存加速。CDN的原理是将你站点部分的内容,分发到CDN服务商的服务器上,因为CDN服务商广泛分布的服务器可以更加接近最终用户的地域,这样速度就会更快。假如你当前的POF页面有8幅图片,每幅图片的下载需要100毫秒,那么光下载这些图片就需要花上一秒钟。所以分配这些图片到离用户更近的区域是非常必要的,而且CDN也一定程度缓解了不同网络服务商之间的线路差异。当然,也不是所有的图片都采用了CDN,一些小于2KB的图片还是缓存于本地内存。可能因为部署了CDN,POF虽然是国外网站,但速度却非常快,与国内网站无二。有关CDN技术,可以参考http://baike.baidu.com/view/21895.htm
  5. 用Foundry ServerIron 来做负载均衡
    POF采用了网捷网络公司的Web交换器ServerIron,ServerIron 能够有效地处理超过 16,000,000个并发连接,而且能够改善服务器负载均衡和缓冲转换。正如上文所述,最终站长放弃了NLB而采用了ServerIron 负载均衡,经过详细计算之后,他发现部署ServerIron要比NLB便宜。其实也不只是POF,很多大网站都采用ServerIron来处理TCP 连接pooling和bot自动监察。ServerIron除了负载均衡还能做很多事情,因此还是值得的考虑的。
  6. 数据库优化
    3台SQL Server,采用master-slave架构,两台负责read操作,master那台负责写操作。这个和myspace早期的后台数据库架构是一样,看来这种架构很流行嘛。POF 有一个主要的数据库,两个搜索数据库。监测使用任务管理器来完成。过去,有些问题会将数据库堵塞,其实这都是数据库自己的问题,好在POF没用.net的 library,找出问题相对容易一些。不过假如你使用了framework的很多层级,找出问题就可能很困难了。对于POF而言,数据库不仅仅是不出问题,还需要稳定和快速。由于POF网站的动态特性,基本用不到缓存,所以站长几年来花了很大功夫,在很多细节上优化了数据库,让数据库的相应更加迅速。
  7. Memory和CPU
    把最近常使用的图片直接放在内存中,所以内存会那么大;CPU配置也挺好,gzip是相当耗费CPU计算的。

    Markus说他碰到问题基本上是IO操作方面的瓶颈,很少是被.Net block住。Markus在Session,Farm,以及数据库反范式等很多方面都有很不错的经验,很值得我们学习和借鉴,更多的细节大家可以参考后面的链接的几篇文章。

  8. 压缩
    所有的request数据都使用了gzip压缩,大概耗费了30%的CPU,但是降低了带宽成本。欧美的带宽不便宜。

中国的经济环境持续向好,所以很多公司的IT部门都得到了更多的预算,但这些预算被合理的使用了吗?这些预算往往被用来采购更好的服务器硬件,更新的操作系统和数据库软件,还有各式各样的行业应用。倒不是说这些部署不好,只是说我们的IT部署一定要以实用为出发点,少做一些可有可无的投资。我们要多向 POF学习,其实稳定、快速、便捷才是制胜的关键。正如POF站长一再强调的简单哲学,所有复杂的东西都尽量不去使用。


虽然站长一开始的技术一般,但是随着建站时间的加长,他现在也已经是一个网站架构专家,他花了很多力气来优化数据库和维护系统,而且他也采用了CDN来加快不同地域的用户访问网站空间。不过其实该网站的搭建可以更加合理,比如可以采用S3来外包其图片存储,采用更轻质化的操作系统或者Web服务器等等。这些年来,类似于这样的建议非常多,但是站长还是坚持了他的简单策略,而且也拒绝对主页面进行美工优化,因为他认为多余的工作只会引来他人反感,实用才是关键。可见,保持简单性,和持续勤劳的维护是服务器运行良好的法宝。



相信我们可以从POF上学习的东西还有很多,毕竟该网站以一己之力,达到了史无前例的高度,净利润竟然逼近了500多人的大型IT网站。POF的成功必然有它的深刻理由,不仅是网站的整体的服务器和软件架构、很多细节的处理也同样值得我们借鉴。

狼族营销:http://www.wolves69.com  助你的网站腾飞

posted @ 2011-08-17 13:23 Wolves 阅读(211) 评论(2) 编辑
OK,我们以一个销售数据库场景开始分区表实战。
 
第一步:建立我们要使用的数据库,最重要的是建立多个文件组。
CREATE DATABASE Sales ON PRIMARY
(    
  NAME = N'Sales',    
  FILENAME = N'C:\Sales.mdf',    
  SIZE = 3MB,
  MAXSIZE = 100MB,    
  FILEGROWTH = 10%    
),    
FILEGROUP FG1    
(    
  NAME = N'File1',    
  FILENAME = N'C:\File1.ndf',    
  SIZE = 1MB,    
  MAXSIZE = 100MB,    
  FILEGROWTH = 10%    
),    
FILEGROUP FG2    
(    
  NAME = N'File2',    
  FILENAME = N'C:\File2.ndf',    
  SIZE = 1MB,    
  MAXSIZE = 100MB,
  FILEGROWTH = 10%    
),
FILEGROUP FG3    
(    
  NAME = N'File3',    
  FILENAME = N'C:\File3.ndf',    
  SIZE = 1MB,    
  MAXSIZE = 100MB,    
  FILEGROWTH = 10%    
)    
LOG ON    
(    
  NAME = N'Sales_Log',    
  FILENAME = N'C:\Sales_Log.ldf',    
  SIZE = 1MB,    
  MAXSIZE = 100MB,    
  FILEGROWTH = 10%
)
GO
 
第二步:建立分区函数,这里我们建立三个分区。 how(如何对数据进行分区)
USE Sales    
GO
CREATE PARTITION FUNCTION pf_OrderDate (datetime)    
AS RANGE RIGHT    
FOR VALUES ('2003/01/01', '2004/01/01') --n不能超过 999,创建的分区数等于 n + 1
GO
 
第三步:创建分区方案,关联到分区函数 。 where(在哪里对数据进行分区)
USE Sales    
GO    
CREATE PARTITION SCHEME ps_OrderDate    
AS PARTITION pf_OrderDate    
TO (FG1, FG2, FG3)    
GO
 
第四步:创建分区表。创建表并将其绑定到分区方案。这里我们建立2个表,表的结构一样。其中OrdersHistory表用于保存归档数据。
USE Sales    
GO    
CREATE TABLE dbo.Orders    
(    
  OrderID int identity(10000,1),    
  OrderDate datetime NOT NULL,    
  CustomerID int NOT NULL,    
  CONSTRAINT PK_Orders PRIMARY KEY (OrderID, OrderDate)    
)    
ON ps_OrderDate (OrderDate)    
GO    
CREATE TABLE dbo.OrdersHistory    
(    
  OrderID int identity(10000,1),    
  OrderDate datetime NOT NULL,    
  CustomerID int NOT NULL,    
  CONSTRAINT PK_OrdersHistory PRIMARY KEY (OrderID, OrderDate)    
)    
ON ps_OrderDate (OrderDate)    
GO
 
通过以上四步,我们建立了分区表。接着我们要插入一些数据,来进行数据归档,分区查询等。
 
向数据表中写入2002年的范例数据
USE Sales    
GO    
INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES ('2002/6/25', 1000)    
INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES ('2002/8/13', 1000)    
INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES ('2002/8/25', 1000)    
INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES ('2002/9/23', 1000)
GO
 
向数据表中写入2003年的范例数据
USE Sales    
GO
INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES ('2003/6/25', 1000)
INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES ('2003/8/13', 1000)
INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES ('2003/8/25', 1000)
INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES ('2003/9/23', 1000)    
GO
 
我们可以用下面的代码查询这2表:
SELECT * FROM dbo.Orders    
SELECT * FROM dbo.OrdersHistory
查询的结果是Orders里面有8行数据,而OrdersHistory还没有数据。因为我们还没归档数据,所以OrdersHistory表还没有数据。
 
插入完数据后,我们来做如下实验:
 
1,查询某个分区
这里我们要用到$PARTITION 函数,这个函数可以帮助我们查询某个分区的数据,还可以检索某个值所隶属的分区号。$PARTITION 函数的进一步细节可以查看MSDN
 
查询已分区表Order的第一个分区,代码如下:
SELECT *
FROM dbo.Orders
WHERE $PARTITION.pf_OrderDate(OrderDate) = 1
查询结果只包含2002年的数据,如下图:
650) this.width=650;">
 
如果想获得2003年的数据,需要如下的代码:
SELECT *
FROM dbo.Orders
WHERE $PARTITION.pf_OrderDate(OrderDate) = 2
 
我们还可以查询某个分区有多少行数据,代码如下:
SELECT $PARTITION.pf_OrderDate(OrderDate) AS Partition,
COUNT(*) AS [COUNT]    
FROM dbo.Orders    
GROUP BY $PARTITION.pf_OrderDate(OrderDate)    
ORDER BY Partition ;
 
我们还可以通过$PARTITION 函数获得一组分区标示列值的分区号,例如获得2002属于哪个分区,代码如下:
SELECT Sales.$PARTITION.pf_OrderDate('2002')
很明显,2002年隶属于第1个分区,因为我们建立分区函数时用了RANGE RIGHT,所以返回1。你也可以把2002年换成2003,2004,2005,2009等等测试。你会发现,2003年属于第2个分区,2004年以后的都属于第3个分区。
 
2,归档数据
假如现在是2003年年初,那么我们就可以把2002年所有的交易记录归档到历史订单表HistoryOrder中。代码如下:
USE Sales    
GO    
ALTER TABLE dbo.Orders SWITCH PARTITION 1 TO dbo.OrdersHistory PARTITION 1
GO
 
此时如果我们再执行如下代码:
SELECT * FROM dbo.Orders        
SELECT * FROM dbo.OrdersHistory
便会发现,Orders 表只剩2003年的数据,而OrdersHistory表中包含了2002年的数据。
 
当然如果到了2004年年初,我们也可以归档2003年的所有交易数据。代码如下:
USE Sales    
GO    
ALTER TABLE dbo.Orders SWITCH PARTITION 2 TO dbo.OrdersHistory PARTITION 2
GO
 
3,添加分区
由于目前我们只有三分分区,而这三个分区的区间如下:
文件组
分区
取值范围
FG1
1
(过去某年, 2003/01/01)
Fg2
2
[2003/01/01, 2004/01/01)
Fg3
3
[2004/01/01,未来某年)
 
所以假如到了2005年年初,我们需要为2005年的交易记录准备分区,代码如下:
USE Sales    
GO    
ALTER PARTITION SCHEME ps_OrderDate NEXT USED FG2    
ALTER PARTITION FUNCTION pf_OrderDate() SPLIT RANGE ('2005/01/01')
GO
 
ALTER PARTITION SCHEME ps_OrderDate NEXT USED FG2 用来指定新分区的数据存储在那个文件。这里NEXT USED FG2 代表我们将新分区的数据保存在FG2文件组中,当然我们也可以在原有数据库上新建一个文件组,把新分区的数据保存在新文件组当中,这里我们直接用FG2文件组。
ALTER PARTITION FUNCTION pf_OrderDate() SPLIT RANGE ('2005/01/01') 代表我们创建一个新分区,而这里SPLIT RANGE ('2005/01/01')正是创建新分区的关键语法。
执行完上面的代码之后,我们就有了4个分区,此时的区间如下:
文件组
分区
取值范围
FG1
1
(过去某年, 2003/01/01)
Fg2
2
[2003/01/01, 2004/01/01)
Fg3
3
[2004/01/01, 2005/01/01)
Fg2
4
[2005/01/01, 未来某年)
 
4,删除分区
删除分区又称为合并分区,假如我们想合并2002年的分区和2003年的分区到一个分区,我们可以用如下的代码:
USE Sales    
GO    
ALTER PARTITION FUNCTION pf_OrderDate() MERGE RANGE ('2003/01/01')
GO
 
执行完上面的代码,此时分区区间如下:
文件组
分区
取值范围
Fg2
1
[过去某年, 2004/01/01)
Fg3
2
[2004/01/01, 2005/01/01)
Fg2
3
[2005/01/01, 未来某年)
 
合并2002和2003年的数据到2003年之后,我们执行如下代码:
SELECT Sales.$PARTITION.pf_OrderDate('2003')
你会发现返回的结果是1。而原来返回的是2,原因是2002年以前数据所在的那个分区合并到了2003年这个分区中了。
假如此时我们执行如下代码:
SELECT *
FROM dbo.OrdersHistory    
WHERE $PARTITION.pf_OrderDate(OrderDate) = 2
结果一行数据都没返回,事实就这样,因为OrdersHistory 表中只存储了2002和2003年的历史数据,在没有合并分区之前,执行上面的代码肯定会查询出2003年的数据,但是合并了分区之后,上面代码实际查询的是第二个分区中2004年的数据。
不过当我们改成如下的代码:
SELECT *
FROM dbo.OrdersHistory    
WHERE $PARTITION.pf_OrderDate(OrderDate) = 1
便会查询出8行数据,包括2002年和2003年的数据,因为合并分区后2002年和2003年的数据都成了第1个分区的数据了。
 
通过图形我们来回忆下归档数据、添加分区、合并分区。
650) this.width=650;">
 
5,查看元数据
我们可以通过以下三个视图来观察我们创建的分区函数,分区方案,边界点值等。
select * from sys.partition_functions    
select * from sys.partition_range_values
select * from sys.partition_schemes
查询的结果如下图:
650) this.width=650;">

本文出自 “李涛的技术专栏” 博客,请务必保留此出处http://terryli.blog.51cto.com/704315/169601

posted @ 2011-06-01 10:05 Wolves 阅读(71) 评论(1) 编辑
分区方案
对表和索引进行分区的第二步是创建分区方案。分区方案定义了一个特定的分区函数将使用的物理存储结构(其实就是文件组),或者说是分区方案将分区函数生成的分区映射到我们定义的一组文件组。所以分区方案解决的是Where的问题,即表的各个分区在哪里存储的问题。分区方案的创建语法如下:
CREATE PARTITION SCHEME partition_scheme_name
AS PARTITION partition_function_name
[ ALL ] TO ( { file_group_name | [ PRIMARY ] } [ ,...n ] )
[ ; ]
 
分区方案语法的相关解释:
1,  创建分区方案时,根据分区函数的参数,定义映射表分区的文件组。必须指定足够的文件组来容纳分区数。可以指定所有分区映射到不同文件组、某些分区映射到单个文件组或所有分区映射到单个文件组。如果您希望在以后添加更多分区,还可以指定其他“未分配的”文件组。在这种情况下,SQL Server 用 NEXT USED 属性标记其中一个文件组。这意味着该文件组将包含下一个添加的分区。一个分区方案仅可以使用一个分区函数。但是,一个分区函数可以参与多个分区方案。
2,  partition_scheme_name 是分区方案的名称。分区方案名称在数据库中必须是唯一的,并且符合标识符规则。
3,  partition_function_name 是使用当前分区方案的分区函数的名称。分区函数所创建的分区将映射到在分区方案中指定的文件组。partition_function_name 必须已经存在于数据库中。
4,  ALL 指定所有分区都映射到在 file_group_name 中提供的同一个文件组,或映射到主文件组(如果指定了 [PRIMARY])。如果指定了 ALL,则只能指定一个 file_group_name。
5,  file_group_name | [ PRIMARY ] [ ,...n] 代表n个文件组。和分区函数中的各个分区对应。文件组必须已经存在于数据库中。 如果指定了 [PRIMARY],则分区将存储于主文件组中。如果指定了 ALL,则只能指定一个 file_group_name。分区分配到文件组的顺序是从分区 1 开始,按文件组在 [,...n] 中列出的顺序进行分配。在 [,...n] 中,可以多次指定同一个文件组。如果 n 不足以拥有在分区函数中指定的分区数,则 CREATE PARTITION SCHEME 将失败,并返回错误。
6,  如果分区函数生成的分区数少于创建分区方案时提供的文件组数,则分区方案中第一个未分配的文件组将被标记为 NEXT USED,并且出现显示命名 NEXT USED 文件组的信息。如果指定了 ALL,则单独的文件组将为该分区函数保持它的NEXT USED 属性。如果在 ALTER PARTITION FUNCTION 语句中创建了一个分区,则 NEXT USED 文件组将再接收一个分区。若要再创建一个未分配的文件组来拥有新的分区,请使用 ALTER PARTITION SCHEME。
分区方案例子1:下面的代码先创建一个分区函数,然后再创建这个分区函数使用的分区方案,这个分区方案将每个分区映射到不同文件组。代码如下:
create partition function MyPF1(int)
as range left
for values(500000,1000000,1500000)
go
create partition scheme MyPS1
as partition MyPF1
to (fg1, fg2, fg3, fg4)
文件组、分区和分区边界值范围之间的关系如下表:
文件组
分区
取值范围
fg1
1
(负无穷,500000]
fg2
2
[500001,1000000]
fg3
3
[1000001,1500000]
fg4
4
[1500001,正无穷)
 
分区方案例子2:下面的代码先创建一个分区函数,然后再创建这个分区函数使用的分区方案,这个分区方案将多个分区映射到同一个文件组。代码如下:
create partition function MyPF2(int)
as range left
for values(500000,1000000,1500000)
go
create partition scheme MyPS2
as partition MyPF2
to (fg1, fg1, fg1, fg2)
文件组、分区和分区边界值范围之间的关系如下表:
文件组
分区
取值范围
fg1
1
(负无穷,500000]
Fg1
2
[500001,1000000]
Fg1
3
[1000001,1500000]
Fg2
4
[1500001,正无穷)
 
分区方案例子3:下面的代码先创建一个分区函数,然后再创建这个分区函数使用的分区方案,这个分区方案将所有分区映射到同一个文件组。代码如下:
create partition function MyPF3 (int)
as range left
for values(500000,1000000,1500000)
go
create partition scheme MyPS3
as partition MyPF3
all to (fg1)
文件组、分区和分区边界值范围之间的关系如下表:
文件组
分区
取值范围
fg1
1
(负无穷,500000]
Fg1
2
[500001,1000000]
Fg1
3
[1000001,1500000]
Fg1
4
[1500001,正无穷)
 
分区方案例子4:下面的代码先创建一个分区函数,然后再创建这个分区函数使用的分区方案,这个分区方案指定了“NEXT USED”文件组。代码如下:
create partition function MyPF4(int)
as range left
for values(500000,1000000,1500000) --4个分区
go
create partition scheme MyPS4
as partition MyPF4
to (fg1, fg2, fg3, fg4, fg5)   --5个文件组
那么文件组fg5将自动被标记为“NEXT USED”文件组。
分区方案例子5:下面的代码先创建一个分区函数,然后再创建这个分区函数使用的分区方案,这个分区方案指定了“[primary]”文件组。代码如下:
create partition function MyPF5(datetime)
range right
for values('2008/01/01', '2009/01/01')
go
create partition scheme MyPS5
as partition MyPF5
to([primary], fg1, fg2)
 
最后必须明白一点,一张表最多只能有1000个分区。
 
分区表
 
在分区函数和分区方案创建完成后,创建分区表的准备工作已经完成。我们看一个完整的例子,代码如下:
--创建分区函数
create partition function MyPF(datetime)
range right
for values('2007-1-1', '2008-1-1')
go
--创建分区方案
create partition scheme MyPS
as partition MyPF
to(fg1, fg2, fg3)
go
--创建分区表
create table orders
(
    OrderID int identity(1,1) primary key,
    OrderDate datetime,
    CustID varchar(10)
)
on MyPS(OrderDate)
 
更完整的例子请关注实战分区表,我会用一个完整的Demo来演示分区表这一技术。
下一节内容包裹:
1,  实战分区表
2,  查询某个分区
3,  增加分区
4,  删除分区
5,  归档数据
敬请期待...
 

本文出自 “李涛的技术专栏” 博客,请务必保留此出处http://terryli.blog.51cto.com/704315/163317

posted @ 2011-06-01 09:58 Wolves 阅读(53) 评论(1) 编辑
在谈论分区表这个话题之前,先和大家分享一个案例:
2008年秋天的某天,我的团队接到成都市XX局一个SQL调优的ESS单子。客户反映查询统计一次各地市局上报的数据汇总,需要6到15秒才能获得真正想要的数据,当我和销售人员赶到客户数据中心现场后,发现里面布置了很多柜式服务器,每台服务器都是8核16G内存。和相关技术负责人沟通以及演示业务系统之后,可以肯定不是服务器性能的问题,我详细分析了他们的数据库,统计慢的几张表往往一周的上报数据便会增加1百多万行,导致他们这个系统刚上线没多久,某些表产生的数据已经在2000万行以上,最终我提出了优化方案,业务逻辑层采用存储过程代替普通的SQL语句,并启用相关开发平台的缓存技术;数据库系统中采用增强索引和规划分区表进行优化,最终问题解决。
事实上数据库性能优化是每个优秀的数据库工程师必须具备的素质之一,而这一节讨论的分区表便是性能调优的一种技术。在企业级应用系统中,一个表存储2千万行的数据很常见,不可预期的数据也会在逐渐增长,所以数千万级别的表DBA会常常碰到,而TB级别的数据最终也在所难免,因此了解和掌握性能调优的18般兵器非常重要。
 
我计划用三篇博文介绍分区表这个主题,分别为:
1,    分区表理论解析
2,    实战分区表
3,    分区表前传
  
650) this.width=650;">
 
大凡在应用系统和数据库系统中行走江湖多年的朋友,都会面临数据统计、分析以及归档的问题,企业信息化进程加速了各种数据的极具增长,商务智能(BI)的出现和实施着实给信息工作者和决策者带来了绝妙的体验,但从 OLTP 向 OLAP 系统加载数据是很头疼的事,常常需要数分钟或数小时,解决这一问题的技术之一便是分区表,一旦实施了分区表,这样的操作往往只需几秒钟,太让人兴奋了。而大型表或索引经过分区后更容易进行管理,因为这样可以快速高效地管理和访问数据子集,同时维护数据集合的完整性。分区表的数据分布于一个数据库中的多个文件组单元中,数据是按水平方式分区的(数据分区的多种方式会在分区表前传中阐述),因此一个表的某些行映射到某个分区,而另外一些行映射到另外某个分区,以此类推。当对数据进行查询或更新时,表将被视为单个逻辑实体,所以在数据访问层你会感觉和访问普通表一样,而好处就在于可以查询想要的某个分区,而不必扫描整个表。有一点必须明白,单个表的所有分区都必须位于同一个数据库中。
分区表支持和标准表相关的所有属性和功能,包括约束、默认值、标识和时间戳值以及触发器等。决定是否实现分区主要取决于表当前的大小或将来的大小以及对表执行查询和维护操作的完善程度。
通常,如果某个大型表同时满足下列两个条件,则可能适于进行分区:
1,该表包含或将包含以多种不同方式使用的大量数据
2,维护开销超过了预定义的维护期
例如,如果对当前年份或当前月份的数据主要执行 SELECT 、INSERT、UPDATE 和 DELETE 操作,而对以前年份或以前月份的数据主要执行 SELECT 查询,则如果按年份或月份对表进行分区,表的管理要容易些,因为此时对表的维护操作只针对一个数据子集。如果该表没有分区,那么就需要对整个数据集执行这些操作,这样就会消耗大量资源。
所以常常根据日期和分类对表进行分区,当然利用某个标识列ID也是很好的选择。例如,电子商务数据库的某张表可能包含了近6年的数据,但是只定期访问本年度或某个月的数据,那么就可以按年份或月份分区,而另外一张表包含了近几十种类型商品的订单,那么此时可以为每种类型商品分一个区。
一般而言,衡量大型表是以数据为标准的,但对于适合分区的大型表,衡量大型表更重要的是对数据访问的性能,如果对于某些表的访问和维护有较严重的性能问题,就可以视为大型表,就应该考虑通过更好的设计和分区来解决性能问题。
创建分区表必须经过如下三个步骤:
1,  创建分区函数
2,  创建映射到分区函数的分区方案
3,  创建使用该分区方案的分区表
 
分区函数
 
分区函数是数据库中的一个独立对象,它将表的行映射到一组分区,所以分区函数解决的是HOW的问题,即表如何分区的问题。创建分区函数时,必须指明数据分区的边界点以及分区依据列,这样便知道如何对表或索引进行分区。分区函数的创建语法如下:
CREATE PARTITION FUNCTION partition_function_name ( input_parameter_type )
AS RANGE [ LEFT | RIGHT ]
FOR VALUES ( [ boundary_value [ ,...n ] ] )
[ ; ]
分区函数语法的相关解释:
1,  创建一个分区函数和创建一个普通的数据库对象(例如表)没什么区别。所以根据标准语法走就OK了。
2,  partition_function_name是分区函数的名称。分区函数名称在数据库内必须唯一,并且符合标识符的规则。
3,  input_parameter_type是用于分区的列的数据类型,习惯把它称为分区依据列。当用作分区列时,除 text、ntext、image、xml、timestamp、varchar(max)、nvarchar(max)、varbinary(max)、别名数据类型或 CLR 用户定义数据类型外,其他所有数据类型均有效。分区依据列是在 CREATE TABLE 或 CREATE INDEX 语句中指定的。
4,  boundary_value [ ,...n ]中的boundary_value是边界值(或边界点的值),n代表可以最多有n个边界值,即n指定 boundary_value 提供的值的数目,但n不能超过 999。所创建的分区数等于 n + 1。不必按顺序列出各值。如果值未按顺序列出,则 Database Engine 将对这些边界值进行排序,创建分区函数并返回一个警告,说明未按顺序提供值。如果 n 包括任何重复的值,则数据库引擎将返回错误。边界值的取值一定是和分区依据列相关的,所以只能使用 CREATE TABLE 或 CREATE INDEX 语句中指定的一个分区列。
5,  LEFT | RIGHT 指定boundary_value [ ,...n ] 的每个boundary_value属于每个边界值间隔的哪一侧(左侧还是右侧)。如果未指定,则默认值为 LEFT。
例如我们可以依据某个表的int列来创建分区函数:
create partition function MyPF1(int)
range left    --默认是left,所以可以省略left
for values(500000,1000000,1500000)
很明显,这个分区函数创建了4个分区,因为此时n=3,所以分区总数是n+1=4。而那个int分区依据列表明将要分区的那个表里面一定有一列是int类型,是分区依据列。这个分区函数我们用的是range left,各个分区的取值范围如下表:
分区
取值范围
1
(负无穷,500000]
2
[500001,1000000]
3
[1000001,1500000]
4
[1500001,正无穷)
 
如果换成range right,即创建分区函数时代码如下:
create partition function MyPF1(int)
range right
for values(500000,1000000,1500000)
那么各个分区的取值范围如下表:
分区
取值范围
1
(负无穷,499999]
2
[500000,999999]
3
[1000000,1499999]
4
[1500000,正无穷)
 
我们还可以根据日期列创建分区函数,例如:
create partition function MyPF2(datetime)
range right
for values('2008/01/01', '2009/01/01')
这个分区函数非常适合查询和归档某一年的数据。各个分区的取值范围如下表:
分区
取值范围
1
<=2007/12/31
2
[2008/01/01,2008/12/31]
3
>=2009/01/01
当然我们也可以根据月份分区,而分区依据列支持的数据类型非常多,参照项目的实际情况选择最能表示分区的列类型。
接分区表理论解析(下)

本文出自 “李涛的技术专栏” 博客,请务必保留此出处http://terryli.blog.51cto.com/704315/163315

posted @ 2011-06-01 09:57 Wolves 阅读(107) 评论(1) 编辑
1. 世界气候数据中心(WDCC)
  如果你有一台价值3500万欧元的超级计算机,你会把它用来做什么?炒股?搭建自己的“因特网”?WDCC就有一台这样的机器,又逢全球变暖,正好用它来做气候研究。WDCC由马克思·普朗克气象研究院和德国气候计算机中心共同运作,其数据库是全球最大的。

  
全球10大终极数据库(完整版)


  WDCC有220TB的网络数据,包括气候研究、预测气候变化和110TB(24500张DVD)的气候模拟数据。尤为重要的是,它还有保存在磁带上的6PB的其他信息。你会问,这6PB的数据有多大呢?这个数据是全美所有学术研究图书馆内容总和的3倍。

  WDCC数据库概括:

  1. 220TB的网络数据

  2. 6PB的其他数据

2. 美国国家能源研究科学计算中心(简称NERSC)
  第二大的数据库应属加州奥克兰的NERSC。NERSC由“劳伦斯伯克利能源实验室”和“美国能源部”共同运作。它数据库保存的信息包括了原子能研究、高 能物理实验和早期宇宙模拟等数据。如果想看宇宙过去的模样,启动NERSC的超级计算机就可以观看“大爆炸”时期的宇宙形态。

  

全球10大终极数据库(完整版)


  NERSC数据库由2000多名计算机科学家操作和维护,其数据量高达2.8PB。(注:1 PB = 1024 TB;1 TB = 1024 GB;)

  NERSC数据库概括:

  1. 信息量高达2.8PB

  2. 由2000多名计算机科学家共同运作

3. AT&T 美国电话电报公司
  和Sprint一样,美国的老牌通信公司AT&T的数据库也能进入排名。从结构上来说,AT&T的最大数据库是百里挑一的,因为它有2个 重要“头衔”,总量最大的独立数据库(312TB)和行数第二大的独立数据库(1.9万亿行,这个数据库是处理呼叫记录的)。

  

全球10大终极数据库(完整版)


  1.9万亿条呼叫记录,包括了主叫和被叫号码、呼叫时间和通话时长以及其他各种账单目录信息。AT&T的工作做得非常细致,他们业保存了10年前的呼叫信息。要知道,10年前可没有保存数百TB级数据的技术。(或者说技术还不成熟。)

  AT&T数据库概括:

  1. 信息量为323TB

  2. 1.9万亿的通话记录

4. Google
  尽管目前外界没有太多关于Google的数据库真实大小的信息(Google一直能严守信息,这让诺克斯堡军事基地情何以堪。),但我们已知道Google所收集信息的数量和种类。

  

全球10大终极数据库(完整版)


  Google平均每天处理9100万次查询(Google的处理海量请求的能力是基于其庞大且强大的数据中心),这将近占整个互联网每日查询总量的50%。Google把用户的每一次搜索保存在数据库中。所以,Google平均一年要保存33万亿条查询记录。根据Google数据的结构类型,一年的查询总量将折合成数百TB。

  除了查询记录,Google还收集用户的个人信息。(怎么收集?)Google把用户的查询请求和用户电脑上Cookie保留的信息整合到一起,创建虚拟的个人信息。

  尤为重要的是,除了搜索,Google帝国的疆土还在不断扩大,现有疆土已有数字媒体(Google视频和YouTube)、广告(Google Ads)和邮箱等。归根结底,Google的疆土越大,其数据库处理的信息量就越大。就互联网范围内的数据库而言,Google是No 1。

  Google数据库概括:

  1. 平均每天9100万查询请求

  2. 查询数量占所有互联网查询量的50%

  3. 不计其数的用户虚拟资料

5. Sprint 斯普林特
  Sprint是全球最大的通信公司之一,向5300万客户提供服务。在和Nextel合并之前,提供本地和长途通信服务。(Sprint Nextel公司现已是全美第3大通信公司,仅次于Verizon和AT&T。)

  

全球10大终极数据库(完整版)


  像Sprint这样的大型通信公司,均有庞大的数据库,以追踪客户呼叫请求。Sprint的数据库每天要处理多达3.65亿次呼叫记录。其数据库已扩展到2.85万亿行。在顶峰期间,每秒有7万次呼叫详细记录新增到数据库中。

  Sprint数据库概括:

  1. 数据库有2.85万亿行

  2. 每日平均处理3.65亿个呼叫详细记录

  3. 顶峰期间,每秒插入7万次呼叫详细记录

6. ChoicePoint
  设想一下:在一本10亿页的电话本上找一个电话号码。这是一项什么的工作。当你有求于ChoicePoint的时候,ChoicePoint 的员工就得干这活。如果把ChoicePoint的数据库资料全部打印出来,在不这些纸张连起来,其长度足以在地月之间往返77回。

  

全球10大终极数据库(完整版)


  ChoicePoint是一家信息服务机构,你可以通过它查询美国的人口数量、地址和电话号码、驾驶记录和犯罪记录等。在大多数情况下,Choicepoint数据库中的数据是只卖给出价最高的买主,包括美国政府。

  ChoicePoint到底知道多少呢?2002年,借助ChoicePoint数据中的DNA和个人记录数量,政府成功破获了费城和柯林斯堡的一起系列强/奸案。2001年,世贸中心有很多遇难者已无法辨别身份,在提取遇难者的DNA后,通过比对ChoicePoint数据库中的遇难者家属的数据,才得以确认遇难者身份。

  ChoicePoint数据库概括:

  1.个人数据总量为250TB

  2.信息覆盖2.5亿人

7. YouTube
  在经过这些年的积累发展,YouTube已经成为全球最大的视频库(视频网站)。如今,YouTube上每日视频播放次数高达1亿次,60%的视频是在线观看的。

  

全球10大终极数据库(完整版)


  2006年8月,《华尔街日报》称YouTube的视频总量已有45TB。相对互联网上数据量来说,这个数字听起来不是很高,但自从这个数字公布以来,YouTube正经历了一段大幅增长时期,(每天有65000段视频上传至YouTube,)所以在过去五个月中,YouTube的数据库大小很可能已经翻倍了。

  因为YouTube上的每段视频的大小不一,所以要估计YouTube的数据库大小并非易事。不过,也可以大胆来预测一下:

  每天上传6500段视频,故每个月共有 65000 * 30 = 1,950,000段视频;

  假设每段视频大小为1MB,每月将有 1.95TB;

  假设每段视频大小为10MB,每月将有19.5TB。

  所以,YouTube下个月将增加近20TB数据。

  YouTube数据库概括:

  1.每日的视频播放量为1亿次

  2.每日新增65000段视频

  3. 60%的视频是在线观看的

  4.视频总量大小至少是45TB

8. Amazon 亚马逊
  Amazon,全球最大的零售网站,“收藏”了5900万活跃用户的信息,包括个人信息(电话号码等)、收据/发票、清单和还有其他能从用户那提取的数据。Amazon也有25万多的在线书籍(可以全文阅读的),并允许用户在其各个页面进行评论和交互。因此,Amazon跻身为全球最大的在线社区之一。

  

全球10大终极数据库(完整版)


  (不知你有注意Amazon的Logo上的箭头么? 有2层意思:1.从A到Z是指其物品繁多;2.笑脸。)

  上述这些数据和Amazon每年的数百万巨额销售量,再加上Amazon合伙人的巨额销售量,造就了一个超大数据库。Amazon最大的2个数据库的数据量加起来有42TB,这还只是开始。如果Amazon公开其所有的数据库数量和每个数据库的数据量,这就不仅是42TB了。

  尽管如此,我们暂且就算它42TB吧。42TB数据,如果换算成论坛帖子的话,应该是37万亿个帖子。

  Amazon数据库概括:

  1. 5900万活跃用户

  2.数据量超过42TB

9. 美国中央情报局(CIA)
  CIA的任务(之一)就是收集和散发各种信息和资料,所以CIA能上榜就不足为奇了。虽然CIA数据库的总量外界不得而知,但下面这个说法是十分肯定的。这个机构一定收集了大量的公共信息和私人信息。

  

全球10大终极数据库(完整版)


  CIA数据库对公众开放的部分有:“信息自由法”电子阅览室、“世界概况”和其他情报相关出版物。在“信息自由法”电子阅览室中,公众可以看到成千上万的美国政府官方文档(也有已解密的文档)。电子阅览室每月新增100份文档,文档主题内容范围很广,从巴基斯坦核发展到“韩战”(西方皆称“韩战”,大陆称“抗美援朝”)中的啤酒种类。“世界概况”收藏了各个国家和地区的信息,包括地图、人口数量和军事能力等。

  CIA数据库概括:

  1.电子阅览室每个月新增100份文档;

  2.覆盖全球250多个国家和地区的统计数据;

  3.数目不详的机密资料

10. 美国国会图书馆
  不管是不是在数字时代,全球最大的图书馆——美国国会图书馆都可以荣登这一列表。国会图书馆的藏书数量之高——1.4亿多册,范围之广——从烹饪书籍到殖民地时期的报纸到美国政府刊物。据估计,如果把国会图书馆的文字以数字形式存储,其总量将达20TB。

  

全球10大终极数据库(完整版)


  如果你(特指老美)在互联网上找东西又找不到时,那么国会图书馆应是你要去的地方。对于研究美国历史的用户来说,国会图书馆是个必去之处,用户访问国会图书馆网站的“美国记忆”目录,该目录下大约有5百万册相关资料。

  但不幸的是,国会图书馆并无计划把所有的馆藏内容都数字化,并且有些馆藏是限制查阅人群,只对最高法院法官、国会议员、馆内工作人员和其他政府官员。但是,只要你有国会图书馆的借阅卡,就可以借阅(大部分)资料。(编者注:该图书馆的资料不能外借,读者只能在馆内查阅。)

  国会图书馆数据库概括:

  1.馆藏资料总量1.3亿份(包括书籍、照片和地图等)

  2. 2900万册书

  3.每天新增1万馆藏

  4.书架长度共有530英里

  5. 5百万份数字文档

  6.文字数据总量20TB

posted @ 2011-05-03 09:48 Wolves 阅读(276) 评论(0) 编辑

  SEO最关键的4点就是:关键词,内容,内链,外链,我分别分类整理一些最近学到的知识点给大家,欢迎大家也来补充,可以在本文后面评论中来补充,我将及时更新该文。

域名
  1. 域名最好包含要进行优化的关键字,简短易记,最好是顶级域名
  2. 不要使用冷门,很少使用的英文单词
  3. gov>edu>org>com=net=cn,但只占很少因素,对SEO影响不大
  4. 二级域名和顶级域名是独立的PR值和信任度,如果是小站,最好用二级目录代替二级域名
  5. 域名最好一次多注册几年,给人信任度高
  6. 如果是抢注的域名,查下该域名的历史,是否曾经被搜索引擎降权

空间
  1. 空间是否和别人共用IP,该IP下是否有被搜索引擎惩罚过的站点
  2. 要保证网站可用性高,避免搜索引擎收录时站点无法访问

关键词
  1. 去百度指数或谷歌趋势查询你要做的关键词,了解每日的搜索量
  2. 避免竞争过大的词,6个字以下的是大词,在百度做了很多推广的词也是竞争大的词
  3. 不断的寻找关键字,把想到的相关的关键字都写下来,大的做专题,小的写文章优化
  4. 可以尝试使用一些带地域性的关键词,比如烟台SEO,北京生日礼物
  5. 考虑使用更长的关键字
  6. 打开百度搜索如何,怎样,然后看给的搜索建议是什么,比如如何养猪,怎样做蛋糕等,然后选自己想做的长尾词
  7. 避免一些常用的语气词,副词等作为关键词
  8. 不要为了优化某个关键字,做重复的内容而只是标题不同
  9. 网页标题,h1-h3标签,都要突出要优化的关键词,但不要堆砌关键词,每页的关键词密度要在%4-8%之间,可用chinaz的站长工具查。
  10. 内容页的第一段和最后一段最好出现要优化的关键词,还有每一段的第一句,但注意关键词密度不要过大,最好自然一些。
  11. 首先选好你要做的产品,然后选择关键字,满足4个条件:有指数,竞争度小,有定向流量,有购买欲望,然后围绕关键词做站
  12. 最好把你要优化的关键字做到百度前三
  13. 在百度知道里找找长尾关键词,里面提问的都是一些有需求的人,看他们怎么提问的

内链
  1. 动态页面的查询参数不要太多,最好是静态化
  2. 页面地址最好包含要优化的关键字,用有意义的网址
  3. 避免死链接,会降低收录数
  4. 网站的栏目页要包含长尾关键词,长尾关键词可以用*站长必备工具*进行挖掘,或利用*相关搜索*挖掘
  5. 要把关键的页面在每个子页上都做上链接,出现次数最多的页面会被搜索引擎提高权重
  6. 做好导航和面包屑导航,还有专题,tag,网站的互通性要好,方便搜索引擎索引
  7. 做好sitemap,结构良好的内链是首页->栏目->专题->内容页,
  8. 每个页面的链接不要超过50-100

内容
 
  1. 网站越大,内容越多,对用户帮助越大,积累的信任度也越高
  2. 坚持发原创,定时定量发,培养搜索引擎定时抓取的习惯,
  3. 每篇原创帖子最好在500字以上,且和SEO主题相关
  4. 帖子最好对用户有帮助,让用户认可,有转发的欲望,增加外链,软文很难被人转发。
  5. 单纯的电子商务网站很难获得自然外链,所以搞电商网站,商品推广网站要建立个博客,多写原创博客,别只做产品页面。
  6. 伪原创有很多工具,可以尝试一下,但不能作为主要方式,还得自己多写原创文章
  7. 自己手工写伪原创文章的一个办法就是做评论,把一篇好文章改改标题,然后每一段下都发表下自己的看法和见解后再发出来
  8. SEO想提高排名最关键的就是要发高质量的原创内容

外链
  1. 文章标题最好是”帮你xxx的10大窍门",比较容易获得反链
  2. 写文章列出行业专家的名单,如果能让这些专家印象深刻,并且感到很权威,这些专家有可能主动给你做反链
  3. 在艾瑞,donews等IT行业新闻网站发高质量文章
  4. 如提供开源程序,采用者会留有链接。
  5. 给内容管理系统CMS或Blog系统等开源网站系统提供免费精美模板。别忘了在模板中添加“由×××设计”。
  6. 把内容写得简单易懂,这样更多的人可以看懂并为你传播。
  7. 不要到处去论坛,博客,问答直接发外链
  8. 行业会议时,拍摄行业名人(喝醉酒了)的照片,并留有你的精彩解说。这可能是很好的链接诱饵
  9. 可以去一些问答社区积极的回答网友的问题,坐沙发,然后适当的宣传自己的网站,最好不要直接贴链接
  10. 不要以任何方式做交叉链接,会被搜索引擎惩罚
  11. 在行业网站和论坛提交文章,最好能加精或上首页
  12. 发送新闻稿。高质量的新闻稿提交给新闻门户网站。
  13. 问问你的合作伙伴或商业伙伴是否可以给你一个链接。
  14. 做外链不要只图量,更要讲究质量,交换友情链接前要看对方的导出链接多不多,百度收录情况如何,是否有不良历史,
  15. 做友情链接时考虑对方网站的文章是原创居多还是转载居多,更新频率快不快,PR值多少,是否和自己的站点相关
  16. 不要去一些链接工厂做链接
  17. 为开源网站程序开发插件,并留有作者链接。
  18. 开发有用的工具,发表并留有下载地址。
  19. 可以把站点提交给一些站点目录网站,网摘等网站
  20. 如果你在网上购买了产品,则把产品评论写下来,会带来链接。你也可以写产品推荐,注意:要写得可信,如果有具体情况最佳。
  21. 外链最好是文字链,且链接文字包含要优化的关键词,而且最好有所变化,不要千篇一律,如果是图片链,要加alt标记
  22. 最好是追求自然的外链,你写了优质的文章被人转贴
  23. 忽然获取大量外链不是件好事,容易被惩罚或被认为是买来的链接
  24. 不要只增加首页的外链,内页的外链也要多做一些

竞争对手分析
  1. 关注竞争对手的各项排名:你就能了解到竞争对手网站各个时期,他的SEO策略的重心在哪里。
  2. 关注竞争对手的内容策略:内容是否原创?原创内容源是哪里?竞争对手是如何可以持久的创造原创的?每天更新多少篇原创?原创内容是否都有对应关键词?关键词对应的内容方向是什么?
  3. 关注竞争对手的链接导向:是想增加哪方面的内容收录?是想提升哪些页面的权重?是想提升哪些长尾的排名?

 
其它
  1. 查看网站是否被K:先用site:查看收录量,在用link:(百度是domain:)查看外链情况,如果有大量外链,但没有收录,则是被K
  2. 学会用谷歌站长工具,关键词工具,谷歌分析
  3. 学会用51.la分析回头客和浏览深度
  4. 查反链用雅虎,雅虎是最准确的,百度,谷歌都不准,地址是http://sitemap.cn.yahoo.com/
  5. 不要迷信单页面优化,为一个关键词做一个页面进行优化是不可能出效果的
  6. 避免各种自以为是的SEO技巧,如关键词堆砌,各种方式的隐藏文本和链接,重复站点等
  7. 如果你的站点荣robots禁止索引一些页面,那没禁止的页面有时也很难收录
  8. 谷歌对新域名会有沙盒功能,一般新站即使做的很好,也很难短时间提高排名,过了考验期就好多了,之前的优化也不白做

    转自:http://www.itivy.com/ivy/archive/2011/3/2/634347029083814127.html

狼族营销:http://www.wolves69.com  助你的网站腾飞

posted @ 2011-03-12 17:05 Wolves 阅读(39) 评论(0) 编辑

这几天一直在关注和学习一些大型网站的架构,希望有一天自己也能设计一个高并发、高容错的系统并能应用在实践上。今天在网上找架构相关的资料时,看到一个被和谐的视频网站YouTube的架构分析,看了以后觉得自己又向架构走近了一步,于是赶快拿出来与大家一起分享。

YouTube发展迅速,每天超过1亿的视频点击量,但只有很少人在维护站点和确保伸缩性。这点和PlentyOfFish类似,少数人维护庞大系统。是什么原因呢?放心绝对不是靠人品,也不是靠寂寞,下面就来看看YouTube的整体技术架构吧。

平台

Apache
Python
Linux(SuSe)
MySQL
psyco,一个动态的Python到C的编译器
lighttpd代替Apache做视频查看

状态

 
1,花费包括带宽,硬件和能源消耗
2,每个视频由一个迷你集群来host,每个视频被超过一台机器持有
3,使用一个集群意味着:
   -更多的硬盘来持有内容意味着更快的速度
   -failover。如果一台机器出故障了,另外的机器可以继续服务
   -在线备份
4,使用lighttpd作为Web服务器来提供视频服务:
   -Apache开销太大
   -使用epoll来等待多个fds
   -从单进程配置转变为多进程配置来处理更多的连接
5,大部分流行的内容移到CDN:
  -CDN在多个地方备份内容,这样内容离用户更近的机会就会更高
  -CDN机器经常内存不足,因为内容太流行以致很少有内容进出内存的颠簸
6,不太流行的内容(每天1-20浏览次数)在许多colo站点使用YouTube服务器
  -长尾效应。一个视频可以有多个播放,但是许多视频正在播放。随机硬盘块被访问
  -在这种情况下缓存不会很好,所以花钱在更多的缓存上可能没太大意义。
  -调节RAID控制并注意其他低级问题
  -调节每台机器上的内存,不要太多也不要太少

 
视频服务关键点
1,保持简单和廉价
2,保持简单网络路径,在内容和用户间不要有太多设备
3,使用常用硬件,昂贵的硬件很难找到帮助文档
4,使用简单而常见的工具,使用构建在Linux里或之上的大部分工具
5,很好的处理随机查找(SATA,tweaks)

缩略图服务
 
1,做到高效令人惊奇的难
2,每个视频大概4张缩略图,所以缩略图比视频多很多
3,缩略图仅仅host在几个机器上
4,持有一些小东西所遇到的问题:
   -OS级别的大量的硬盘查找和inode和页面缓存问题
   -单目录文件限制,特别是Ext3,后来移到多分层的结构。内核2.6的最近改进可能让 Ext3允许大目录,但在一个文件系统里存储大量文件不是个好主意
   -每秒大量的请求,因为Web页面可能在页面上显示60个缩略图
   -在这种高负载下Apache表现的非常糟糕
   -在Apache前端使用squid,这种方式工作了一段时间,但是由于负载继续增加而以失败告终。它让每秒300个请求变为20个
   -尝试使用lighttpd但是由于使用单线程它陷于困境。遇到多进程的问题,因为它们各自保持自己单独的缓存
   -如此多的图片以致一台新机器只能接管24小时
   -重启机器需要6-10小时来缓存
5,为了解决所有这些问题YouTube开始使用Google的BigTable,一个分布式数据存储:
   -避免小文件问题,因为它将文件收集到一起
   -快,错误容忍
   -更低的延迟,因为它使用分布式多级缓存,该缓存与多个不同collocation站点工作
   -更多信息参考Google Architecture,GoogleTalk Architecture和BigTable

数据库

1,早期
   -使用MySQL来存储元数据,如用户,tags和描述
   -使用一整个10硬盘的RAID 10来存储数据
   -依赖于信用卡所以YouTube租用硬件
   -YouTube经过一个常见的革命:单服务器,然后单master和多read slaves,然后数据库分区,然后sharding方式
   -痛苦与备份延迟。master数据库是多线程的并且运行在一个大机器上所以它可以处理许多工作,slaves是单线程的并且通常运行在小一些的服务器上并且备份是异步的,所以slaves会远远落后于master
   -更新引起缓存失效,硬盘的慢I/O导致慢备份
   -使用备份架构需要花费大量的money来获得增加的写性能
   -YouTube的一个解决方案是通过把数据分成两个集群来将传输分出优先次序:一个视频查看池和一个一般的集群
2,后期
   -数据库分区
   -分成shards,不同的用户指定到不同的shards
   -扩散读写
   -更好的缓存位置意味着更少的IO
   -导致硬件减少30%
   -备份延迟降低到0
   -现在可以任意提升数据库的伸缩性

数据中心策略
 
1,依赖于信用卡,所以最初只能使用受管主机提供商
2,受管主机提供商不能提供伸缩性,不能控制硬件或使用良好的网络协议
3,YouTube改为使用colocation arrangement。现在YouTube可以自定义所有东西并且协定自己的契约
4,使用5到6个数据中心加CDN
5,视频来自任意的数据中心,不是最近的匹配或其他什么。如果一个视频足够流行则移到CDN
6,依赖于视频带宽而不是真正的延迟。可以来自任何colo
7,图片延迟很严重,特别是当一个页面有60张图片时
8,使用BigTable将图片备份到不同的数据中心,代码查看谁是最近的

学到的东西
 
1,Stall for time。创造性和风险性的技巧让你在短期内解决问题而同时你会发现长期的解决方案
2,Proioritize。找出你的服务中核心的东西并对你的资源分出优先级别
3,Pick your battles。别怕将你的核心服务分出去。YouTube使用CDN来分布它们最流行的内容。创建自己的网络将花费太多时间和太多money
4,Keep it simple!简单允许你更快的重新架构来回应问题
5,Shard。Sharding帮助隔离存储,CPU,内存和IO,不仅仅是获得更多的写性能
6,Constant iteration on bottlenecks:
   -软件:DB,缓存
   -OS:硬盘I/O
   -硬件:内存,RAID
7,You succeed as a team。拥有一个跨越条律的了解整个系统并知道系统内部是什么样的团队,如安装打印机,安装机器,安装网络等等的人。
   With a good team all things are possible。

posted @ 2011-03-12 17:03 Wolves 阅读(142) 评论(0) 编辑

Facebook是一个社会化网络站点,它于2004年2月4日上线。每个用户在facebook上有自己的档案和个人页面,用户之间可以通过各种方式发生互动:留言、发站内信,评论日志。虽然目前在国内无法访问facebook,但其强悍的技术架构还是值得我们去研究分析和总结的,或许我们可以从中得到一点启发。

facebook的设计原则是模块化原则、整合化原则、清晰化原则,其架构设计的目标是简单高效。facebook的架构是基于LAMP,差不多是用LAMP实现的最大的动态站点,以下是facebook架构图概览:



PHP经验:

《Facebook 的PHP性能与扩展性》

MySql经验:

主要用于做Key-Value类型的存储操作,数据随机分布在多台逻辑实例上,访问多数基于全局ID。
逻辑实例分散在多台物理主机上(超过1800台),负载均衡在物理层进行。
不做读复制。尽量不做逻辑数据迁移(成本太高)。
不做JOIN操作(豆瓣在QCon上也阐述了这一点)。数据是随机分布的,关联操作反而带来了极大的复杂度。
对于数据访问,主要的操作集中在最新的数据上,针对这部分做优化,旧的数据进行归档。

在中心DB绝不存储非静态数据。

使用服务或者Memcached进行全局查询。

Memcached经验:

一个比较有价值的是关于个人页面数据的获取的描述。这个就完全是需要做单页面Benchmark的细致活儿了,可能还需要产品经理能够理解工程师的"抵抗"。

获取个人信息数据:通过Cache,隐性通过用户所在的DB获取(基于User-ID获知DB)

获取朋友连接信息:通过Cache,否则的话通过DB(基于User-ID获知DB)

并行抓取每个朋友的10个照片相册ID,从Cache抓取,如果失效,再从DB抓取(基于相册ID)

并行抓取最近相册中的照片数据

运行PHP把整个业务逻辑跑出来

FacebookNewsFeed的架构示意图:

 

 

  Facebook搜索功能的架构示意图 

posted @ 2011-03-12 17:00 Wolves 阅读(792) 评论(0) 编辑
1
2
3
4
5
6
7
8
9
10
11
。。。。。。。。。。。。。。
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_http_module modules/mod_proxy_http.so
。。。。。。。。。。。。。。。。。。。。
BalancerMember "http://slave1:8008/App"   loadfactor=4
BalancerMember "http://slave2:8008/App"   loadfactor=3
BalancerMember "http://slave3:8008/App"   loadfactor=3
....................
///slave load ratio 4:3:3.
最终,Flickr采用了一种非常“轻量”但有效的“简易”PHP实现,基本的代码只有10几行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function db_connect($hosts, $user, $pass){
shuffle($hosts);     //shuffle()是PHP函数,作用是将数组中每个元素的顺序随机打乱。
foreach($hosts as $host){
debug("Trying to connect to $host...");
$dbh = @mysql_connect($host, $user, $pass, 1);
if ($dbh){
debug("Connected to $host!");
return $dbh;
}
debug("Failed to connect to $host!");
}
debug("Failed to connect to all hosts in list - giving up!");
return 0;
}
在上述代码中,如果需要对特定的Slave赋予更高的负载,只要在$hosts中多出现一次或多次就可以了。这段代码只要稍稍改进,就可以实现更复杂的功能,如当connect失败时自动将host从hosts列表中去除等。
“Master”-"Slave"模式的缺点是它并没有对于“写'操作提供扩展能力,而且存在单点故障,即一旦Master故障,整个网站将丧失“更新” 的能力。解决的办法采用“Master"-"Master"模式,即两台服务器互为”Master“-"Slave",这样不仅”读/写“能力扩展了一 倍,而且有效避免了”单点故障“,结合已有的“Master"-"Slave",整个数据库的架构就变成了下面的”双树“结构,
点看全图

“双树”架构并没有支撑太久的时间,大概6个月后,随着用户的激增,系统再一次达到了极限,不仅”写”操作成为了瓶颈,而且“异步复制"也由于 ”Slave“服务器过于繁忙而出现了严重的滞后而造成读数据的不一致。那么,能不能在现有架构加以解决,比如说增加新的”Master“服务器和考虑采 用”同步复制“呢?答案是否定的,在Master超过两台的设置中,只能采用”闭环链“的方式进行复制,在大数据量的生产环境中,很容易造成在任意时刻没 有一个Master或Slave节点是具有全部最新数据的(有点类似于”人一次也不能踏进同一条河“?),这样很难保障数据的一致性,而且一旦其中一个Master出现故障,将中断整个复制链;而对于”同步复制“,当然这是消除”复制滞后“的最好办法,不过在当时MySQL的同步复制还远没有成熟到可以运用在投产环境中。

Flickr网站的架构,需要一次大的变化来解决长期持续扩展的问题。

Shard - 大型网站数据库扩展的终极武器?

2005年7月,另一位大牛(MySQL 2005、2006年度 "Application of the Year Award"获得者)Dathan Pattishall加入了Flickr团队。一个星期之内,Dathan解决了Flickr数据库40%的问题,更重要的是,他为Flickr引进了 Shard架构,从而使Flickr网站具备了真正“线性”Scale-Out的增长能力,并一直沿用至今,取得了巨大的成功。
Shard主要是为了解决传统数据库Master/Slave模式下单一Master数据库的“写”瓶颈而出现的,简单的说Shard就是将一个大表分 割成多个小表,每个小表存储在不同机器的数据库上,从而将负载分散到多个机器并行处理而极大的提高整个系统的“写”扩展能力。相比传统方式,由于每个数据 库都相对较小,不仅读写操作更快,甚至可以将整个小数据库缓存到内存中,而且每个小数据库的备份,恢复也变得相对容易,同时由于分散了风险,单个小数据库 的故障不会影响其他的数据库,使整个系统的可靠性也得到了显著的提高。
对于大多数网站来说,以用户为单位进行Shard分割是最合适不过的,常见的分割方法有按地域(比如邮编),按Key值(比如Hash用户ID),这些 方法可以简单的通过应用配置文件或算法来实现,一般不需要另外的数据库,缺点是一旦业务增加,需要再次分割Shard时要修改现有的应用算法和重新计算所 有的Shard KEY值;而最为灵活的做法是以“目录”服务为基础的分割,即在Shard之前加一个中央数据库(Global Lookup Cluster),应用要先根据用户主键值查询中央数据库,获得用户数据所在的Shard,随后的操作再转向Shard所在数据库,例如下图:

点看全图

而应用的主要修改在于要添加一个Lookup访问层,例如将以下的代码:

1
2
3
string connectionString = @"Driver={MySQL};SERVER=dbserver;DATABASE=CustomerDB;";      
OdbcConnection conn = new OdbcConnection(connectionString);
conn.Open();
变为:
1
2
3
string connectionString = GetDatabaseFor(customerId);          
OdbcConnection conn = new OdbcConnection(connectionString);
conn.Open();
GetDatabaseFor()函数完成根据用户ID获取Shard connectionString的作用。
对应我们前面所提到过的Flickr架构
点看全图

Dual Tree Central Database就是中央数据库,存放用户表,记录的信息是用户主键以及此用户对以的数据库Shard区;而Master-Master Shards就是一个个的Shard用户数据库,存储实际的用户数据和照片的元数据(Meta Data)。

Flickr Shard的设计我们在Flickr 网站架构研究(1)中已经总结过了,在此不再赘述。我们在此谈一下Shard架构的主要问题和Flickr的解决办法:1)Shard只适用于不需要 join操作的表,因为跨Shard join操作的开销太大,解决的办法是将一个用户的所有数据全部存放在同一个Shard里,对于一些传统方式下需要 跨Shard查询的数据,只能采取冗余的方法,比如Shard1的用户A对Shard2的用户B的照片进行了评论,那么这条评论将同时存放在Shard1 和Shard2中。这样就存在一个数据一致性的问题,常规的做法是用数据库事务(Transaction)、”两阶段提交“(2 phase commit)来解决,但做过两阶段提交(2PC)应用的都知道,2PC的效率相对较差,而且实际上也不能100%保证数据的完整性和一致性;另外,一旦 由于其中一个Shard故障而提交失败回滚,用户只能放弃或再试一遍,用户体验较差。Flickr对于数据一致性的解决方案是Queue(Flickr用 PHP开发了一个强大的Queue系统,将所有可以异步的任务都用Queue来实现,每天处理高达1千万以上的任务。),事实上当用户A对用户B的照片进 行评论时,他并不关心这条评论什么时候出现在用户B的界面上,即将这条评论添加到用户B的交易是可以异步的,允许一定的迟延,通过Queue处理,既保证 了数据的一致性,又缩短了用户端的相应时间,提高了系统性能。2)Shard的另一个主要问题Rebalancing,既当现有Shard的负载达到一定 的阀值,如何将现有数据再次分割,Flickr目前的方式依然是手工的,既人工来确定哪些用户需要迁移,然后运行一个后台程序进行数据迁移,迁移的过程用 户账户将被锁住。(据说Google做到了完全自动的Rebalancing,本着”萨大“坑里不再挖坑的原则,如果有机会的话,留到下一个系列再研究 吧)

Memcached的应用和争论

大家应该已经注意到,Flickr为中央数据库配置了Memcached作为数据库缓存,接下来的问题是,为什么用Memcached?为什么 Shard不需要Memcached?Memcached和Master,Slave的关系怎样?笔者将试图回答这些问题供大家参考,网上的相关争论很 多,有些问题尚未有定论。
Memecached是一个高性能的,分布式的,开源的内存对象缓存系统,顾名思义,它的主要目的是将经常读取的对象放入内存以提高整个系统,尤其是数 据库的扩展能力。Memcached的主要结构是两个Hash Table,Server端的HashTable以key-value pair的方式存放对象值,而Client端的HashTable的则决定某一对象存放在哪一个Memcached Server.举个例子说,后台有3个Memecached Server,A、B、C,Client1需要将一个对象名为”userid123456“,值为“鲁丁"的存入,经过Client1的Hash计 算,"userid123456"的值应该放入Memcached ServerB, 而这之后,Client2需要读取"userid123456"的值,经过同样的Hash计算,得出"userid123456"的值如果存在的话应该在 Memcached ServerB,并从中取出。最妙的是Server之间彼此是完全独立的,完全不知道对方的存在,没有一个类似与Master或Admin Server的存在,增加和减少Server只需在Client端"注册"并重新Hash就可以了。
Memcached作为数据库缓存的作用主要在于减轻甚至消除高负载数据库情况下频繁读取所带来的Disk I/O瓶颈,相对于数据库自身的缓存来说,具有以下优点:1)Memecached的缓存是分布式的,而数据库的缓存只限于本机;2)Memcached 缓存的是对象,可以是经过复杂运算和查询的最终结果,并且不限于数据,可以是任何小于1MB的对象,比如html文件等;而数据库缓存是以"row"为单 位的,一旦"row"中的任何数据更新,整个“row"将进行可能是对应用来说不必要的更新;3)Memcached的存取是轻量的,而数据库的则相对较 重,在低负载的情况下,一对一的比较,Memcached的性能未必能超过数据库,而在高负载的情况下则优势明显。
Memcached并不适用于更新频繁的数据,因为频繁更新的数据导致大量的Memcached更新和较低的缓冲命中率,这可能也是为什么Shard没 有集成它的原因;Memcached更多的是扩展了数据库的”读“操作,这一点上它和Slave的作用有重叠,以至于有人争论说应该 让"Relication"回到它最初的目的”Online Backup"数据库上,而通过Memcached来提供数据库的“读”扩展。(当然也有人说,考虑到Memcached的对应用带来的复杂性,还是慎 用。)
然而,在体系架构中增加Memecached并不是没有代价的,现有的应用要做适当的修改来同步Memcached和数据库中的数据,同时Memcached不提供任何冗余和“failover”功能,这些复杂的控制都需要应用来实现。基本的应用逻辑如下:

对于读操作:

1
2
3
4
5
$data = memcached_fetch( $id );
return $data if $data
$data = db_fetch( $id );
memcached_store( $id, $data );
return $data;
对于写操作:
1
2
db_store( $id, $data );
memcached_store( $id, $data );
我们看到在每一次数据更新都需要更新Memcached,而且数据库或Memcached任何一点写错误应用就可能取得“过期”的数据而得到错误的结果,如何保证数据库和Memcached的同步呢?

复制滞后和同步问题的解决

我们知道复制滞后的主要原因是数据库负载过大而造成异步复制的延迟,Shard架构有效的分散了系统负载,从而大大减轻了这一现象,但是并不能从根本上消除,解决这一问题还是要靠良好的应用设计。
当用户访问并更新Shard数据时,Flickr采用了将用户“粘”到某一机器的做法,
$id = intval(substr($user_id, -10));
$id % $count_of_hosts_in_shard
即同一用户每次登录的所有操作其实都是在Shard中的一个Master上运行的,这样即使复制到Slave,也就是另一台Master的时候有延时,也不会对用户有影响,除非是用户刚刚更新,尚未复制而这台Master就出现故障了,不过这种几率应该很小吧。
对于Central Database的复制滞后和同步问题,Flickr采用了一种复杂的“Write Through Cache"的机制来处理:

点看全图

"Write Through Cache"就是将所有的数据库”写“操作都先写入”Cache",然后由Cache统一去更新数据库的各个Node,“Write Through Cache"维护每一个Node的更新状态,当有读请求时,即将请求转向状态为”已同步“的Node,这样即避免了复制滞后和Memcached的同步问 题,但缺点是其实现极为复杂,“Write Throug Cache"层的代码需要考虑和实现所有”journal","Transaction“,“failover”,和“recovery"这些数据库已经 实现的功能,另外还要考虑自身的"failover"问题。我没有找到有关具体实现的说明,只能猜测这一部分的处理可能也是直接利用或是实现了类似于 Flickr的Queue系统吧。


posted @ 2011-03-12 16:59 Wolves 阅读(177) 评论(0) 编辑

维基百科(Wikipedia)是一个基于Wiki技术的全球性多语言百科全书协作计划,同时也是一部在网际网路上呈现的网路百科全书,其目标及宗旨是为全人类提供自由的百科全书──用他们所选择的语言来书写而成的,是一个动态的、可自由和的全球知识体。

wikipedia在IT架构方面的经验,对于我们构建网站极有参考价值,因为wikipedia提供的这些信息非常详细和确凿。下面是我学习Wikipedia架构后的一些总结。

1、Wikipedia的相关数据

2、系统架构图

Lighttpd是一个德国人领导的开源软件,其根本的目的是提供一个专门针对高性能网站,安全、快速、兼容性好,并且灵活的web server环境。具有非常低的内存开销,cpu占用率低,效能好,以及丰富的模块等特点。lighttpd是众多OpenSource轻量级的web server中较为优秀的一个。支持FastCGI, CGI, Auth, 输出压缩(output compress), URL重写, Alias等重要功能,而Apache之所以流行,很大程度也是因为功能丰富,在lighttpd上很多功能都有相应的实现了,这点对于apache的用户是非常重要的,因为迁移到lighttpd就必须面对这些问题。

6、使用MediaWiki软件

squid,~17台,P4,3~4GB内存,1U机架服务器,FedoraCore3;Squid 大部份应付未登入使用者的需求,快取命中率达75%,有效的减轻Apache的负载。负载平衡是以Round-Robin DNS法來达成。

Apache,49台,P4,1~4GB内存,1U机架服务器,FedoraCore2;运行PHP,且搭配Turck的PHP快取系統以增进效能。这些服务器以NFS共享工作目录,以实现同步运作。

转载自:http://www.itivy.com/ivy/archive/2011/3/7/634351127072679482.htmls

posted @ 2011-03-12 16:54 Wolves 阅读(183) 评论(0) 编辑