月度归档:2014年03月

redis集群的简单实现

集群的优点:

集中闲散的机器内存,
为redis的连接做代理,不再把庞大的前台调用并发压给redis本身。
连接性能的提高。

集群的解决方案:

利用nutcracker来实现,nutcracker是twitter开源的一个proxy,他可以用来解决memcache和redis的集群连接问题。

下载代码:

wget http://twemproxy.googlecode.com/files/nutcracker-0.2.4.tar.gz

安装到prefix目录,此例中prefix是 /data0/nutcracker024

拷贝源代码目录中得conf目录到/data0/nutcracker024

然后,建立一个配置文件[redis.yml]来实现redis的集群:

leaf:
  listen: 10.44.3.56:6379
  hash: fnv1a_64
  distribution: ketama
  auto_eject_hosts: false
  redis: true
  server_retry_timeout: 2000
  server_failure_limit: 1
  servers:
   - 10.73.12.22:6379:1
   - 10.73.12.23:6379:1

启动方式:

/data0/nutcracker024/sbin/nutcracker -c redis.yml -d

启动以后,这个端口对外透明,相当于一个简单的redis,只不过数据被分散到了几台服务器上。

配置选项说明:

listen
twemproxy监听的端口。可以以ip:port或name:port的形式来书写。

hash
可以选择的key值的hash算法:
> one_at_a_time
> md5
> crc16
> crc32 (crc32 implementation compatible with libmemcached)
> crc32a (correct crc32 implementation as per the spec)
> fnv1_64
> fnv1a_64
> fnv1_32
> fnv1a_32
> hsieh
> murmur
> jenkins

如果没选择,默认是fnv1a_64。

hash_tag
hash_tag允许根据key的一个部分来计算key的hash值。hash_tag由两个字符组成,一个是hash_tag的开始,另外一个是hash_tag的结束,在hash_tag的开始和结束之间,是将用于计算key的hash值的部分,计算的结果会用于选择服务器。

例如:如果hash_tag被定义为”{}”,那么key值为”user:{user1}:ids”和”user:{user1}:tweets”的hash值都是基于”user1”,最终会被映射到相同的服务器。而”user:user1:ids”将会使用整个key来计算hash,可能会被映射到不同的服务器。

distribution
存在ketama、modula和random3种可选的配置。其含义如下:

ketama
ketama一致性hash算法,会根据服务器构造出一个hash ring,并为ring上的节点分配hash范围。ketama的优势在于单个节点添加、删除之后,会最大程度上保持整个群集中缓存的key值可以被重用。

modula
modula非常简单,就是根据key值的hash值取模,根据取模的结果选择对应的服务器。

random
random是无论key值的hash是什么,都随机的选择一个服务器作为key值操作的目标。

timeout
单位是毫秒,是连接到server的超时值。默认是永久等待。

backlog
监听TCP 的backlog(连接等待队列)的长度,默认是512。

preconnect
是一个boolean值,指示twemproxy是否应该预连接pool中的server。默认是false。

redis
是一个boolean值,用来识别到服务器的通讯协议是redis还是memcached。默认是false。

server_connections
每个server可以被打开的连接数。默认,每个服务器开一个连接。

auto_eject_hosts
是一个boolean值,用于控制twemproxy是否应该根据server的连接状态重建群集。这个连接状态是由server_failure_limit 阀值来控制。
默认是false。

server_retry_timeout
单位是毫秒,控制服务器连接的时间间隔,在auto_eject_host被设置为true的时候产生作用。默认是30000 毫秒。

server_failure_limit
控制连接服务器的次数,在auto_eject_host被设置为true的时候产生作用。默认是2。

servers
一个pool中的服务器的地址、端口和权重的列表,包括一个可选的服务器的名字,如果提供服务器的名字,将会使用它决定server的次序,从而提供对应的一致性hash的hash ring。否则,将使用server被定义的次序

绑定hosts测试多点服务器状况


<?php
$url = 'http://iask.sina.com.cn/rank/';
$domain = 'iask.sina.com.cn';
$test_ips = array(
		'10.44.3.85'
		);
$current_ip;
if($_SERVER['USER'] != 'root'){
	echo "NEED TO BE ROOT\n";	
	exit();
}
foreach($test_ips as $ip){
	$current_ip = $ip;
	bind_host($domain, $ip);	
	$content = get_url($url);
	do_content($content);
}
bind_host($domain,false);
function do_content($content){
	echo $content;
}

function bind_host($domain, $ip = false){
	$host_file = '/etc/hosts' ;
	$fp = fopen($host_file,"r");
	$contents = '';
	while(!feof($fp)){
		$line = fgets($fp);	
		if(trim($line," \n\t\r") == ''){
			continue;
		} else {
			if($line[0] != '#'){
				$reg = '#(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+(\S+)\s*#';	
				preg_match($reg, $line, $match);
				list($line, $lip, $cdomain) = $match;
				if($cdomain == $domain){
					if(strpos($line,'#add_by_hostinfo') != 0){
						$line = '#' . $line;
					} else {
						$line = '';	
					}
				}
			}
		}
		$contents .= $line  ;
	}
	fclose($fp);
	if($ip !== false){
		$contents .= "\n" . $ip . ' '. $domain.  "    #add_by_hostinfo not to del me\n";
	}
	file_put_contents($host_file, $contents);
}

function get_url($url,$timeout = 1){
	$ch = curl_init($url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
	curl_setopt($ch,CURLOPT_TIMEOUT,$timeout);
	$content = curl_exec($ch);
	return $content;
}