一、介绍
中文官网 Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
1.redis与memcache
(1) redis可以用来做存储(storge)、而memcache是来做缓存(cache)。这个特点主要是因为其有“持久化”功能
(2)存储的数据有“结构”,对于memcache来说,存储的数据,只有一种类型—>“字符串”,而redis则可以存储字符串、链表、集合、有序集合、哈序结构
2.
二、安装
2.1 redis 各版本下载地址
2.2 下载、解压并安装redis
[root@server1 ~]# tar zxf redis-5.0.8.tar.gz
[root@server1 ~]# cd redis-5.0.8
[root@server1 redis-5.0.8]# make && make install
make 过程中可能会有依赖性问题,根据报错解决即可
gcc-c++ jemalloc-3.6.0-1.el6.x86_64.rpm jemalloc-devel-3.6.0-1.el6.x86_64.rpm
找到对应的包下载即可,如果解决了依赖性仍然报错的话,请删除重新解压再进行make
[root@server1 redis-5.0.8]# cd utils/
[root@server1 utils]# ./install_server.sh
##自动生成配置文件等信息,全部回车即可
从上图中可以看出redis的配置文件
[root@server1 redis-5.0.8]# vim /etc/redis/6379.conf
修改主配置文件,默认在/etc/redis/6379.conf 修改, 修改监听接口为0.0.0.0
重启服务,配置信息生效
[root@server1 redis-5.0.8]# /etc/init.d/redis_6379 restart
查询端口是否打开
[root@server1 redis-5.0.8]# netstat -antlp | grep 6379
三、redis常用指令:
config get * | //查看配置 |
select 1 | //选择数据库 |
flushdb | //清空当前数据库 |
flushall | //清空所有数据库 |
move key 1 | //移动key |
del key | //删除 |
rename oldkey newkey | //改名 |
expire key 10 | //设置过期时间 |
persist key | //设置持久化 |
keys user* | //查询 |
exists key | //判断是否存在 |
redis-cli 是Redis命令行界面,这是一个简单的程序,它允许直接从终端向Redis发送命令并读取服务器发送的回复。
默认情况下redis-cli,该服务器通过127.0.0.1端口6379连接到服务器。您可以猜测,可以使用命令行选项轻松更改此设置。要指定其他主机名或IP地址,请使用-h。为了设置其他端口,请使用-p。交互式
[root@server1 ~]# redis-cli
四、redis 的主从复制
Redis使用默认的异步复制,其特点是低延迟和高性能,是绝大多数 Redis 用例的自然复制模式。但是,从 Redis 服务器会异步地确认其从主 Redis 服务器周期接收到的数据量。
Redis 使用异步复制,slave 和 master 之间异步地确认处理的数据量,一个 master 可以拥有多个 slave
再重新配置一个redis服务,方法同上
[root@server2 utils]# vim /etc/redis/6379.conf
这里只需在配置文件最后加上
slaveof 172.25.1.1 6379
min-slaves-to-write <slave 数量> 这两行可以不加入
min-slaves-max-lag <秒数>
Redis 使用异步复制,因此无法确保 slave 是否实际接收到给定的写命令
[root@server2 utils]# /etc/init.d/redis_6379 restart
[root@server1 utils]# redis-cli
127.0.0.1:6379> info
[root@server2 utils]# redis-cli
127.0.0.1:6379> info
测试
我们可以看出在server1中输入的键值在server2中可以get到,所以实现主从关系
五、redis 的高可用
1.介绍
Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:
监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
2.配置Sentinel
开启第三台虚拟机server3,同样的方法进行redis配置
其中server1作为master server2和server3作为slave;
[root@server1 redis-5.0.8]# vim sentinel.conf
第一行配置指示 Sentinel 去监视一个名为 mymaster 的主服务器, 这个主服务器的 IP 地址为 172.25.1.1, 端口号为 6379 , 而将这个主服务器判断为失效至少需要 2 个 Sentinel 同意 (只要同意 Sentinel 的数量不达标,自动故障迁移就不会执行)。
指定当主服务器掉线10秒就会被认定为服务失效
将这个sentinel 配置传给2和3放到/etc/redis下 用于sentinel监控
[root@server1 redis-5.0.8]# cp sentinel.conf /etc/redis/
[root@server1 redis]# scp sentinel.conf server2:/etc/redis/
[root@server1 redis]# scp sentinel.conf server3:/etc/redis/
3.启动 Sentinel
对于 redis-sentinel 程序, 你可以用以下命令来启动 Sentinel 系统:
对于 redis-server 程序, 你可以用以下命令来启动一个运行在 Sentinel 模式下的 Redis 服务器:
在三台机子上都执行以下命令来启动sentinel服务,查看效果
redis-sentinel /etc/redis/sentinel.conf ##保持这个页面不能推出,可以远程连接到serve1上查看
[root@server1 ~]# redis-cli
127.0.0.1:6379> SHUTDOWN
这是我们查看info,master已经是server2了,并且当原来的master.server1开启之后也不会再跳回去,server1自动变成slave
4.主观下线和客观下线
主观下线(Subjectively Down, 简称 SDOWN)指的是单个 Sentinel 实例对服务器做出的下线判断。
客观下线(Objectively Down, 简称 ODOWN)指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断。 (一个 Sentinel 可以通过向另一个 Sentinel 发送 SENTINEL is-master-down-by-addr 命令来询问对方是否认为给定的服务器已下线。)
如果一个服务器没有在 master-down-after-milliseconds 选项所指定的时间内, 对向它发送 PING 命令的 Sentinel 返回一个有效回复(valid reply), 那么 Sentinel 就会将这个服务器标记为主观下线。
服务器对 PING 命令的有效回复可以是以下三种回复的其中一种:
返回 +PONG 。
返回 -LOADING 错误。
返回 -MASTERDOWN 错误。
客观下线条件只适用于主服务器: 对于任何其他类型的 Redis 实例, Sentinel 在将它们判断为下线前不需要进行协商, 所以从服务器或者其他 Sentinel 永远不会达到客观下线条件。
只要一个 Sentinel 发现某个主服务器进入了客观下线状态, 这个 Sentinel 就可能会被其他 Sentinel 推选出, 并对失效的主服务器执行自动故障迁移操作。
六、redis集群
1.Redis集群介绍
Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。
Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误.
Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令. Redis 集群的优势:
- 自动分割数据到不同的节点上。
- 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。
2.搭建并使用集群
(1)创建实例
搭建集群的第一件事情我们需要一些运行在 集群模式的Redis实例. 这意味这集群并不是由一些普通的Redis实例组成的,集群模式需要通过配置启用,开启集群模式后的Redis实例便可以使用集群特有的命令和特性了。
首先, 让我们进入一个新目录, 并创建六个以端口号为名字的子目录, 稍后我们在将每个目录中运行一个 Redis 实例: 命令如下:
cd /usr/local/
mkdir redis
cd redis
mkdir 7000
mkdir 700{1..6}
在文件夹 7000 至 7006中, 各创建一个 redis.conf 文件, 文件的内容可以使用上面的示例配置文件, 但记得将配置中的端口号从 7000 改为与文件夹名字相同的号码。
下面是一个最少选项的集群的配置文件:
[root@server1 ~]# cd 7000/
[root@server1 7000]# vim redis.conf
port 7000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
daemonize yes
文件中的 cluster-enabled 选项用于开实例的集群模式, 而 cluster-conf-file 选项则设定了保存节点配置文件的路径, 默认值为 nodes.conf.节点配置文件无须人为修改, 它由 Redis 集群在启动时创建, 并在有需要时自动进行更新。
要让集群正常运作至少需要三个主节点,不过在刚开始试用集群功能时, 强烈建议使用六个节点: 其中三个为主节点, 而其余三个则是各个主节点的从节点。
打开实例
[root@server1 7000]# redis-server redis.conf
用ps ax 查看进程,查看cluster是否创建成功
(2) 搭建集群
现在我们已经有了7正在运行中的 Redis 实例, 接下来我们需要使用这些实例来创建集群, 并为每个节点编写配置文件。
通过使用 Redis 集群命令行工具 redis-trib , 编写节点配置文件的工作可以非常容易地完成: redis-trib 位于 Redis 源码的 src 文件夹中, 它是一个 Ruby 程序, 这个程序通过向实例发送特殊命令来完成创建新集群, 检查集群, 或者对集群进行重新分片(reshared)等工作。
[root@server1 ~]# redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
这个命令在这里用于创建一个新的集群, 选项–replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。
之后跟着的其他参数则是这个集群实例的地址列表,3个master3个slave redis-trib 会打印出一份预想中的配置给你看, 如果你觉得没问题的话, 就可以输入 yes , redis-trib 就会将这份配置应用到集群当中,让各个节点开始互相通讯,最后可以得到如下信息:
这表示集群中的 16384 个槽都有至少一个主节点在处理, 集群运作正常。
3.使用集群
测试 Redis 集群比较简单的 redis-cli , 接下来我们将使用 redis-cli 为例来进行演示:
三主信息
[root@server1 ~]# redis-cli --cluster info 127.0.0.1:7000
127.0.0.1:7000 (fb6af12f...) -> 0 keys | 5461 slots | 1 slaves.
127.0.0.1:7001 (e27ba0ce...) -> 0 keys | 5462 slots | 1 slaves.
127.0.0.1:7002 (6441e2ec...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
[root@server1 ~]# redis-cli -c -p 7000
七、结合数据库
部署和之前一样,可看文章开头部署。
这里用到server1 server2 server3
以下实验所以需要的包链接: 需要的软件包及依赖 提取码: hend
[root@server2 ~]# tar zxf redis-5.0.8.tar.gz
[root@server2 ~]# cd redis-5.0.8/
[root@server2 redis-5.0.8]# yum install gcc-c++ -y
[root@server2 redis-5.0.8]# make & make install
[root@server2 utils]# ./install_server.sh
server1
root@server1 ~]# yum install -y httpd php php-mysql.x86_64 php-redis
[root@server1 ~]# cd /var/www/html/
get test.php
[root@server1 html]# vim test.php
<?php
$redis = new Redis();
$redis->connect('172.25.3.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.3.3','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 "<br>";
for ($key = 1; $key < 10; $key++)
{
echo "number is <b><font color=#FF0000>$key</font></b>";
echo "<br>";
echo "name is <b><font color=#FF0000>$data[$key]</font></b>";
echo "<br>";
}
?>
[root@server1 html]# systemctl start httpd.service
get php-devel-5.4.16-46.el7.x86_64.rpm
[root@server1 html]# yum install php-devel-5.4.16-46.el7.x86_64.rpm -y
mirror rhel7
[root@server1 ~]# cd rhel7/
[root@server1 rhel7]# yum install php-pecl-redis-2.2.8-1.el7.x86_64.rpm php-fpm-5.4.16-46.el7.x86_64.rpm php-pecl-igbinary-1.2.1-1.el7.x86_64.rpm -y
server3:mysql
[root@server3 ~]# yum install mariadb-server -y
[root@server3 ~]# systemctl start mariadb.service
get test.sql
[root@server3 ~]# vim 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 ;
[root@server3 ~]# mysql < test.sql
[root@server3 ~]# mysql
grant all on test.* to redis@'%' identified by 'westos';
到这里,我们已经实现了 redis 作为 mysql 的缓存服务器,但是如果更新了 mysql,redis
中仍然会有对应的 KEY,数据就不会更新,此时就会出现 mysql 和 redis 数据不一致的情
况。所以接下来就要通过 mysql 触发器将改变的数据同步到 redis 中。
更新完数据库如何实现同步redis
配置 gearman 实现数据同步
Gearman 是一个支持分布式的任务分发框架:
Gearman Job Server: Gearman 核心程序,需要编译安装并以守护进程形式运行在后台。
Gearman Client:可以理解为任务的请求者。
Gearman Worker:任务的真正执行者,一般需要自己编写具体逻辑并通过守护进程方式
运行,Gearman Worker 接收到 Gearman Client 传递的任务内容后,会按顺序处理。
大致流程:
下面要编写的 mysql 触发器,就相当于 Gearman 的客户端。修改表,插入表就相当于直接
下发任务。然后通过 lib_mysqludf_json UDF 库函数将关系数据映射为 JSON 格式,然后
在通过 gearman-mysql-udf 插件将任务加入到 Gearman 的任务队列中,最后通过
redis_worker.php,也就是 Gearman 的 worker 端来完成 redis 数据库的更新。
安装 gearman 软件包:
[root@server1 rhel7]# yum install libgearman-* libevent-devel-2.0.21-4.el7.x86_64.rpm gearmand-1.1.12-18.el7.x86_64.rpm php-pecl-gearman-1.1.2-1.el7.x86_64.rpm -y
启动服务:
[root@server1 ~]# systemctl start gearmand
安装 lib_mysqludf_json
lib_mysqludf_json UDF 库函数将关系数据映射为 JSON 格式。通常,数据库中的数据映
射为 JSON 格式,是通过程序来转换的。
server3
get lib_mysqludf_json-master.zip
[root@server3 ~]# yum install unzip -y
[root@server3 ~]# unzip lib_mysqludf_json-master.zip
[root@server3 ~]# yum install mariadb-devel -y
[root@server3 ~]# yum install gcc -y
[root@server3 ~]# cd lib_mysqludf_json-master/
[root@server3 lib_mysqludf_json-master]# gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c
查看mysql的模块目录:
[root@server3 lib_mysqludf_json-master]# mysql
MariaDB [(none)]> show global variables like 'plugin_dir';
拷贝 lib_mysqludf_json.so 模块:
[root@server3 lib_mysqludf_json-master]# cp lib_mysqludf_json.so /usr/lib64/mysql/plugin/
注册UDF函数
MariaDB [(none)]> CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so';
查看函数:
MariaDB [(none)]> select * from mysql.func;
安装 gearman-mysql-udf
这个插件是用来管理调用 Gearman 的分布式的队列。
https://launchpad.net/gearman-mysql-udf
[root@server3 ~]# yum install libgearman-1.1.12-18.el7.x86_64.rpm libgearman-devel-1.1.12-18.el7.x86_64.rpm libevent-devel-2.0.21-4.el7.x86_64.rpm -y
get gearman-mysql-udf-0.6.tar.gz
[root@server3 ~]# tar zxf gearman-mysql-udf-0.6.tar.gz
[root@server3 ~]# cd gearman-mysql-udf-0.6/
[root@server3 gearman-mysql-udf-0.6]# ./configure --libdir=/usr/lib64/mysql/plugin/
[root@server3 gearman-mysql-udf-0.6]# make & make install
注册UDF函数
MariaDB [(none)]> CREATE FUNCTION gman_do_background RETURNS STRING SONAME 'libgearman_mysql_udf.so';
MariaDB [(none)]> CREATE FUNCTION gman_servers_set RETURNS STRING SONAME 'libgearman_mysql_udf.so';
查看函数:
MariaDB [(none)]> select * from mysql.func;
指定 gearman 的服务信息
[root@server3 ~]# yum install gearmand-1.1.12-18.el7.x86_64.rpm -y
[root@server3 ~]# systemctl start gearmand.service
root@server1 ~]# yum install gearmand-1.1.12-18.el7.x86_64.rpm -y
[root@server3 ~]# mysql
MariaDB [(none)]> SELECT gman_servers_set('172.25.3.1:4730');
编写 mysql 触发器(根据实际情况编写)
[root@server3 ~]# vim test.sql
use test;
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 ;
[root@server3 ~]# mysql < test.sql
查看触发器:
MariaDB [(none)]> SHOW TRIGGERS FROM test;
编写 gearman 的 worker 端
[root@server1 ~]# cat worker.php
<?php
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction('syncToRedis', 'syncToRedis');
$redis = new Redis();
$redis->connect('172.25.3.2', 6379);
while($worker->work());
function syncToRedis($job)
{
global $redis;
$workString = $job->workload();
$work = json_decode($workString);
if(!isset($work->id)){
return false;
}
$redis->set($work->id, $work->name);
}
?>
后台运行 worker
[root@server1 ~]# nohup php worker.php &
更新 mysql 中的数据
MariaDB [(none)]> update test.test set name='hello' where id=1;
查看redis
[root@server2 utils]# redis-cli
127.0.0.1:6379> get 1
"hello"
127.0.0.1:6379>