跨IDC ycache原理和配置说明

总体介绍:


  多idc缓存方案的invalid方案(如下图),是通过两个操作保证多个idc之间的缓存的高可用性和最终一致性的。

  1. 更新数据库后,发送invalid消息;invalid消息广播到其他idc后,立即删除所在idc缓存中的对应key;单凭这个操作,在使用一个数据库的场景,已经能保证缓存一致性了;在使用主、备数据库的场景,如果主备库的同步非常快,也能保证很大概率的缓存一致性;
  2. invalid消息会在每个idc的缓存中设置一个mark,用来标志这个key已经被其他人更新了,并且设置一个TTL指示在某个时间内它可能是旧值。这个key的所有更新操作(比如set)使用的ttl都会被marker指定的TTL覆盖;这就保证了在TTL之后,改key值会被更新一次。如果TTL设置合理(总是大于数据库之间的同步延时),就能达到最终一致性。

为什么用twemproxy做代理?

  1. 屏蔽其他idc内部缓存的细节。ycache-client只要往本idc的twemproxy发送invalid消息,而无需关注其他idc内有多少缓存,不用关注他们的部署结构、不需要关心他们是不是变化了;
  2. 减少idc之间的tcp连接,从而降低延时,避免网络故障时的重传风暴。由于所有跨idc连接都是由twemproxy连接(通过tcp常链接)的,发送时无需再进行tcp链接建立;而且,网络故障时,也仅需要重建twemproxy之间的连接,不需要idc之间数量巨大的ycache-client之间重传。

client端:



原理:app在更新数据库后(或者其他需要更新缓存的操作),调用IDCMemcacheProxyFactory工厂类获取一个实例,通过这个实例发送一个invalid消息。 这个invalid消息会在内部处理中通过twemproxy广播给所有的idc。

app需要初始化的,与以前的相比,使用IDCMemcacheProxyFactory代替以前的

YmemcacheProxyFactory;使用IDCProxy发送invalid消息,而其他的消息还是通过CacheProxy接口;

内部实现:

除了根据app指定的配置文件路径配置它的cache-pool外,还额外做如下的初始化(把本所有远端idc的2个twemproxy端口当作一个cache-pool始化(从zk上读取twemproxy的ip和端口):



    public class IDCMemcacheProxyFactory extends YmemcacheProxyFactory {

/**

* 初始化 IDC cache 和 twemproxy 的连接

* @throws MemcacheInitException

*/

public void reInitIDCYCache() throws MemcacheInitException {

//从ycc 获取各个IDC的对应到本idc的twemproxy pool名称,本地广播消息

String properties = YccGlobalPropertyConfigurer.loadConfigString(IDCConstants.IDCPoolName, IDCConstants.idc_common);

Hashtable<String, String> pro = YccGlobalPropertyConfigurer.loadProperties(properties);

String idc_ycache_poolName_list = pro.get(IDCConstants.IDCCacheIdList);

if (idc_ycache_poolName_list == null || idc_ycache_poolName_list.trim().length() == 0) {

logger.error(IDCConstants.idc_common + " 文件缺少值" + IDCConstants.IDCCacheIdList);

}

String[] poolNames =  IDCCommandUtil.getOtherIDCPoolNames();

if(poolNames  == null ){

poolNames = idc_ycache_poolName_list.split(",");

IDCCommandUtil.setOtherIDCPoolNames(poolNames);

}else{

for (String poolName : poolNames) {

//先关闭原来的连接

SockIOPool pool = SockIOPool.getInstance(poolName);

if (pool != null && pool.isInitialized()) {

pool.shutDown();

}

}

}

//init idc ycache ,全局只需要增加一次

File loadConfigFile = YccGlobalPropertyConfigurer.loadConfigFile(IDCConstants.IDCPoolName, IDCConstants.idc_ycache_memcache);

super.add("file:" + loadConfigFile.getAbsolutePath());

}

public class IDCConstants {

public static final String IDCPoolName = "yihaodian/common";//poolid

public static final String idc_ycache_redis = "idc_ycache_redis.xml";// dataid

public static final String idc_ycache_memcache = "idc_ycache_memcache.xml";

public static final String idc_common = "idc_common.properties";

public static final String IDCCacheIdList = "idc_ycache_poolName_list";//idc_ycache_redis.xml  idc_ycache_memcache.xml 中配置的 id

。。。

}


 所以,在调用invalid的时候,实际上是遍历这些代表各个idc的cache-pool发送一个invalid消息;这些cache-pool的配置信息是在IDCPoolName = "yihaodian/common"、idc_ycache_memcache = "idc_ycache_memcache.xml"这连个变量指定的配置中心的配置。(多个idc公用这个配置文件,通过pool id属性扩展为多个)。

注意,由于所有poolname的ycache-client实例都会连接到twenproxy,数量非常大。所以这个配置文件的mincon必须很小,否则会导致twemproxy的连接数很高。因为invalid消息不多,建议1个就够了

而要发送给几个idc,是在 IDCPoolName = "yihaodian/common"、idc_common = "idc_common.properties"这里指定的:

ycache-server端:


原理:server端事实上是起一个消息分发器的作用。一个idc内有很多的ycache-server,他们都配置在twemproxy的一个服务组内。twemproxy将一个invalid消息随机(算法可配置)分发给一个ycache-server;ycache-server会根据消息内部的poolname,发送一个delete key和add ttl-key的命令到这个poolname的memcached。 所以ycache-server实际上支持所有poolname的cache-client实例。

内部实现: 配置文件的读取是通过spring框架的配置文件初始化的。所有的poolname使用同一个"memcacheConfigureTemplatePath"=yihaodian/common : yihaodian_ycache-server/idc_ycache_memcache_server_template.xml指定的配置文件模板,每次初始化一个poolname的clien实例时,更改一下配置文件的pool id属性即可;而poolname的memcached的ip和端口号从zk读取。

注意,ycache-server要连接所有poolname的memcache实例,数量非常大。所以这个配置文件的mincon必须很小。因为invalid消息不多,建议1个就够了。

public class CacheServiceImpl implements CacheService {

public void init() throws Exception {

logger.info("start init all cache");

CacheAdmin.getInstance().reInitAll(zkServers, this.memcacheConfigureTemplatePath, this.redisConfigureTemplatePath, initAllCache);

logger.info("finish init all cache");

}

/ycache-server/src/main/resources/applicationContext.xml

<bean id="yccPropertyConfigurer_common"

class="com.yihaodian.configcentre.client.utils.YccGlobalPropertyConfigurer">

<property name="locations">

<list>

<value>zookeeper-ycache.properties</value>

<value>idc_common.properties</value>

<value>yihaodian_ycache-server/idc_ycache_memcache_server_template.xml</value>

<value>yihaodian_ycache-server/idc_ycache_redis_server_template.xml</value>

</list>

</property>

<property name="poolId">

<value>yihaodian/common</value>

</property>

<property name="ignoreUnresolvablePlaceholders" value="true" />

</bean>

<bean id="nettyService" class="com.yhd.ycache.service.NettyServiceImpl" init-method="init"  destroy-method="destroy">

<property name="port" value="${ycache-server-port}"/>

</bean>

<bean id="cacheService" class="com.yhd.ycache.service.CacheServiceImpl" init-method="init"  destroy-method="destroy">

<!-- 值来自zookeeper-ycache.properties-->

<property name="memcacheConfigureTemplatePath" value="file:${global.config.path}/ycc/snapshot/yihaodian_ycache-server/idc_ycache_memcache_server_template.xml"/>

<property name="redisConfigureTemplatePath" value="file:${global.config.path}/ycc/snapshot/yihaodian_ycache-server/idc_ycache_redis_server_template.xml"/>

<property name="zkServers" value="${zk-servers}"/>

<property name="initAllCache" value="false"/>

</bean>

<bean id="exampleService" class="com.yhd.ycache.service.ExampleServiceImpl"></bean>

twemproxy:


twemproxy在整个组网中起桥接各个idc的作用。每个twemproxy都连接其他idc的twemproxy,任何ycache-client需要跨idc的通信都是通过twemproxy完成。也就是任何ycache-client都不应该看到非本idc的cache的存在。每个idc的twemproxy为本idc的ycache-client开启代表其他idc的端口(每个端口代表一个idc),所以ycache-client需要给其他idc的cache发送消息时,就往本idc的twemproxy的这些端口通信。

同时,从ycache-client的视角,twemproxy其实相当于cache实例。每个idc有两个twemproxy(相互备份和负载分担),它们像cache一样被分配在一个pool-id内,写到zookeeper的‘/ycache/pools/‘路径下。所以本idc的ycache以为自己连接的是cache。

From WizNote

时间: 2024-10-19 15:46:07

跨IDC ycache原理和配置说明的相关文章

JSONP跨域的原理解析

JSONP跨域的原理解析 一种脚本注入行为 在 2011年10月27日 那天写的     已经有 99238 次阅读了 感谢 参考或原文 JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为"Same-Origin Policy"(同源策略).这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容. JavaScript这个安全策略在进

js中几种实用的跨域方法原理详解(转)

今天研究js跨域问题的时候发现一篇好博,非常详细地讲解了js几种跨域方法的原理,特分享一下. 原博地址:http://www.cnblogs.com/2050/p/3191744.html 下面正文开始 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被当作是不同的域. 下表给出了相对http://store.company.com/dir/pag

atitit. hb 原生sql跨数据库解决原理 获得hb 数据库类型运行期获得Dialect

#-----原理 Hibernate 运行期获得Dialect 2010-07-28 12:59:58|  分类: 软件开发 |举报 |字号 订阅 String dialect = ((SessionFactoryImpl) session.getSessionFactory()).getDialect() .getClass().getName(); //     //org.hibernate.dialect.MySQLDialect 如果是spring + hibernate则可以: St

前端跨域请求原理及实践

前端跨域请求原理及实践 2017-03-03 前端大全 (点击上方公众号,可快速关注) 作者:高鹏 tingandpeng.com/2016/09/05/前端跨域请求原理及实践/ 如有好文章投稿,请点击 → 这里了解详情 一. 跨域请求的含义 浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如 JavaScript)对不同域的服务进行跨站调用. 一般的,只要网站的 协议名protocol. 主机host. 端口号port 这三个中的任意一个不同,网站间的数据请求与传输便构成了跨域调用.

js中几种实用的跨域方法原理详解

这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被当作是不同的域. 下表给出了相对http://store.company.com/dir/page.html同源检测的结果: 要解决跨域的问题,我们可以使用以下几种方法: 一.通过jsonp跨域 在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的.但是,在页面上引入不同

【转】JSONP跨域的原理解析

JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略).这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容. JavaScript这个安全策略在进行多iframe或多窗口编程.以及Ajax编程时显得尤为重要.根据这个策略,在baidu.com下的页面中包含的JavaScript代码,不能访问在

jsonp跨域的原理

1. 前言 jsonp是一种常用的跨域手段,和反向代理,服务端做跨域处理相比,jsonp更显得方便轻巧,因而被大量用来处理跨域的请求,那么,这种请求方式到底是用了什么黑魔法,来解决令我们头疼的跨域问题. 2. 原理 jsonp其实并没有用到什么黑魔法,能达到跨域这种效果,无非是利用script标签自身的跨域能力.我们知道,img,script,这种标签如果有相应的src,那么便会发起一个htttp请求来请求相应的资源,如果有script标签对应的路径是一个js文件,那么在下载完毕这个js之后会马

JSONP跨域的原理解析及其实现介绍

JSONP 即 Json padding ,JSONP跨域GET请求是一个常用的解决方案,下面我们来看一下JSONP跨域是如何实现的,并且探讨下JSONP跨域的原理 JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为“Same- Origin Policy”(同源策略).这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档 在同一域下的内容. JavaScr

几句话说说跨IDC分布式数据库Calvin

CalvinFS拿了FAST 15最佳论文:找到了失联十三年的小伙伴:年终/年初整理资料,发现做团委工作的 King 师兄对Calvin有兴趣:最近其他团队对分布式事务和存储问题/兴趣较多……几件事激发了我写这本文的动机,要知道上一篇是2012年的(虽然一直有做个人学习.工作笔记). Yale的CalvinFS最有价值的就是元数据管理部分,也就是Calvin(的修改版).没有跨IDC的Calvin,也就没有跨IDC的CalvinFS.以下的内容以旁观者角度写,一些问题简单描述,但是实际上非常难处