redis之redis集群、持久化至mysql、与mysql数据同步

 五、redis集群

在做redis集群之前,我们先将之前的mysql和redis实例全部停掉。在redis源码包里有一个脚本可以自动帮我们创建集群:

redis之redis集群、持久化至mysql、与mysql数据同步_第1张图片

可以看README查看怎么创建集群:

 redis之redis集群、持久化至mysql、与mysql数据同步_第2张图片

start 开启六个实例:

redis之redis集群、持久化至mysql、与mysql数据同步_第3张图片

create 创建集群,三个master,三个slave:

redis之redis集群、持久化至mysql、与mysql数据同步_第4张图片

 -c 指定集群模式,-p指定端口:

 redis之redis集群、持久化至mysql、与mysql数据同步_第5张图片

 --cluster 操作集群,可以查看无中心化集群:

redis之redis集群、持久化至mysql、与mysql数据同步_第6张图片

Redis 集群的数据分片

Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念.

Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么:

  • 节点 A 包含 0 到 5500号哈希槽.
  • 节点 B 包含5501 到 11000 号哈希槽.
  • 节点 C 包含11001 到 16384号哈希槽.

这种结构很容易添加或者删除节点. 比如如果我想新添加个节点D, 我需要从节点 A, B, C中得部分槽到D上. 如果我想移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可. 由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态.

 我们先连接30001,设置一个key值,此值保存在5798这个哈希槽上,但这个哈希槽在节点B上,即30002端口上,所以我们再查看值就自动跳到了30002端口上,这就是无中心化的操作。但是在建立集群时要设置负载均衡,因为如果这16384个哈希槽有一个出了问题整个集群就不可用了,同时不需要做读写分离,因为每个结点都能读写。

我们停掉30002做测试:

redis之redis集群、持久化至mysql、与mysql数据同步_第7张图片

当30002挂掉时, 原来30002的slave30005自动变成了master,接管原来30002的哈希槽,自动做了主从的切换。此时我们再把30002启动起来(还是用脚本帮我们启动):

redis之redis集群、持久化至mysql、与mysql数据同步_第8张图片

 redis之redis集群、持久化至mysql、与mysql数据同步_第9张图片

 可以看到30002已经成了30005的slave。但是一对master和slave不能同时挂掉,同时挂掉集群就不能使用了。若是我们想再开几个节点,进入create-cluster脚本更改:

redis之redis集群、持久化至mysql、与mysql数据同步_第10张图片

此时再start又开了两个实例,但是这两个实例并不在集群中:

 redis之redis集群、持久化至mysql、与mysql数据同步_第11张图片

 使用add-node 添加到集群中去:

redis之redis集群、持久化至mysql、与mysql数据同步_第12张图片

此时查看30007是作为一个master加进去的。我们再把30008加进集群: redis之redis集群、持久化至mysql、与mysql数据同步_第13张图片

 但是此时30007上没有哈希槽,我们迁移一点哈希槽给30007,使用下面这条命令可以进行交互式操作:

redis之redis集群、持久化至mysql、与mysql数据同步_第14张图片

我们选择all就是均衡的从其他3个节点上移3000个哈希槽到30007上,也可以指定哪个哈希槽移出来3000个。 此时再查看节点发现30007上有3000个哈希槽了:
redis之redis集群、持久化至mysql、与mysql数据同步_第15张图片

 停止集群:

redis之redis集群、持久化至mysql、与mysql数据同步_第16张图片

六、redis持久化

Redis 提供了不同级别的持久化方式:

  • RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储.
  • AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.
  • 如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
  • 你也可以同时开启两种持久化方式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
  • 最重要的事情是了解RDB和AOF持久化方式的不同,让我们以RDB持久化方式开始:

RDB的优点

  • RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集.
  • RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3(可能加密),非常适用于灾难恢复.
  • RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能.
  • 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些.

RDB的缺点

  • 如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么RDB不适合你.虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据.
  • RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度.

AOF 优点

  • 使用AOF 会让你的Redis更加耐久: 你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync.使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,你最多丢失1秒的数据.
  • AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题.
  • Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。
  • AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。

AOF 缺点

  • 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
  • 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。
  • 如何选择使用哪种持久化方式?

一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。

如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。

有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快, 除此之外, 使用 RDB 还可以避免之前提到的 AOF 程序的 bug 。

Note: 因为以上提到的种种原因, 未来我们可能会将 AOF 和 RDB 整合成单个持久化模型。 (这是一个长期计划。) 接下来的几个小节将介绍 RDB 和 AOF 的更多细节。

参数设置:

redis持久化:

  • RDB 快照存储(默认)
  •  AOF 以追加的方式保存所有写操作
  • save 900 1    #当有一条Keys数据被改变时,900秒刷新到Disk一次
  • save 300 10   #当有10条Keys数据被改变时,300秒刷新到Disk一次
  • save 60 10000 #当有10000条Keys数据被改变时,60秒刷新到Disk一次
  • appendonly yes               #启用AOF持久化方式
  • appendfsync everysec        #每秒钟强制写入磁盘一次

redis和mysql数据同步,我们要做的是从redis里读数据,写数据往mysql数据库里写,当redis里没有的时候从数据库里加载

我们新开一个主机server4,并安装mariadb-server,作为数据库端:

redis之redis集群、持久化至mysql、与mysql数据同步_第17张图片

redis之redis集群、持久化至mysql、与mysql数据同步_第18张图片

server3上我们没有做过lnmp架构的编译,所以我们在server3上重新做一个带有redis模块的lnmp架构:

 redis之redis集群、持久化至mysql、与mysql数据同步_第19张图片

 redis之redis集群、持久化至mysql、与mysql数据同步_第20张图片

redis之redis集群、持久化至mysql、与mysql数据同步_第21张图片

 redis之redis集群、持久化至mysql、与mysql数据同步_第22张图片

 redis之redis集群、持久化至mysql、与mysql数据同步_第23张图片

 

 

redis之redis集群、持久化至mysql、与mysql数据同步_第24张图片

 redis之redis集群、持久化至mysql、与mysql数据同步_第25张图片

redis之redis集群、持久化至mysql、与mysql数据同步_第26张图片

以下就是 /etc/local/nginx/html 中的test.php:

connect('172.25.254.2',6379) or die ("could net connect redis server");
  #      $query = "select * from test limit 9";
        $query = "select * from test";
        for ($key = 1; $key < 10; $key++)
        {
                if (!$redis->get($key))
                {
                        $connect = mysql_connect('172.25.254.4','redis','westos');
                        mysql_select_db(test);
                        $result = mysql_query($query);
                        //如果没有找到$key,就将该查询sql的结果缓存到redis
                        while ($row = mysql_fetch_assoc($result))
                        {
                                $redis->set($row['id'],$row['name']);
                        }
                        $myserver = 'mysql';
                        break;
                }
                else
                {
                        $myserver = "redis";
                        $data[$key] = $redis->get($key);
                }
        }

        echo $myserver;
        echo "
"; for ($key = 1; $key < 10; $key++) { echo "number is $key"; echo "
"; echo "name is $data[$key]"; echo "
"; } ?>

在server4上通过test.sql导入数据库,以下是test.sql中的内容:

use test;
CREATE TABLE `test` (`id` int(7) NOT NULL AUTO_INCREMENT, `name` char(8) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test` VALUES (1,'test1'),(2,'test2'),(3,'test3'),(4,'test4'),(5,'test5'),(6,'test6'),(7,'test7'),(8,'test8'),(9,'test9');

#DELIMITER $$
#CREATE TRIGGER datatoredis AFTER UPDATE ON test FOR EACH ROW BEGIN
#    SET @RECV=gman_do_background('syncToRedis', json_object(NEW.id as `id`, NEW.name as `name`));
#  END$$
#DELIMITER ;
~              

redis之redis集群、持久化至mysql、与mysql数据同步_第27张图片
在server4数据库上建立用户并授权:

在浏览器上访问:

redis之redis集群、持久化至mysql、与mysql数据同步_第28张图片

 在server2redis服务器上访问:

redis之redis集群、持久化至mysql、与mysql数据同步_第29张图片

测试: 

在srever4数据库上修改:

redis之redis集群、持久化至mysql、与mysql数据同步_第30张图片

但是redis上还是test1:

redis之redis集群、持久化至mysql、与mysql数据同步_第31张图片

 在浏览器端先访问redis,如果redis里有他就不会访问后端mysql,所以1还是test1:

redis之redis集群、持久化至mysql、与mysql数据同步_第32张图片

若是我们删除redis中的数据,从浏览器访问时,如果redis里面没有,就会从后台mysql里面读取。

redis之redis集群、持久化至mysql、与mysql数据同步_第33张图片

redis之redis集群、持久化至mysql、与mysql数据同步_第34张图片

 此时我们已经完成了redis作为mysql的缓冲,但是redis数据无法和mysql同步是我们接下来要解决的。

gearmand简介

Gearmand 是一个用来把工作委派给其它机器、分布式的调用更适合做某项工作的机器、并发的做某项工作在多个调用间做负载均衡、或用来调用其它语言的函数的系统。

简单来讲,就是客户端程序把请求提交给 gearmand,gearmand 会把请求转发给合适的 worker 来处理这个请求,最后还通过 gearmand 返回结果。

运行流程:

Client --> Job --> Worker

1、Client 请求发起者,客户端程序可以是任何一种语言,C 、PHP 、Perl 、Python 等。
2、Job 请求调度者,负载协调把 Client 发出的请求转发给合适的 Worker。
3、Worker 请求处理者,处理 Job 分发来的请求,可以是任何一种语言。

首先我们要给数据库安装额外的两个函数:

redis之redis集群、持久化至mysql、与mysql数据同步_第35张图片

redis之redis集群、持久化至mysql、与mysql数据同步_第36张图片

查看mysql插件所在目录:

 redis之redis集群、持久化至mysql、与mysql数据同步_第37张图片

 redis之redis集群、持久化至mysql、与mysql数据同步_第38张图片

通过刚刚拷贝的模块注册UDF函数: 

查看自定义函数:

 redis之redis集群、持久化至mysql、与mysql数据同步_第39张图片

第二个插件:
 

安装依赖性: 

编译: 

redis之redis集群、持久化至mysql、与mysql数据同步_第40张图片

使用gearman在redis和mysql之间做一个截藕,使之在数据量庞大时也不会出问题。 

再创建两个自定义函数:

redis之redis集群、持久化至mysql、与mysql数据同步_第41张图片

 redis之redis集群、持久化至mysql、与mysql数据同步_第42张图片

 在lnmp架构服务器server3上安装gearmand客户端:

redis之redis集群、持久化至mysql、与mysql数据同步_第43张图片

gearmand 监听本机的4730端口:

redis之redis集群、持久化至mysql、与mysql数据同步_第44张图片

在server4 数据库端告知gearmand的客户端在哪:

 redis之redis集群、持久化至mysql、与mysql数据同步_第45张图片

修改test.sql ,加上触发器:

将原来的test删除:

redis之redis集群、持久化至mysql、与mysql数据同步_第46张图片

触发器添加成功:

redis之redis集群、持久化至mysql、与mysql数据同步_第47张图片

在server3 gearmand调度端编辑一个worker.php:

 redis之redis集群、持久化至mysql、与mysql数据同步_第48张图片

 由于上面的php代码中还用到了gearmand模块,所以还要给php添加gearmand模块:

redis之redis集群、持久化至mysql、与mysql数据同步_第49张图片

平滑加载php设置:

php执行worker.php 并打入后台:

测试: 

 此时我们在mysql上更改数据:

redis之redis集群、持久化至mysql、与mysql数据同步_第50张图片

然后直接去redis中查看数据:

redis之redis集群、持久化至mysql、与mysql数据同步_第51张图片

此时redis中的数据已经变更了。在网页端查看也是直接变更:

redis之redis集群、持久化至mysql、与mysql数据同步_第52张图片

 此时我们就已经完成了redis以异步方式同步mysql中的数据。只要application将数据写到mysql中,mysql触发器检测到更新,就会通过Gearman将数据同步到redis中。然后读取的话,就直接从redis中进行读取。

你可能感兴趣的:(大数据,redis,缓存)