redis集群搭建以及Yii1.1连接redis集群
来源:互联网 发布:金针软件 编辑:程序博客网 时间:2024/05/19 19:30
本来博客搭建在自己的服务器上,不知道多久没有维护和更新后,再一看域名都需要重新备案了。介于本人的“懒惰性”,还是迁过来不浪费资源了。
最近搭建一个业务,号称每秒响应需要1W次请求,然后LZ各种折腾php、mysql和nginx配置。最后放弃mysql使用redis单机版,最后的最后使用redis集群。
1、生产环境
ubuntu16.04
redis-3.0.7
内网机器IP:192.168.140.180和192.168.140.181
机器CPU:4核
2、搭建
LZ在搭建集群前是使用的redis单机版,而单机版的启动直接使用redis.server /etc/redis/redis.conf的,也就是说完全没有理解redis的单核运行原理 【手动滑稽,LZ是个菜】,还是记录一下redis的单线程:
redis是用"单线程-多路复用io模型"来实现高性能的内存数据服务的,这种机制避免了使用锁,但是同时这种机制在进行sunion之类的比较耗时的命令时会使redis的并发下降。因为是单一线程,所以同一时刻只有一个操作在进行,所以,耗时的命令会导致并发的下降,不只是读并发,写并发也会下降。而单一线程也只能用到一个cpu核心。
然后LZ的业务负载机器上面还跑着redis的实例,最后造成了这种情况:
简直不要太开心,8核机器redis用了50%的CPU??? WTF???当时LZ的内心是崩溃的。所以查找了相当的redis集群资料开始搭建过程。
2.1.1 下载和安装redis源码
cd /data/baowget "http://download.redis.io/releases/redis-3.0.7.tar.gz"tar -zxvf redis-3.0.7.tar.gz、
然后进入到安装目录
cd redis-3.0.7make test
ubuntu 下会报错:
You need tcl 8.5 or newer in order to run the Redis test
然后我们需要一下操作:
wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gzsudo tar xzvf tcl8.6.1-src.tar.gz -C /usr/local/cd /usr/local/tcl8.6.1/unix/sudo ./configuresudo makesudo make install
再返回进入到redis目录下
cd /data/bao/redis-3.0.7 && make && make install
OK,搭建了六套相关环境暂时还没有出现过其他问题.现在源码安装好了redis,redis的启动和cli是和系统同样的,也就是
cd /data/bao/redis-3.0.7/src下有 redis-server 和 redis-cli 文件。./redis-cli 就可以使用连接了。
2.1.2 搭建redis集群
OK,两台机器做同样的命令:
用端口为名称建立redis集群的配置,LZ搭建4主4从,所以启用四个端口
mkdir -p /data/redis/7000mkdir -p /data/redis/7001mkdir -p /data/redis/7002mkdir -p /data/redis/7003
将编译好的redis-server移过来,只是为了启动方便
cp /data/bao/redis-3.0.7/src/redis-server /data/redis
编写相对简答的redis.conf文件
vi /data/redis/redis.con
port 7000 #运行端口,和你将要放入的文件夹名称对应cluster-enabled yes cluster-config-file nodes.conf #节点配置信息cluster-node-timeout 5000 #超时appendonly no daemonize yes #后台运行
储存后将这个文件复制到各个以端口命名的文件夹内,并将port修改为文件夹名称存储.
完成之后启用redis-cluster,LZ比较懒,写了个脚本启动。
cd /data/redis/7000/ && taskset -c 0 /data/redis/redis-server /data/redis/7000/redis.confcd /data/redis/7001/ && taskset -c 1 /data/redis/redis-server /data/redis/7001/redis.confcd /data/redis/7002/ && taskset -c 2 /data/redis/redis-server /data/redis/7002/redis.confcd /data/redis/7003/ && taskset -c 3 /data/redis/redis-server /data/redis/7003/redis.conf
这里的taskset -c 0 是指定redis运行在某个cpu上,cpu的个数从0开始往上计算,如LZ的机器是4核,所以开了4个端口使用4个CPU来运行cluster。这种方式比较极限,机器上也不敢运行太多其它东西了。
2.1.3 使用ruby管理redis集群
安装ruby redis插件,听说编写redis的人本身是写ruby的,所以又用ruby编写了一套管理脚本,保证redis的代码清洁,也为后来埋下了坑-。-
apt updateapt install rubygem install redis
cd /data/bao/redis-3.0.7/src
redis-trib.rb create --replicas 1 192.168.140.180:7000 192.168.140.180:7001 192.168.140.180:7002 192.168.140.180:7003 192.168.140.180:7000 192.168.140.181:7000 192.168.140.181:7001 192.168.140.181:7002 192.168.140.181:7003
redis-trib.rb 针对集群的运用:
1、create:创建集群
2、check:检查集群
3、info:查看集群信息
4、fix:修复集群
5、reshard:在线迁移slot
6、rebalance:平衡集群节点slot数量
7、add-node:将新节点加入集群
8、del-node:从集群中删除节点
9、set-timeout:设置集群节点间心跳连接的超时时间
10、call:在集群全部节点上执行命令
11、import:将外部redis数据导入集群
create --replicas 第一个参数1 是指每个master节点将有1个子节点
OK,运行完毕不出意外的话全部都是success,有错误的话问问度娘, ubuntu16下LZ暂时没有出现很难解的错误。
3.1.1 链接redis集群并测试
进入集群池命令:
redis-cli -p 7000 -c
具体set/get的测试就不列举了,蛋疼-。- 但在get的时候或许你会发现下面情况:(error) MOVED 1409 192.168.140.180:7000 ,这个也不是错误,是redis的集群机制。redis的各个master之间是互不干涉的,只是在存储的时候存储池给每个master分配了一些槽和数据。而你在某个节点get命令的时候,redis会先计算这个值存在的哈希,计算出他的存储节点,若不在这台机器上则报上方信息并告知你正确的节点。这样redis就有了两次I/O开销。额,还没到这一层面还是安静的看大神分析吧。
redis cluster浅析和Bada对比 原文
最后LZ测试运行后的结果,跑业务的时候最高占用也仅在20%,和之前可怕的单核形成强烈的对比。。。
4.1.1 yii1.1 连接集群
楼主使用的是yiiredis拓展,github地址:https://github.com/phpnode/YiiRedis
然而,这个拓展没有cluster的链接【微笑】
没办法,山寨的楼主只能用phpredis来写个简单的拓展放里边。。。
<?php/** * Created by PhpStorm. * User: land.zhang * Date: 2017/8/3 * Time: 16:55 */class RedisClusterConnection extends CApplicationComponent{ /** * The redis client * @var RedisCluster */ protected $_client; /** * The redis unix socket location * @var unixSocket */ public $unixSocket=null; /** * Redis default prefix * @var string */ public $prefix = "Yii.redis."; /** * The redis server password * @var password */ public $password=null; /** * The redis socket timeout, defaults to 0 (unlimited) * @var timeout */ public $timeout=0; /** * The redis cluster * @var array */ public $clusterConfig=[]; /** * Sets the redis client to use with this connection * @param RedisCluster $client the redis client instance */ public function setClient(RedisCluster $client) { $this->_client = $client; } /** * Gets the redis client * @return RedisCluster the redis client */ public function getClient($reconnect = false) { if ($this->_client === null || $reconnect) { if(empty($this->clusterConfig)){ throw new CException('Redis Cluster Config Error'); } $clusterList = []; foreach ($this->clusterConfig as $item){ $clusterList[] = $item['host'] . ':' . $item['port']; } if(empty($clusterList)){ throw new CException('Redis Cluster Config Error'); } $this->_client = new RedisCluster(null,$clusterList);// $this->_client->connect($this->hostname, $this->port, $this->timeout); //phpredis not support password yet// if (isset($this->password)) {// if ($this->_client->auth($this->password) === false) {// throw new CException('Redis authentication failed!');// }// }// $this->_client->setOption(Redis::OPT_PREFIX, $this->prefix);// $this->_client->select($this->database); } return $this->_client; } /** * Returns a property value based on its name. * Do not call this method. This is a PHP magic method that we override * to allow using the following syntax to read a property * <pre> * $value=$component->propertyName; * </pre> * @param string $name the property name * @return mixed the property value * @throws CException if the property is not defined * @see __set */ public function __get($name) { $getter='get'.$name; if (property_exists($this->getClient(),$name)) { return $this->getClient()->{$name}; } elseif(method_exists($this->getClient(),$getter)) { return $this->$getter(); } return parent::__get($name); } /** * Sets value of a component property. * Do not call this method. This is a PHP magic method that we override * to allow using the following syntax to set a property * <pre> * $this->propertyName=$value; * </pre> * @param string $name the property name * @param mixed $value the property value * @return mixed * @throws CException if the property is not defined or the property is read only. * @see __get */ public function __set($name,$value) { $setter='set'.$name; if (property_exists($this->getClient(),$name)) { return $this->getClient()->{$name} = $value; } elseif(method_exists($this->getClient(),$setter)) { return $this->getClient()->{$setter}($value); } return parent::__set($name,$value); } /** * Checks if a property value is null. * Do not call this method. This is a PHP magic method that we override * to allow using isset() to detect if a component property is set or not. * @param string $name the property name * @return boolean */ public function __isset($name) { $getter='get'.$name; if (property_exists($this->getClient(),$name)) { return true; } elseif (method_exists($this->getClient(),$getter)) { return true; } return parent::__isset($name); } /** * Sets a component property to be null. * Do not call this method. This is a PHP magic method that we override * to allow using unset() to set a component property to be null. * @param string $name the property name or the event name * @throws CException if the property is read only. * @return mixed */ public function __unset($name) { $setter='set'.$name; if (property_exists($this->getClient(),$name)) { $this->getClient()->{$name} = null; } elseif(method_exists($this,$setter)) { $this->$setter(null); } else { parent::__unset($name); } } /** * Calls a method on the redis client with the given name. * Do not call this method. This is a PHP magic method that we override to * allow a facade in front of the redis object. * @param string $name the name of the method to call * @param array $parameters the parameters to pass to the method * @return mixed the response from the redis client */ public function __call($name, $parameters) { return call_user_func_array(array($this->getClient(),$name),$parameters); }}
然后在配置里边加上如下代码
'clusterConfig' => [ [ 'host' => '192.168.140.180', 'port' => 7000, ], [ 'host' => '192.168.140.180', 'port' => 7001, ], [ 'host' => '192.168.140.181', 'port' => 7000, ], [ 'host' => '192.168.140.181', 'port' => 7001, ], ],
嗯,然后你就能在代码里边欢快的set和get: Yii:app->clusterConfig->get() 。
由于是基于phpredis拓展的,所以需要在ubuntu上为php装上拓展别忘了亲。。。拓展的安装在楼主的另外一篇文章 搭建nginx+php+mysql脚本。
- redis集群搭建以及Yii1.1连接redis集群
- Redis 集群搭建与连接
- Redis集群搭建1
- Redis集群搭建方法以及脚本搭建
- Redis集群搭建(1)
- Redis 3.2.1集群搭建
- Redis 3.2.1集群搭建
- Redis 3.2.1集群搭建
- Redis 4.0.1集群搭建
- redis集群搭建以及和spring整合
- Redis集群搭建以及Spring整合
- Redis cluster 集群搭建以及API访问
- 如何搭建Redis集群与Jedis连接集群
- redis集群搭建
- redis集群环境搭建
- redis-3.0集群搭建
- redis集群部署搭建
- redis集群环境搭建
- linux操作系统安装润乾报表5.0
- spark ha集群配置
- python 引用和对象理解
- 如何编写对拍程序?
- Android中PopupWindow 在 Android N(7.0) 的兼容性问题
- redis集群搭建以及Yii1.1连接redis集群
- ffmpeg基本
- SSH框架搭建
- go get安装第三方包的前提条件和步骤
- JS的各种注意点
- 背景图片全部全景展示
- DataFrame删除特定列
- Mybatis---查询使用resultType和resultMap的区别
- 欢迎使用CSDN-markdown编辑器