好长时间没更新blog了,原因是太忙这个永远的借口,TT&TC正在工作环境中尝试性的运用,不过还在开发阶段,具体实际负载下会出现什么问题还有待时间进一步的考验。
———————我是废话和正文的分隔线————————
内容提要
今天打算说一个应用层面上的东西,关于tokyo tyrant的主从同步特性及利用其构建主从式存储(缓存)的方式,后面顺便扯了一下不相干的TT用作计数器的方案。
TT主辅同步原理
网上讲TT的文章基本都会提到这么一句:可以实现双机互为主辅互相备份的功能。
但我要说,这只是TT主辅同步功能的一个实现实例,基于原理的变化,还可以演化出很多种同步方案。
TT的主从同步方式很简单,在启动某一个TTserver的时候,指定他要同步的另一个server的host和port就可以实现,指定这他们的启动参数分别是-mhost 和 -mport。
TT采用的是从机向主机拉式的主从同步策略(详见我之前的文章:),这一规则只有一个限制,就是一个从库只能从一个主库同步数据。
在这一策略下,可以衍生出多种架构方案,比如计算机网络中的星形,环形等。
如我们可以架设一个主TT供写入,再构建任意多个从TT,将同步源指向主TT,这几个TT做辅库支持读应用。
我们可以将两个TT做双机主辅,分别将同步方指向对方来做单点写入模式的容灾方案。
我们甚至可以将多个TT做成环形,1->2 2->3 3->1,这样无论哪一点的写入,都会最终传递到所有机器上,而且由于TT用时间戳标记每一条写操作,所以不用担心会出现死循环的情况。但这样如果任意一点死的话,会造成断链,可以考虑做一些动态检测方案来侦测倒掉的TT并做相应处理(再启动或将其下一节点的从机的指向改到倒了的TT的上一个节点,如链表中的删除元素操作指针)
实例
下面说一个TT架构方式实现多IDC缓存同步:
1.一是基于上面的主从特性做的,用TT架构同步缓存方案。
我们都知道,用MC做缓存的时候,会遇到一个问题,就是如果异地多IDC部署,两地同样的缓存数据,那么当用户在某一地更新了数据,可能要涉及到清缓存的操作,这时候本地的缓存可以很容易的清,异地的缓存就不那么容易清了。
facebook在启用新的IDC的时候遇到过这个问题,他们首先考虑的是双写清缓存,就是在清缓存的时候,把两地缓存同时清了,但是这时出现一个问题,因为两地的数据库是通过MySQL的主辅来实现同步的,主辅会有一定的延迟,如果在清掉了两个IDC的缓存,而第二个IDC的辅库还没有更新的时候,用户请求了数据,那这时会请求没有更新的这个从库,而缓存数据重建后也是没有更新的数据。长此下来,大家可以想一下,会导致缓存中的数据始终落后DB中一个更新周期,是一个永远也不可能趋近的最终一致性幻想。当然facebook没有这样做,他们是用MySQL来做的,当主库更新的时候,mysql主从同步信息传到从库之后,再多做一件事,清缓存,所以是先更新从库,再清缓存,这样可以保证两个IDC的数据延迟xx地为数据库主辅同步延迟。也能够保证多个IDC缓存与DB中所有数据的最终一致。
而用TT就根本不用考虑这些问题,上面说的双机主辅就直接可以搞定了。
2.下面这个和上面讲的东西无关,是将TT用作计数器的做法。
先说一下原理,关于TT的锁机制。研究TT源码发现,TT在写操作的时候都会加锁。这样对同一个key的写操作就会被顺序执行,不会出现并发操作的情况。
但是锁是一个很恶心的东西,他会导致性能的直接下降,一是维护锁的成本,二是在数据被锁的时候,会导致写操作阻塞,严重影响性能。TT在一开始初始化了32把锁,通过不同的key的hash值选择不同的锁,同一个key肯定取得同一把锁,从而保证对同一个数据元素的原子性写操作。为什么是32把锁呢?我想这是一个权衡数字,无疑,越多的锁就好像hash存储中越多的bucket数量,越多的锁会导致更少的hash碰撞,能让更多的线程同时操作,但是更多的锁又意味着更大的维护成本。所以作者{zh1}选择了32把锁,并且这是一个不可配置的数字,需要配置的话需要修改原码中的“RECMTXNUM”常量再进行编译。
言归正传,正是因为TT的锁机制,保证了对单个key在写上的原子操作,所以我们可以将TT用作计数器,他用作计数器,不会出现如MC一样的大并发下数据不准的情况。当然,因为加了锁,性能不会如MC那样牛X,比起用MC+MySQL进行定时校正的方案,在实现上简洁了很多,如何选择,可以根据实际情况来做。
完毕,欢迎交流指正!
标签:, ,