2008-08-21 Thu
Facebook 其实对待技术的态度其实挺开放的。今天阅读了这篇 Scale Out, 工程师 Jason Sobel 介绍了在对付跨地域 MySQL 复制网络延迟的问题。
Cache 一致性问题解决思路
大量的 MySQL + Memcached 服务器,布署简示:
California (主 Write/Read)............. Virginia (Read Only)
主数据中心在 California ,远程中心在 Virginia 。这两个中心网络延迟就有 70ms,MySQL 数据复制延迟有的时候会达到 20ms. 如果要让只读的信息从 Virginia 端发起,Memcached 的 Cache 数据一致性就是个问题。
- 1 用户发起更新操作,更名 "Jason" 到 "Monkey" ;
- 2 主数据库写入 "Monkey",删除主、从两端 Memcached 中的名字值;
- 3 在 Virginia 有人查看该用户 Profile ;
- 4 在 Memcached 中没发现用户名字,从 Virginia Slave 数据库读取,因为网络延迟,结果读到了 "Jason";
- 5 更新 Virginia Memcached 中的该用户名字为 "Jason";
- 6 复制追上了,更新名字为 ""Monkey";
- 7 又有人读取 Profile 了;
- 8 在 Memcached 中找到了键值,返回 "Jason" (实际上造成业务冲突了)
解决办法挺有意思,在 SQL 解析层嵌入了针对 Memcached 的操作。
- 1 用户发起更新操作,更名 "Jason" 到 "Monkey" ;
- 2 主数据库写入 "Monkey",删除主端 Memcached 中的名字值,但Virginia 端 Memcached 不删;(这地方在 SQL 解析上作了一点手脚,把更新的操作"示意"给远程);
- 3 在 Virginia 有人查看该用户 Profile ;
- 4 在 Memcached 中找到键值,返回值 "Jason";
- 5 复制追上更新 Slave 数据库用户名字为 "Monkey",删除 Virginia Memcached 中的键值;
- 6 在 Virginia 有人查看该用户 Profile ;
- 7 Memcache 中没找到键值,所以从 Slave 中读取,然后得到正确的 "Monkey" 。
这里面的一个简单的原则是: 更新后的数据,用户第一次读取要从数据库读,顺便扔一份到 Cache 里,而不是在写入的时候直接更新 Memcached 。避免写事务过大。
而写操作的原则是:一次写入,到处分发。
第二个问题是关于"Page Routing"的 ,也很有参考价值。感兴趣的自己读一下吧。
--EOF--
另推荐一下: 分布式系统中的一致性和可用性,该文是上次在支付宝 QClub 活动的总结之二。
由于IO的请求不是每次等待完成指令后再发送下一个请求,而是存在于队列中,且遵循FIFO。因此如果遇到存储掉电的情况,就可能会出现数据的不一致。虽然这种情况出现的可能性不大,因为存储中有电池,能保证cache中的信息写到存储中。但是在这里还是提一下数据丢失的风险。
由于我们的异步IO的队列中是针对使用裸设备的IO请求,即redo log、datafile和controlfile,这边分2种情况讨论存储掉电时候,数据的丢失情况(注:以下情况考虑的是cache中的IO请求丢失,但是文件未损坏的情况):
(1)当记录A insert到表中,已经commit,记录B insert到表中,未commit,此时checkpoint未发生时。此时的IO队列中有insert A的redo请求,insert B的redo请求,但未有buffer向dbfile写的请求。此时掉电,oracle端的情况是oracle认为redo的IO请求已经写到redo log,os端的情况redo的IO请求还没写到redo log中。重启数据库时候之前的oracle端认为redo和dbfiles的scn不一致,需要介质恢复,但是在启动的时候,读取redo log,由于在os级上尚未写入,redo log和dbfiles的scn一致,因此正常启动,但是丢失AB记录。
(2)当记录A insert到表中,已经commit,记录B insert到表中,未commit,此时发生了checkpoint。此时的IO队列中有insert A的redo请求,insert B的redo请求,A记录从db buffer向dbfile写的请求,还有控制文件被更新的请求。当都未写到裸设备时掉电,oracle端的情况是oracle认为redo的IO请求已经写到redo log中,db buffer的请求已经写入了数据文件,控制文件已经被更新,os端的情况是redo的IO请求和写dbfiles的IO请求均未完成,控制文件未更新。重启数据库时,由于scn还是一致的,因此能正常打开,但丢失cache中的A、B记录。
(3)当记录A insert到表中,已经commit,记录B insert到表中,未commit,此时发生了checkpoint。此时的IO队列中有insert A的redo请求,insert B的redo请求,A记录从db buffer向dbfile写的请求,还有控制文件被更新的请求。当redo的请求已经被写入redo log,但是A记录从db buffer向dbfiles写的请求和更新控制文件的请求还没写的时候掉电。Oracle端的情况是oracle认为redo的IO请求已经写到redo log中,db buffer的请求已经写入了数据文件,控制文件已经被更新,os端的情况是redo完成写入redo log,但是dbfiles未写,控制文件未更新。重启数据库,oracle读取了redolog、控制文件、dbfile,发现redo log、dbfile不一样,需要介质恢复。AB数据不丢失。
2008-08-20 Wed
这几天,在客户处实施Sybase ASE到Oracle 10g的变化数据捕获以及数据转换的前期测试工作,问题此起彼伏,但最终效果圆满,感觉上仿佛遇神杀神,遇鬼杀鬼。不拽了,总结一下遇到的问题以及相应的解决方法。
一. ODI连接数据库阶段
1. JDBC版本 - jConnect 5.5
ODI自带的JDBC驱动无法正常连接Sybase ASE数据库。
解决方法:需要去Sybase站点上下载jConnect 5.5版本,然后将其中的jconn2.jar文件拷贝进ODI安装目录的drivers文件夹中,之后再次选择com.sybase.jdbc2.jdbc.SybDriver,才可以连接。
2. 为什么不选择jConnect 6.05
因为在jConnect 6版本以后,”getColumnName”方法返回的是列的COLUMN Name,而之前的版本都是返回列的ALIAS,而ODI使用的都是列ALIAS,因此如果选用jConnect 6.05,那么在最后执行Interface的时候,将会碰到下面的错误:
com.sunopsis.sql.SnpsMissingParametersException: Missing parameter…
解决方法:使用jConnect 5.5,这也是Oracle lab test时推荐的JDBC驱动版本。
3. JDBC连接串的写法
如果写法如下:
Driver是:com.sybase.jdbc2.jdbc.SybDriver
连接串是:jdbc:sybase:Tds:172.22.224.106:4100/dbemp1
连接时将碰到JZ00L错误,已经确保用户名和密码一定正确:
java.sql.SQLException: JZ00L: Login failed. Examine the SQLWarnings chained to this exception for the reason(s).
解决方法:添加charset属性,修改连接串为 jdbc:sybase:Tds:172.22.224.106:4100/dbemp1?charset=eucgb
最后Physical Schema的设置应该类似如下界面(点击以后放大)。

二. Datastore创建阶段
1. Sun JDBC-ODBC Bridge驱动无法实施反向工程(Reverse Engineering)
因为一开始配置jConnect驱动的时候死活无法连通,因此尝试了Sun JDBC-ODBC Bridge驱动,这种方法需要首先在机器上创建一个ODBC连接,因此也就需要Sybase客户端,所以实际上是不推荐的,而且通过JDBC-ODBC Bridge连接进数据库以后,发现无法执行反向工程。
解决方法:放弃这种方法,换用jConnect连接Sybase ASE。
2. Changed Data Capture
对于创建了唯一聚簇索引的Sybase表也无法启动Journal,必须需要Primary Key。没有主键在启动Journal的时候会碰到如下错误:
com.sunopsis.tools.core.exception.SnpsSimpleMessageException: Journalizing requires a Primary Key on the Table:ODI_TEST
解决方法:在表上创建Primary Key。
三. Interface执行阶段
1. Oracle端表中包含Date或者Timestamp类型的字段时,执行时报ORA-30088错误
如果包含DATE或者TIMESTAMP类型字段的Datastore是由反向工程直接从数据库中reverse生成的,那么对于DAYE字段,默认的Logical Length是7,对于TIMESTAMP字段默认的Logical length是16,那么这样在执行阶段的create work table步骤中,将会按照这些Logical Length来在目标数据库端创建C$_表,而DATE(7)或者TIMESTAMP(16)这样的语法都会报ORA-30088错误。
java.sql.SQLException: ORA-30088: datetime/interval precision is out of range
解决方法:在reverse生成Datastore以后,手工修改DATE和TIMESTAMP类型的字段,将Logical length改为空,Scale也改为空。

2. 执行时,Loading data步骤时报7725错误
在执行Interface的时候,到Loading data这一步,报如下错误:
7725 : ZZZZZ : com.sybase.jdbc2.jdbc.SybSQLException: Cursor ‘jconnect_implicit_2′ was declared with a FOR UPDATE clause. This cursor was found to be read only.
这是花费了最长时间解决的错误,十分感谢Rich Ho何致亿,帮我发邮件到OracleDI的邮件列表中去提问。
解决方法:在Topology Manager中将Data Server的Array Fetch Size和Batch Update Size设置为0,默认是30。
到今天为止,ODI的大致架构和基本功能算是掌握了,更加深入的学习还要看以后这个项目是不是会继续下去了。
昨天下午,第一次降落在北京国际机场三号航站楼,从兰州返回北京,结束了这一周的旅程。
感谢兰州大学李仲贤老师的邀请,在兰大进行了一次为期两天左右的技术交流。
然后顺路西上,经嘉峪关、至敦煌,走青藏公路,出玉门关,深入戈壁,在归途中,我们甚至看到了难得一见的海市蜃楼。当时在茫茫戈壁的尽头,看到清晰的海中山,云水环绕,还有红砖墙逶迤环绕,司机师傅说,这样的景象在沙漠里是很常见的。
下面这张照片就是来自嘉峪关 - 天下第一雄关 的最后一道城门,出了这道门就是塞外:
在敦煌,丝绸之路的明珠之上,我们足登鸣沙山,掬水月牙泉,听大漠驼铃,彻底圆了我的西行梦。
至于在莫高窟,除了赞叹之外,更多的是气愤,众多的历史珍宝流落海外,不知何日能重演辉煌了。
这次的旅程非常开心,美中不足是我一直被感冒发烧所困扰,期待下一次再赴敦煌。
下面这张照片来自玉门关,以前出了这道门,就是茫茫戈壁,春风都不度的地方:
感谢李老师全家同行,李萱小美女的体力与耐力都是相当不错,一直陪我们走完了所有的旅程,感谢吴斌帮我负担了不少的重量,为我拍摄了大量的照片。
还要感谢公安系统的林科长,他的关照使我们的旅途顺利而舒畅,更重要的是他对软件及系统的了解让我对甲方的印象大为改观!
这次最远的地方到达玉门关外的雅丹地貌景区,距离新疆仅有8Km:
希望以后有机会再赴兰州,重走丝绸之路!
-The End-
相关文章|Related Articles
评论数量(0)|Add Comments
本文网址:http://www.eygle.com/archives/2008/08/lanzhou_silkroad.html
史冬鹏没能进决赛,但他尽力了。纵观大史一直以来在赛场上的表现,他是真正诠释体育精神的英雄。
赛前,我是多么希望史冬鹏能在这次"家门口"的比赛中夺得一枚奖牌,但这毕竟是比赛,胜负只在一瞬间。尽管以后还有更多的比赛,还有世锦赛,大史说"那毕竟不一样",这是绝对的真心话!
刘翔几乎独占了所有可用的资源,留给大史的资源太少了。从这一点上来说,刘翔是一个团队在作战,而大史只是一个人在战斗! 赛前刘翔的信息铺天盖地,关注大史的文章少而又少。看过的文章中,只有《环球企业家》的这篇特刊《奔跑者》能让读者了解一下关于大史的更多信息。
史冬鹏,加油!期待你的精彩!
--EOF--
还要控诉一下冬日娜这"梅超风",你能不能少说几句弱智的话? "没关系,毕竟你上次连第二轮还没跑进呢" ,这是人说的话么?
你平常用什么IM工具跟朋友们联系呢,MSN,QQ,yahoo messager 还是gtalk?也或者其中的几个,是不是为每次都要登录几个工具而发愁?既要输入不同的帐号和密码,而且多个工具意味着占用更多的系统资源。今天就给大家隆重推荐一款开源的多协议IM工具-Pidgin
下面是pidgin的一个简单介绍:
介绍
Pidgin(Gaim)是模块化的即时通讯客户程序,同时支持QQ、MSN、Jabber(gtalk)、AIM、Yahoo! 、ICQ、IRC、SILC、Novell GroupWise、Napster、Zephyr 和Gadu-Gadu。
Pidgin(Gaim)基于GTK+,并以GPL 许可协议发行。 支持多平台、多语言、多服务、多插件。
功能
同时登录多个帐户,可以同时登录多个MSN帐号,也可以同时登录MSN和gtalk帐号,不受任何限制。
同时更改状态,已经登录的帐号可以一起改状态,比如一起改为隐身。
好友千里眼的功能,当某好友上线或下线的时候,可以发出问候消息或改为隐身状态,这是可配置的。所有可登录的帐号都拥有这个功能,不再限制于QQ。
同一个窗口放置多个聊天窗口,任务栏上不再有一大片聊天窗口了,当然也可以将聊天窗口分开显示。同样适用于所有的帐号。
多种提醒方式,可以在标题上显示消息数,也可以闪烁窗口,适用于所有的帐号。
好友多种排序方式,可以按字母序,也可以按状态排序,也可以按聊天记录大小排序(独有的功能,明显区分熟悉度),也适用于所有的帐号。
公共分组,所有帐号的好友可以统一管理,QQ和MSN的好友可以放在一个组里,这样方便自己对好友的管理,感觉不到帐号的区别,当然也可以按帐号分组,适用于所有帐号。
隐私设置,可以只让好友聊天,或屏蔽所有对话,分级别设置隐私是独有的功能,同样适用于所有的帐号。
跨平台运行,gtalk、qq等软件没有linux的版本,可以使用Gaim来代替。其它平台也可以兼容。
好了,说了这么多,一定想马上试用一下吧,赶紧下载去吧,Windows版本,如果你想自己进行改进,可以到sourceforge 下载源代码
我自己比较常用MSN,OIC(Oracle Instance Chat),偶尔用下gtalk和qq,下面是我的帐号配置页面。

带宽与I/O
带宽与I/O 这是两个衡量存储设备性能最基本的概念,明确的区分两者也是对存储产品性能了解的第一步。如果我们把存储设备比做一间会议室,被存取的数据就是前来参加会议或从会议中离开的人,那么带宽性能就是指这间会议室大门的宽度,大门越宽,可以同时进出的人也就越多,而I/O性能是指房门开合的频繁程度,迎来一批前来参加会议的人,就需要打开一次大门,送走一批人也是一样,哪怕这“一批人”其实只是一个人。由此可见,当我们考察会议室的门设计得是否合理时,必须结合会议本身的性质。 对纪律严明的会议来说,与会者轻易不会凌乱的进出会场,人们在会议开始时统一进入,结束时再统一离开。对这种情况,门的宽度就十分重要,而是否易于开合则显得不那么关键,反正这扇门在整个会议中只需要开合两次而已。相反的,对于联欢性质的聚会而言,门设计得太宽除了显得气派之外,并没有什么实际的意义,但是门开合的频率却很重要,因为会有客人频繁的进进出出。 对应到存储设备上,道理也是一样。大文件持续传输型的应用需要的是充分的带宽性能,而小文件随即读写的应用则要求足够的I/O能力。那么多大的文件算“大文件”呢?一般而言,超过1MB大小的文件就可以算做“大文件”了。如果您的应用系统处理的资料中,最小的文件也有4~5MB甚至几十MB,就需要重点考察存储系统的带宽性能了。如果您的应用是数据库形式,或是电子邮件系统,系统中有大量KB级大小的文件,那么就可以忽略掉产品介绍中xxx MB/s的字样,重点关心xxx IOPS就可以了。
影响性能的因素
当然,仅看产品彩页中的简单数字还是远远不够的。存储设备的标称指数只是其最最理想情况下的表现,而实际应用中,存储设备表现出的处理能力往往与其标称指数相去甚远。为了反映更多的细节,会议室的比喻不足以说明问题。所以我们前面的例子再改进一下,把存储设备看作一栋有很多房间的大厦。人们从门口进入大厦,先来到大堂,经过走廊,最后到达房间。人们进大厦的方式也分为两种:一种是所有人按房间号码顺序排好队,一起进入大厦,我们称之为“顺序进入”;另一种是他们无规律的自由进入,我们称为“随即进入”。
显而易见,“顺序进入”的效率要大大高于“随即进入”。这就说明,一般情况下,顺序读写的性能要远高于随即读写的性能。还有一个结论也不难得出,一个宽敞的大堂更有利于偶然性较大的“随机进入”,而对“顺序进入”的人群而言,经过大堂基本属于浪费时间。存储设备中的“大堂”就是高速缓存。也就是说,大容量高速缓存可以提高随机读写性能,而对顺序读写的性能改进则不明显。
还记得前面讨论的带宽和I/O的差别吗?带宽考察的是单位时间进入大厦的人数,而I/O关心的是单位时间进出大厦的批次。从次可见,如果走廊没有任何变化,那么大堂只要不是太小,就不会影响带宽性能。相对的,对I/O性能而言,大堂显然是越大越好。总之,影响带宽的因素主要是前端控制器(大门)和后端磁盘通道(走廊)的带宽;而影响I/O的因素主要是控制器(大门)处理能力和高速缓存(大堂)容量。
当然,前面的讨论都基于一个假设前提:磁盘(房间)足够多。如若只配置寥寥几个磁盘,它们就会成为整个系统的性能瓶颈。任凭其他配置如何奢华,也于事无补。那么,“足够多”又是多少呢?对光纤通道存储设备来说,每个光纤通道上的磁盘数量达到50~60个的时候性能达到最佳。所以一般中高端存储设备都把每通道50~60个磁盘设计为扩展极限,而不是光纤通道技术规定的126个。

图1. 磁盘数量影响光纤环路性能
这样设计存储产品,可以让系统的性能随着容量的增加而增长。但是同时,用户必须明白,在容量没有配置到最大值的时候,性能就无法达到厂商所宣称的指标。一些厂商还声明其产品的性能可以随着容量的增长而线性增长,按这样讲,当你的存储设备只配置了最大容量的一半时,你得到的性能也只有系统最佳性能的一半。
性能曲线
这里所说的“最佳性能”就是厂商所宣称的指数吗?很遗憾,答案是不一定,一般都不是,而且可能会相差很远!我已经听到有人在叫“天啊!那厂商公布的数字到底有什么意义啊。”别急,看到下面两个图示就清楚了。

图2. IOPS性能曲线示例

图3. 带宽性能示例
这两个图示是典型的存储设备性能实测曲线,所有曲线来自同一个存储设备的同一个配置。不同产品在纵向指标上表现各异,但曲线的形状都大体相同。从图上可以看出,用户环境中存储设备的性能表现严重依赖数据块的大小。以顺序读取操作为例,如果应用产生的数据块大小在8KB左右,那么带宽性能和I/O性能最多也只能达到峰值性能的一半左右。如果希望得到更好的I/O性能,就需要尽量将数据块调整得更小。但不幸的是,如果希望带宽性能更好,就需要想办法把数据块设置得更大。看来,带宽与I/O性能是鱼与熊掌,难以兼得啦。
不过没关系,如我们前面提到的,幸好大多数用户其实只需要其中一种性能。要么是大文件类型的应用,需要带宽性能;抑或是小文件类型应用,需要I/O能力。需要带宽的用户相对容易得到满足。从图3可以看出,只要数据块大于128KB,顺序读的性能就基本可以达到系统饱和值。对顺序写,饱和数据块略大一些,但256KB也不算难以达到的尺寸。
得到最佳的I/O性能似乎就没那么容易了。从图2的曲线来看,I/O性能并没有一个饱和状态,这就要求数据块无穷尽的尽量小。然而所有应用都不可能支持无穷小的数据块。实际上,大多数的数据库应用产生的数据块都在2KB或4KB左右。在这个尺度上,应用得到的性能距离最高性能还有至少20~30%的空间呢。
持续和突发
回到我们那个关于大厦的例子。如果大厦临时发生紧急情况,比如火灾,人们争先恐后的蜂拥在门口,景象一定是一片混乱。在实际应用中,存储系统也可能遭遇类似的情况,一时间大量数据同时被访问,造成系统严重堵塞。这就像存储系统内的交通高峰,往往需要类似交通管制的手段才能提高系统效率。一些厂商会宣称他们的产品在这种情况下的“交通管制”能力有多强,以致可以从容应付大规模的突发访问。诸如“全交换结构”、“直接矩阵结构”等技术均属此类。究其本质,这些“交通管制”都是在大堂(高速缓存)的设计上做文章,将原本一个公共大堂的结构变成若干独立大堂的结构。以此来避免火灾发生时,所有人都拥挤到一个大堂里。
这样设计的确可在访问突然爆发时缓解系统压力,但是需要注意,这样设计的大厦内部一定布满了各种指示牌和路标,对任何一个进入大厦的人而言,进入房间的过程都将变得更复杂。其结果就是,非突发状态下,系统的持续读写能力往往还不如同等计算能力的简单结构存储。
其他影响
除了前面所谈到诸多方面外,还有很多因素都会影响到存储设备在实际运行中的性能。例如RAID级别的设置、磁盘类型甚至型号批次的匹配、缓存的镜像、SCSI指令队列深度的设置,这些方面都与性能结果直接相关。而且,为了能够得到最好的性能指数,几乎所有的厂商在测试自己产品性能的时候都会采用无冗余的RAID0、选用15k rpm的高速磁盘、将写缓存镜像保护关闭或者干脆关闭写缓存、将指令队列深度设置为最大。如此配置方式相信不是每个用户都可以接受的。
另外,所有存储设备在运行快照或远程镜像等附加功能之后,性能都会明显下降,有些情况甚至会下降60%之多。如果用户的应用恰巧需要这些附加功能,就需要在选用存储设备之前认真的实地测量一下真实性能。免得满怀希望的买回家,使用起来却失望至极。
这样的例子其实并不少见,记得我国某大型铁路局的某重要系统就曾经有过这样的失望经历。那时某国外知名厂商的一款中端存储设备刚刚下线,号称是全球第一款可以支持远程容灾的中端存储产品。正值铁路系统整体调整,该单位认为这款产品即可以实现远程容灾的功能,又只有中端产品的价格,是个性能价格比很高的产品。但是采购之后才发现,这款产品作为普通存储设备时,性能还可以应付系统压力,但是启动远程数据镜像之后,性能下降到原来的三分之一,完全无法满足系统需求。几经努力都失败之后,用户只好放弃了这个鸡肋,而为此付出的软硬件投资也付之东流。
