二月 16th, 2012 / No Comments » / by admin
1:安装,安装其实非常简单
#yum install subversion
测试是否安装成功
#svnserve --version
如果显示了版本信息则表示安装成功
2:配置
svn配置建立svn版本库目录可建多个:
新建一个版本库目录 名字为repos
#mkdir -p /opt/svndata/repos
建立svn版本库:
#svnadmin create /opt/svndata/repos
修改svn版本库配置文件版本库:
# vim /opt/svndata/repos/conf/svnserve.conf
内容修改为:
[general]
anon-access = none
auth-access = write
password-db = /opt/svn/conf/passwd.conf
authz-db = /opt/svn/conf/authz.conf
realm = repos
注重:对用户配置文件的修改立即生效,不必重启svn。
#vim /opt/svn/conf/passwd.conf
[users]
username = password
这里是配置用户名与密码
配置svn用户访问权限:
# vim /opt/svn/conf/authz.conf
注重:
* 权限配置文件中出现的用户名必须已在用户配置文件中定义。
* 对权限配置文件的修改立即生效,不必重启svn。
用户组格式:
[groups]
= ,
其中,1个用户组可以包含1个或多个用户,用户间以逗号分隔。
版本库目录格式:
[:/项目/目录]
@ =
=
其中,方框号内部分可以有多种写法:
[/],表示根目录及以下,根目录是svnserve启动时指定的,我们指定为/opt/svndata,[/]就是表示对全部版本库设置权限。
[repos:/] 表示对版本库repos设置权限
[repos2:/abc] 表示对版本库repos2中的abc项目设置权限
[repos2:/abc/aaa] 表示对版本库repos2中的abc项目的aaa目录设置权限
权限主体可以是用户组、用户或*,用户组在前面加@,*表示全部用户。
权限可以是w、r、wr和空,空表示没有任何权限。
示例:
[groups]
admin = alan
[/]
@admin = rw
[repos1:/abc/aaa]
king = rw
[repos2:/pass]
king =
svn 配置完毕。
启动svn建立启动svn的用户
# useradd svn
# passwd svn
根据提示,为用户svn设置密码
允许用户svn访问版本库:
# chown -R svn:svn /opt/svndata
启动svn
# su – svn -c “svnserve -d –listen-port 9999 -r /opt/svndata”
其中:
su – svn表示以用户svn的身份启动svn
-d表示以daemon方式(后台运行)运行
–listen-port 9999表示使用9999端口,可以换成你需要的端口。但注意,使用1024以下的端口需要root权限
-r /opt/svndata指定根目录是/opt/svndata
好SVN已经启动了,你可以通过svn://ip地址:端口/repos 这种方式来访问了
让他去后台运行,这样就OK拉
另外一个要说的是,有时候发现你的SVN连不上,也许是因为端口被防火墙墙掉的缘故
# telnet {your-server-ip} 9999 检查端口是不是通的
SVN默认端口为3690,而我们上面已经将其改为9999,你可以去iptable里面将他开放
# vi /etc/sysconfig/iptables
添加:
-A OUTPUT -p tcp -m tcp –dport 9999 -j ACCEPT
为了可以在修改完代码提交到SVN服务器后,WEB服务器直接同步.需要配置SVN的钩子,打开hooks目录,
可以看到有一个post-commit.tmpl文件,这是一个模板文件,
复制一份放在此目录下,命名为post-commit,并将其用户组设为apache,这样就有了访问apache目录的权限。
里面原有的代码全部注释掉.这里可以执行shell命令,每次commit完成后都会调用此文件.
我的文件内容为
#!/bin/sh
export LANG=zh_CN.UTF-8
svn export –username 你版本库的用户名 –password 用户名的密码 svn://你的IP地址:端口/dev/trunk/source/main/kBase /home/phpcms/public_html/kBase –force
另外还需要修改apache目录下.subversion文 件夹下的servers文件将其中一项改为store-plaintext-passwords = no,主要的原因是:执行脚本的时候会提示是否保存密码,root用户在交互状态下可以回答yes或no,而apache用户没有这个机会,所以要在 apache用户目录下的.subversion/servers中预先配置好
说明:
#!/bin/sh 说明是执行shell命令
export LANG=zh_CN.UTF-8 是为了解决svn post commit 中文乱码。
如果你是GBK编码可能会提示:Error output could not be translated from the native locale to UTF-8
这是客户端和服务器编码的问题,默认是utf-8,可尝试设置export LANG=zh_CN.GBK或者export LANG=en_US.UTF-8
svn export –username 你版本库的用户名 –password 用户名的密码 svn://你的IP地址:端口/dev/trunk/source/main/kBase /home/phpcms/public_html/kBase –force 执行更新操作
–force 是覆盖文件
另外还需要将写入的目录/home/phpcms/public_html/kBase添加svn的权限,不然会提示权限不够。
如果提示:post-commit hook failed (exit code 255) with no output赋予post-commit文件可执行权限
如果您的默认编码就是UTF-8的,要上传中文文件,先将文件另存为UTF-8格式在提交
Posted in: 未分类
十二月 3rd, 2011 / No Comments » / by admin
用jquery form插件,进行ajax提交,本来可以用,好好地,突然发现,firefox,opera等可以提交,ie的success函数运行了。
花了三个钟头,反复查,发现,原来是改了处理页面的返回头信息。
加上了 application/x-javascript ,ie8就不干活了。
如果是text/html,就行,或者不指定也行。
算bug不?让我问候一下写这段代码的ie开发人员吧。
ajax的头信息,编码看来都要注意哎。
Posted in: 未分类
九月 22nd, 2011 / No Comments » / by admin
流行的jQuery信息提示插件(jQuery Tooltip Plugin)
Learning, by 木公.
信息提示虽然是小东西,但是在网站设计中却起到了巨大的作用。如果你网站的信息提示做的好,会给访客留下非常深刻的印象。下面有30个非常流行的jQuery信息提示插件,希望对各位有所帮助。记住,所有的这些都是为了使网站设计更好。 
非常漂亮的tooltip!有渐变、透明、阴影等效果。

Dynamic tooltip
优秀的tooltip!虽然看起来简单,但是过渡效果非常棒,适用于简单干净的网站。

Popup Bubble
精美的tooltip!提示信息不会消失,除非你点击其它链接。看起来非常简单,但是它的动画效果却非常棒。

jQuery Horizontal Tooltips Menu Tutorials
多种多样的提示效果,极有效的简化工作过程。

Prototip
非常漂亮的信息提示,有过渡效果和背景阴影。

Coda Popup Bubble
非常酷的信息提示,平滑的过渡效果,并且有透明边框。

Awesomeness
漂亮的信息提示,有淡入淡出过渡效果,幻灯、阴影特效。

TipTip
这个是为输入框开发的信息提示,过渡效果美观。

(mb)Tooltip
简单但是非常好的信息提示,有淡入效果。

vTip
当点击链接时淡入出现,然后固定在右上角,一段时间后自动消失,或者可以手动关闭。

jGrowl
有趣的信息提示,可以处理像小型网页图片和文字。它有一个阴影效果。

jQuery Ajax Tooltip
漂亮的digg样式,适用于社交网站。

Digg-style post sharing tool with jQuery
有趣的输入框提示,边框为圆角。输入框获得焦点时淡入,点击其它地方淡出。

Input Floating Hint Box
漂亮的提示与褪色的过渡。将鼠标悬停在链接上,tooltip淡入在链接的上方或者下方。

Simpletip
很简单,但 好看的提示。可以圆角,说话提示的样式。

qTip
有趣的提示插件,您可以手动设定在您需要的时间出现。

Orbital Tooltip
漂亮的提示,有过渡效果。

Inline HTML Tooltip

tipsy

Easiest jQuery Tooltip Ever

BsTip

EZPZ Tooltip

BeautyTips

Tooltip
简单的提示,当鼠标悬停在链接上时出现,直到你关闭它才会消失。

clueTip
几个简单但是不同的提示。

Creating A Simple Tooltip Using jQuery and CSS
Tooltip出现在链接的右边。

BetterTip
简单但是对于登录页面非常有用。

jTip
简单的ajax加载效果,可以淡入淡出。

jqTooltip

Pop!
Simple tooltip with rounded corners. It follows your mouse movements.
简单的圆角tooltip,随鼠标移动。

Posted in: AJAX(Javascript)
Tags: jquery
九月 19th, 2011 / No Comments » / by admin
Eclipse3.76月22日正式发布,代号是Indigo,初次体验,在Windows7下初始后化,发现界面变化不大,字体却面目全非,小得根本看不见,而且也看起来很不爽。
Eclipse以前的默认字体一般是CourierNew字体,这种字体看着习惯。但当我试图修改回去时,发现字体列表里根本没有这种字体,郁闷了半天,终于在网上找到了解决方法。(iTeye(原JavaEye,因与Oracle发生名字纠纷而被迫改名))
具体的原因是jFace的问题,jFace顾名思义,是控制Eclipse整个用户界面的包,打开它后,可以看到里面有各个组件(比如菜单、对话 框、面板)的字体风格等属性。而且分成多个系统的属性(Windows7/Vista/XP/NT/2000,Linux等)。注意:这里保存的是默认属 性,修改界面后,这里的值将不起作用。
1.找到jFace并用WinRAR打开之:
jFace的具体位置:$Eclipse目录$/plugins/org.eclipse.jface_3.7.0.I20110522-1430.jar,找到后,用WinRAR打开。
2.找到并修改字体属性:
打开后,依次展开:/org/eclipse/jface/resources,这里,你将看到不同操作系统的字体设置,比如 jfacefonts_hp_ux,properties里保存了HP-UX系统的字体设置,jfacefonts_macosx.properties 则保存了MacX的字体设置。找到Windows7/Vista的字体设置,双击,随便用一个文本编译器打开,找到 org.eclipse.jface.textfont.0的配置项,将其设置成CourierNew-regular即可,后面还可以设置字号。修改完 成后,保存,WinRAR自动更新jar包。
3.启动EclipseIndigo,如果你没有修改过字体,将看到字体已经改过来了,但如果你修改了,则Reset一下,字体就会改过来了。
友情提示:修改文件的时候,一定要记着关闭Eclipse哦,否则无法修改成功!
Posted in: 未分类
Tags: 技术
九月 19th, 2011 / No Comments » / by admin
经过了几个小时的调试终于成功了,还要感谢 http://www.ciphp.com/2011/03/647 提供的解决方法,这里也记录一下,
以供朋友们参考,在解决这个问题的过程中,发现网上很多人都说在某某地方设置一下就可以了,也不仔细看下什么问题就回答!
这个问题好像是Eclipse Helios SP2 (PDT)的BUG, 似乎其它版本不存在此问题,在 zend for eclipse 里也不存在这个问题!
Eclipse PHP 版本:
Eclipse for PHP Developers
Version: Helios Service Release 2
下载地址: http://www.eclipse.org/downloads/
解决方法:
1. 下载这个文件Download the jar listed : http://sourceforge.jp/projects/pdt-tools/releases/51060 里面有3个文件
下载这个name org.eclipse.php.ui_2.2.1.v20101001-2300.jar 然后复制到你的eclipse的plugins目录里面
也许你的文件夹里已存在这个文件,覆盖就可以了!
Posted in: 未分类
Tags: PD, php
五月 18th, 2011 / No Comments » / by admin
一、Master/slave
这个是多机房数据访问最常用的方案,一般的需求用此方案即可。因此大家也经常提到“premature optimization is the root of all evil”。
优点:利用mysql replication即可实现,成熟稳定。
缺点:写操作存在单点故障,master坏掉之后slave不能写。另外slave的延迟也是个困扰人的小问题。
二、Multi-master
Multi-master指 一个系统存在多个master, 每个master都具有read-write能力,需根据时间戳或业务逻辑合并版本。比如分布式版本管理系统git可以理解成multi-master模 式。具备最终一致性。多版本数据修改可以借鉴Dynamo的vector clock等方法。
优点:解决了单点故障。
缺点:不易实现一致性,合并版本的逻辑复杂。
三、Two-phase commit(2PC)
Two-phase commit是一个比较简单的一致性算法。由于一致性算法通常用神话(如Paxos的The Part-Time Parliament论文)来比喻容易理解,下面也举个类似神话的例子。
某班要组织一个同学聚会,前提条件是所有参与者同意则活动举行,任意一人拒绝则活动取消。用2PC算法来执行过程如下
Phase 1
Prepare: 组织者(coordinator)打电话给所有参与者(participant) ,同时告知参与者列表。
Proposal: 提出周六2pm-5pm举办活动。
Vote: participant需vote结果给coordinator:accept or reject。
Block: 如果accept, participant锁住周六2pm-5pm的时间,不再接受其他请求。
Phase 2
Commit: 如果所有参与者都同意,组织者coodinator通知所有参与者commit, 否则通知abort,participant解除锁定。
Failure 典型失败情况分析
Participant failure:
任一参与者无响应,coordinator直接执行abort
Coordinator failure:
Takeover: 如果participant一段时间没收到cooridnator确认(commit/abort),则认为coordinator不在了。这时候可自动成为Coordinator备份(watchdog)
Query: watchdog根据phase 1接收的participant列表发起query
Vote: 所有participant回复vote结果给watchdog, accept or reject
Commit: 如果所有都同意,则commit, 否则abort。
优点:实现简单。
缺点:所有参与者需要阻塞(block),throughput低;无容错机制,一节点失败则整个事务失败。
四、Three-phase commit (3PC)
Three-phase commit是 一个2PC的改进版。2PC有一些很明显的缺点,比如在coordinator做出commit决策并开始发送commit之后,某个 participant突然crash,这时候没法abort transaction, 这时候集群内实际上就存在不一致的情况,crash恢复后的节点跟其他节点数据是不同的。因此3PC将2PC的commit的过程1分为2,分成 preCommit及commit, 如图。

(图片来源:http://en.wikipedia.org/wiki/File:Three-phase_commit_diagram.png)
从图来看,cohorts(participant)收到preCommit之后,如果没收到commit, 默认也执行commit, 即图上的timeout cause commit。
如果coodinator发送了一半preCommit crash, watchdog接管之后通过query, 如果有任一节点收到commit, 或者全部节点收到preCommit, 则可继续commit, 否则abort。
优点:允许发生单点故障后继续达成一致。
缺点:网络分离问题,比如preCommit消息发送后突然两个机房断开,这时候coodinator所在机房会abort, 另外剩余replicas机房会commit。
五、Paxos
Google Chubby的作者Mike Burrows说过, “there is only one consensus protocol, and that’s Paxos” – all other approaches are just broken versions of Paxos. 意即“世上只有一种一致性算法,那就是Paxos”,所有其他一致性算法都是Paxos算法的不完整版。相比2PC/3PC, Paxos算法的改进
- P1a. 每次Paxos实例执行都分配一个编号,编号需要递增,每个replica不接受比当前最大编号小的提案
- P2. 一旦一个 value v 被replica通过,那么之后任何再批准的 value 必须是 v,即没有拜占庭将军(Byzantine)问题。拿上面请客的比喻来说,就是一个参与者一旦accept周六2pm-5pm的proposal, 就不能改变主意。以后不管谁来问都是accept这个value。
- 一个proposal只需要多数派同意即可通过。因此比2PC/3PC更灵活,在一个2f+1个节点的集群中,允许有f个节点不可用。
另外Paxos还有很多约束的细节,特别是Google的chubby从工程实现的角度将Paxos的细节补充得非常完整。比如如何避免Byzantine问题,由于节点的持久存储可能会发生故障,Byzantine问题会导致Paxos算法P2约束失效。
以上几种方式原理比较如下

(图片来源:http://snarfed.org/space/transactions_across_datacenters_io.html)
后文会继续比较实践环境选取何种策略合适。
(PS: 写完后在Google Reader上发现本文跟王建硕最近发表的《关于两个机房的讨论》文章有点类似,特别是本文一、二方式。不过他的文章偏MySQL的实现,我的重点是一致性算法,大家可以有选择性的阅读。)
Posted in: 技术资料
五月 18th, 2011 / No Comments » / by admin
在前文《多IDC的数据分布设计(一)》中介绍了多IDC数据一致性的几种实现原理,遗憾的是,目前虽然有不少分布式产品,但几乎都没有开源的产品专门针对IDC来优化。本文从实践的角度分析各种方法优缺点。
背景资料 Latency差异
Jeff Dean提到不同数据访问方式latency差异
Numbers Everyone Should Know
L1 cache reference 0.5 ns
Branch mispredict 5 ns
L2 cache reference 7 ns
Mutex lock/unlock 25 ns
Main memory reference 100 ns
Compress 1K bytes with Zippy 3,000 ns
Send 2K bytes over 1 Gbps network 20,000 ns
Read 1 MB sequentially from memory 250,000 ns
Round trip within same datacenter 500,000 ns
Disk seek 10,000,000 ns
Read 1 MB sequentially from disk 20,000,000 ns
Send packet CA->Netherlands->CA 150,000,000 ns
这个数据对于我们设计多IDC数据访问策略具有关键的指导作用,我们可以用这个数据来衡量数据架构来如何设计才能满足高并发低延迟的目标。
这份数据实际上对所有网络应用及分布式应用开发者都具有很大借鉴作用,数据需要根据访问频率尽量放在latency小的地方。
1. 2PC/3PC/Paxos模式
在上文中提到,2PC/3PC相比Paxos有明显的缺点,因此最好不用于生产环境,这里就不再详述。
Paxos选择了CAP理论中的”Consistency, Partition”, 需要牺牲availability。它可以在多个IDC之间实现强一致性复制。
Paxos缺点
- IDC之间需要高速稳定网络
- 一个2f+1个节点的网络中,需要f+1个节点完成事务才能成功。
- Throughput低,不适合高请求量的场合。所以大部分分布式存储产品并不直接使用Paxos算法来同步数据。
2. Dynamo模式
Dynamo论文中并未专门描述Dynamo算法是否适合多IDC场景,只有少量文字提到
In essence, the preference list of a key is constructed such that the storage nodes are spread across multiple data centers. These datacenters are connected through high speed network links. This scheme of replicating across multiple datacenters allows us to handle entire data center failures without a data outage.
从上文看到,前提条件是“high speed network links” 可能对国内的情况不太适用。假如IDC之间网络不稳定,那会发生哪些情况呢?
Quorum 算法中,如果要考虑高可用性,则数据需要分布在多个机房。双机房如NRW=322由于单机房故障后可能会发生3个点中2个点都在故障机房,导致出现数据不 可用的情况,所以合适的部署是NRW=533,需要3个机房。大部分请求需要2个机房节点返回才能成功,考虑到多IDC的带宽及latency,性能自然 会很差。
Quorum算法在读写的时候都要从quorum中选取一个coordinator,算法如下
A node handling a read or write operation is known as the
coordinator. Typically, this is the first among the top N nodes in
the preference list. If the requests are received through a load
balancer, requests to access a key may be routed to any random
node in the ring. In this scenario, the node that receives the
request will not coordinate it if the node is not in the top N of the
requested key’s preference list. Instead, that node will forward the
request to the first among the top N nodes in the preference list.
如果严格按照Dynamo协议,coodinator一定要在N中第一个节点,那在3个机房中将有2/3的请求需要forward到异地机房的 coordinator执行,导致latency增大。如果对coodinator选择做优化,让client选取preference list中前N个节点中在本地机房的一个节点作为coordinator,这样会一定程度降低latency,但是会存在相同的key选择不同节点作为 coordinator的概率增大,导致数据conflict的概率增大。
同时在多机房模式下,Failure detection容易产生混乱。Dynamo并没有使用一致性的failure view来判断节点失效。而是由每个节点独自判断。
Failure detection in Dynamo is used to avoid attempts to
communicate with unreachable peers during get() and put()
operations and when transferring partitions and hinted replicas.
For the purpose of avoiding failed attempts at communication, a
purely local notion of failure detection is entirely sufficient: node
A may consider node B failed if node B does not respond to node
A’s messages (even if B is responsive to node C’s messages).
而最近非常流行的Cassandra基本上可以看作是开源的Dynamo clone, 它在Facebook Inbox Search项目中部署在150台节点上,并且分布在美国东西海岸的数据中心。
The system(Facebook Inbox Search) currently stores about 50+TB of data on a 150 node cluster, which is spread out between east and west coast data centers.
虽然在它的JIRA中有一个提案 CASSANDRA-492 是讲”Data Center Quorum”,但是整体看来Cassandra并没有特别的针对对IDC的优化,它的paper[5]中提到
Data center failures happen due to power outages, cooling
failures, network failures, and natural disasters. Cassandra
is configured such that each row is replicated across multiple
data centers. In essence, the preference list of a key is con-
structed such that the storage nodes are spread across mul-
tiple datacenters. These datacenters are connected through
high speed network links. This scheme of replicating across
multiple datacenters allows us to handle entire data center
failures without any outage.
跟Dynamo中的描述几乎是相同的。
3. PNUTS模式
PNUTS模式是目前最看好的多IDC数据同步方式。它的算法大部分是为多IDC设计。
PNUTS主要为Web应用设计,而不是离线数据分析(相比于Hadoop/HBase)。
- Yahoo!的数据基本都是用户相关数据,典型的以用户的username为key的key value数据。
- 统计数据访问的特征发现85%的用户修改数据经常来源自相同的IDC。
根据以上的数据特征,Yahoo!的PNUTS实现算法是
- 记录级别的master, 每一条记录选择一个IDC作为master,所有修改都需要通过master进行。即使同一个表(tablet)中不同的记录master不同。
- master上的数据通过Yahoo! Message Broker(YMB)异步消息将数据复制到其他IDC。
- master选择具有灵活的策略,可以根据最新修改的来源动态变更master IDC, 比如一个IDC收到用户修改请求,但是master不在本地需要转发到远程master修改,当远程修改超过3次则将本地的IDC设成master。
- 每条记录每次修改都有一个版本号(per-record timeline consisitency),master及YMB可以保证复制时候的顺序。
Yahoo!的PNUTS实际可理解为master-master模式。
一致性:由于记录都需通过master修改,master再复制到其他IDC, 因此可达到所有IDC数据具有最终一致性。
可用性:
- 由于所有IDC都有每条记录的本地数据,应用可以根据策略返回本地cache或最新版本。
- 本地修改只要commit到YMB即可认为修改成功。
- 任一IDC发生故障不影响访问。
论文中提到的其他优点
hosted, notifications, flexible schemas, ordered records, secondary indexes, lowish latency, strong consistency on a single record, scalability, high write rates, reliability, and range queries over a small set of records.
总之,PNUTS可以很好的适合geographic replication模式。
- 记录publish到本地YMB则认为成功,免除Dynamo方式需要等待多个Data Center返回的latency。
- 如果发生master在异地则需要将请求forward到异地,但是由于存在master转移的策略,需要forward的情况比较少。
极端情况,当record的master不可用时候,实现上似乎有些可疑之处,读者可自行思考。
Under normal operation, if the master copy of a record fails, our system has protocols to fail over to another replica. However, if there are major outages, e.g. the entire region that had the master copy for a record becomes unreachable, updates cannot continue at another replica without potentially violating record-timeline consistency. We will allow applications to indicate, per-table, whether they want updates to continue in the presence of major outages, potentially branching the record timeline. If so, we will provide automatic conflict resolution and notifications thereof. The application will also be able to choose from several conflict resolution policies: e.g., discarding one branch, or merging updates from branches, etc.
初步结论
低带宽网络
PNUTS record-level mastering模式最佳。
高带宽低延迟网络
(1Gbps, Latency < 50ms)
1. 用Dynamo Quorum, vector clock算法实现最终一致性
2. 用Paxos实现强一致性
后记
本文从开始准备到发布时间较长,由于在多IDC数据访问方面目前业界并无统一的成熟方案,相关资料和文献也相对较少,而且对这方面有兴趣且有相应环 境的人不多,短时间要提出自己成熟独立的见解也具有一定难度,本文仅包含一些不成熟的想法的整理,由于自己对文中的观点深度也不是满意,所以一直没有最终 完稿发布。但考虑到最近工作较忙,暂时没有精力继续深入研究,所以希望公开文章抛砖引玉,同时也欢迎对这方面课题有兴趣者进一步交流探讨。
Posted in: 技术资料
五月 18th, 2011 / No Comments » / by admin
场景
Mutex主要用于有大量并发访问并存在cache过期的场合,如
首页top 10, 由数据库加载到memcache缓存n分钟
微博中名人的content cache, 一旦不存在会大量请求不能命中并加载数据库
需要执行多个IO操作生成的数据存在cache中, 比如查询db多次
问题
在大并发的场合,当cache失效时,大量并发同时取不到cache,会同一瞬间去访问db并回设cache,可能会给系统带来潜在的超负荷风险。我们曾经在线上系统出现过类似故障。
解决方法
方法一
在load db之前先add一个mutex key, mutex key add成功之后再去做加载db, 如果add失败则sleep之后重试读取原cache数据。为了防止死锁,mutex key也需要设置过期时间。伪代码如下
(注:下文伪代码仅供了解思路,可能存在bug,欢迎随时指出。)
if (memcache.get(key) == null) {
// 3 min timeout to avoid mutex holder crash
if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
value = db.get(key);
memcache.set(key, value);
memcache.delete(key_mutex);
} else {
sleep(50);
retry();
}
}
方法二
在value内部设置1个超时值(timeout1), timeout1比实际的memcache timeout(timeout2)小。当从cache读取到timeout1发现它已经过期时候,马上延长timeout1并重新设置到cache。然后再从数据库加载数据并设置到cache中。伪代码如下
v = memcache.get(key);
if (v == null) {
if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
value = db.get(key);
memcache.set(key, value);
memcache.delete(key_mutex);
} else {
sleep(50);
retry();
}
} else {
if (v.timeout <= now()) {
if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
// extend the timeout for other threads
v.timeout += 3 * 60 * 1000;
memcache.set(key, v, KEY_TIMEOUT * 2);
// load the latest value from db
v = db.get(key);
v.timeout = KEY_TIMEOUT;
memcache.set(key, value, KEY_TIMEOUT * 2);
memcache.delete(key_mutex);
} else {
sleep(50);
retry();
}
}
}
相对于方案一
优点:避免cache失效时刻大量请求获取不到mutex并进行sleep
缺点:代码复杂性增大,因此一般场合用方案一也已经足够。
方案二在Memcached FAQ中也有详细介绍 How to prevent clobbering updates, stampeding requests,并且Brad还介绍了用他另外一个得意的工具 Gearman 来实现单实例设置cache的方法,见 Cache miss stampedes,不过用Gearman来解决就感觉就有点奇技淫巧了。
Posted in: 技术资料
五月 18th, 2011 / No Comments » / by admin
Posted in: 技术资料
五月 18th, 2011 / No Comments » / by admin
Web数据访问比较好的设计模式是使用cursor方式(参考前文用Twitter的cursor方式进行Web数据分页),原理上相当于增量方式访问数据,可以极大提高访问性能。
在单IDC场景中,如图1,系统的id是递增,假设用户上一次访问最新一条记录是1002,则本次访问最佳的方式是 get?cursor=1002,可以高效取到后面3条新记录。

多IDC场景,看图2,假设白色背景属于Region 1,灰色背景属于Region 2, 由于两地同步有延迟,这样在Region 1中1001和1003来到时间较晚,排在本地数据1002和1004后面。假设用户上一次也是取到最新一条是1002(注意此时1001没取到,因为从 外地未同步过来)。在Region 1调用 get?cursor=1002返回结果会得到什么?从数据库角度来看,访问cursor=1002 只会取到id>1002的记录,而上次未取到的1001即使已经同步过来是永远不会返回了。这样就产生了数据一致性问题,1001丢了。另外一个机 房Region 2调用也产生类似问题。不同的cursor产生不同的丢失问题。
提出这个问题后身边很多技术人员非常感兴趣,经常走在路上被拦住介绍他们突然想到的一种更巧妙的解决方法。部分思路如下
(这里先不考虑ID递增算法如何实现,多IDC使用K-SORT方式递增也是比较容易的)
- 例外的方式,把迟到的id都存下来
- 补方式,把cursor往前多取一点,宁滥毋缺
- 快照方式,最近取的记录都存下来,这样服务器内部知道这个cursor上次哪些id取了哪些没取
大部分方法貌似都能工作,但都有问题或不完美,更重要的一点,也就是上周演讲中提到的,架构要把复杂的问题抽象简单,很多技术人员面对这个问题,并没有深层次思考这个场景的问题本质是什么,因此虽然匆匆考虑了很多复杂的解决方案,但是没有完美解决问题。
有兴趣的朋友可以继续思考,看能否将复杂的问题抽象简单并解决?
Posted in: 技术资料