Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了
memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便
Redis 的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上,(这称为“半持久化模式”);也可以把每一次数据变化都写入到一个 append,only file(aof)里面(这称为“全持久化模式”)。
它的大概框架有点像这样:
主机环境 rhel6.5 selinx and iptales disabled
# tar zxf redis-3.0.2.tar.gz
# yum install -y gcc
# cd redis-3.0.2
make
make install
安装完后会在/usr/local/bin下产生如下文件
# ls /usr/local/bin/
redis-benchmark redis-check-dump redis-sentinel
redis-check-aof redis-cli redis-server
这些可执行文件的作用如下:
redis-server: Redis 服务主程序。
redis-cli: Redis 客户端命令行工具,也可以用 telnet 来操作。
redis-benchmark: Redis 性能测试工具,用于测试读写性能。
redis-check-aof:检查 redis aof 文件完整性,aof 文件持久化记录服务器执行的所有写操作命令,用于还原数据。
redis-check-dump:检查 redis rdb 文件的完整性,rdb 就是快照存储,即按照一定的策略周期性的将数据保存到磁盘,是默认的持久化方式。
redis-sentinel: redis-sentinel 是集群管理工具,主要负责主从切换。
2. 配置并启动服务
# /root/redis/redis-3.0.2/utils/install_server.sh
redis服务配置及安装,可以直接回车,采取默认方式
Welcome to the redis service installer
This script will help you easily set up a running redis server
Please select the redis port for this instance: [6379]
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf]
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log]
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379]
Selected default - /var/lib/redis/6379
Please select the redis executable path [/usr/local/bin/redis-server]
Selected config:
Port : 6379
Config file : /etc/redis/6379.conf
Log file : /var/log/redis_6379.log
Data dir : /var/lib/redis/6379
Executable : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
查看网络状态会发现已经自动开启了redis的6379端口
# netstat -antulp | grep redis
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 4197/redis-server *
tcp 0 0 :::6379 :::* LISTEN 4197/redis-server *
# ls /etc/redis/
6379.conf #这个就是它的配置文件
Redis 客户端使用:
127.0.0.1:6379> config get *
1) "dbfilename"
2) "dump.rdb"
3) "requirepass"
4) ""
5) "masterauth"
6) ""
当需要做redis扩展时,我们可以这样做
# vim /etc/redis/6379.conf
# slaveof <masterip> <masterport>
slaveof masterip 6379
即可实现redis的高可用
Redis 作 mysql 的缓存服务器
1. 安装 lnmp 环境,安装以下软件包:
这一步可能会出现版本不兼容问题,建议安装最新稳定版rpm包,如果曾经安装过可以进行更新
# yum localinstall nginx-1.8.0-1.el6.ngx.x86_64.rpm
php-5.3.3-38.el6.x86_64.rpm
php-cli-5.3.3-38.el6.x86_64.rpm
php-common-5.3.3-38.el6.x86_64.rpm
php-devel-5.3.3-38.el6.x86_64.rpm
php-fpm-5.3.3-38.el6.x86_64.rpm
php-gd-5.3.3-38.el6.x86_64.rpm
php-mbstring-5.3.3-38.el6.x86_64.rpm
php-mysql-5.3.3-38.el6.x86_64.rpm
php-pdo-5.3.3-38.el6.x86_64.rpm
# yum install mysql-server -y
2. 简单配置 nginx
# vim /etc/nginx/conf.d/default.conf
location / {
root /usr/share/nginx/html;
index index.php index.html index.htm;
}
location ~ \.php$ {
root /usr/share/nginx/html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/$fastcgi_script_name;
include fastcgi_params;
}
# nginx -t #检测是否出现语法问题
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# service nginx start
3:php-fpm简单配置
# vim /etc/php-fpm.d/www.conf
修改其用户和用户组为nginx
user = nginx
; RPM: Keep a group allowed to write in log dir.
group = nginx
# vim /etc/php.ini #修改其时区为亚洲上海
date.timezone = Asia/Shanghai
# service php-fpm start
# vim /usr/share/nginx/html/index.php
<?php
phpinfo()
?>
# nginx -s reload
4:安装 php 的 redis 扩展
# unzip phpredis-master.zip
# cd phpredis-master
[root@server1 phpredis-master]# phpize
# ./configure --with-php-config=/usr/bin/php-config
# make && make install
; Enable mysql extension module
# cp mysql.ini redis.ini
# vim redis.ini
extension=redis.so
# vim /etc/php.ini
extension=redis.so #加载 redis 模块
5.配置 mysql
mysql> grant all on test.* to redis@localhost identified by 'redis';
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
编辑测试sql语句脚本
# 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');
# mysql < test.sql # 导入mysql数据库
# mysql #查看导入数据
mysql> use test
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| test |
+----------------+
1 row in set (0.00 sec)
mysql> select * from test;
+----+-------+
| id | name |
+----+-------+
| 1 | test1 |
| 2 | test2 |
| 3 | test3 |
| 4 | test4 |
| 5 | test5 |
| 6 | test6 |
| 7 | test7 |
| 8 | test8 |
| 9 | test9 |
+----+-------+
9 rows in set (0.00 sec)
mysql> desc test;
+-------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+----------------+
| id | int(7) | NO | PRI | NULL | auto_increment |
| name | char(8) | YES | | NULL | |
+-------+---------+------+-----+---------+----------------+
6. 创建 php 测试页面
<?php
$redis = new Redis();
$redis->connect('127.0.0.1',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('127.0.0.1','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>";
}
?>
# cp test.php /usr/share/nginx/html/
测试结果:
第一次挥发现其数据来自mysql,当再次刷新后其数据便是来自redis存储了
到这里,我们已经实现了 redis 作为 mysql 的缓存服务器,但是如果更新了 mysql,redis中仍然会有对应的 KEY,数据就不会更新,此时就会出现 mysql 和 redis 数据不一致的情
况。所以接下来就要通过 mysql 触发器将改变的数据同步到 redis 中
配置 gearman 实现数据同步
Gearman 是一个支持分布式的任务分发框架:
一个Gearman请求的处理过程涉及三个角色:Client -> Job -> Worker。
Client:请求的发起者,可以是 C,PHP,Perl,MySQL UDF 等等。
Job:请求的调度者,用来负责协调把 Client 发出的请求转发给合适的 Work。
Worker:请求的处理者,可以是 C,PHP,Perl 等等
大致流程:
下面要编写的 mysql 触发器,就相当于 Gearman 的客户端。修改表,插入表就相当于直接下发任务。然后通过 lib_mysqludf_json UDF 库函数将关系数据映射为 JSON 格式,然后
在通过 gearman-mysql-udf 插件将任务加入到 Gearman 的任务队列中,最后通过redis_worker.php,也就是 Gearman 的 worker 端来完成 redis 数据库的更新
1. 安装 gearman 软件包
yum localinstall gearmand-1.1.8-2.el6.x86_64.rpm
libgearman-devel-1.1.8-2.el6.x86_64.rpm
libgearman-1.1.8-2.el6.x86_64.rpm
libevent-libevent-1.4.13-4.el6.x86_64.rpm
libevent-devel-1.4.13-4.el6.x86_64.rpm
libevent-doc-1.4.13-4.el6.noarch.rpm
libevent-headers-1.4.13-4.el6.noarch.rpm
# service gearmand start #启动服务
# netstat -antlp | grep gearmand
tcp 0 0 0.0.0.0:4730 0.0.0.0:* LISTEN 7009/gearmand
tcp 0 0 :::4730 :::* LISTEN 7009/gearmand
2. 安装 php 的 gearman 扩展
# yum install -y db*-devel
# tar zxf gearman-1.1.2.tgz
# cd gearman-1.1.2
# ./configure --with-php-config=/usr/bin/php-config
# make && make install
# cd /etc/php.d/
# cp redis.ini gearman.ini
# vim gearman.ini
extension=gearman.so
# service php-fpm reload
3. 安装 lib_mysqludf_json
lib_mysqludf_json UDF 库函数将关系数据映射为 JSON 格式。通常,数据库中的数据映射为 JSON 格式,是通过程序来转换的。
# yum install -y mysql-devel
# unzip lib_mysqludf_json-master.zip
# cd lib_mysqludf_json-master
# gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c
查看 mysql 的模块目录:
mysql> show global variables like 'plugin_dir';
+---------------+-------------------------+
| Variable_name | Value |
+---------------+-------------------------+
| plugin_dir | /usr/lib64/mysql/plugin |
+---------------+-------------------------+
1 row in set (0.00 sec)
拷贝 lib_mysqludf_json.so 模块:
# cp lib_mysqludf_json.so /usr/lib64/mysql/plugin/
注册 UDF 函数
mysql> CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so';
查看函数
mysql> select * from mysql.func;
+-------------+-----+----------------------+----------+
| name | ret | dl | type |
+-------------+-----+----------------------+----------+
| json_object | 0 | lib_mysqludf_json.so | function |
+-------------+-----+----------------------+----------+
4. 安装 gearman-mysql-udf
这个插件是用来管理调用 Gearman 的分布式的队列。
# tar zxf gearman-mysql-udf-0.6.tar.gz
# cd gearman-mysql-udf-0.6
# ./configure --with-mysql=/usr/bin/mysql_config
--libdir=/usr/lib64/mysql/plugin/
# make && make install
注册 UDF 函数
mysql> CREATE FUNCTION gman_do_background RETURNS STRING SONAME 'libgearman_mysql_udf.so';
mysql> CREATE FUNCTION gman_servers_set RETURNS STRING SONAME 'libgearman_mysql_udf.so';
查看函数
mysql> select * from mysql.func;
+--------------------+-----+-------------------------+----------+
| name | ret | dl | type |
+--------------------+-----+-------------------------+----------+
| json_object | 0 | lib_mysqludf_json.so | function |
| gman_do_background | 0 | libgearman_mysql_udf.so | function |
| gman_servers_set | 0 | libgearman_mysql_udf.so | function |
+--------------------+-----+-------------------------+----------+
3 rows in set (0.00 sec)
指定 gearman 的服务信息
mysql> SELECT gman_servers_set('127.0.0.1:4730');
+------------------------------------+
| gman_servers_set('127.0.0.1:4730') |
+------------------------------------+
| 127.0.0.1:4730 |
+------------------------------------+
1 row in set (0.00 sec)
5. 编写 mysql 触发器(根据实际情况编写)
ues 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 ;
# mysql < test.sql
查看触发器
mysql> SHOW TRIGGERS FROM test;
| datatoredis | UPDATE | test | BEGIN
SET @RECV=gman_do_background('syncToRedis', json_object(NEW.id as `id`, NEW.name as `name`));
END | AFTER | NULL | | root@localhost | latin1 | latin1_swedish_ci | latin1_swedish_ci |
+-------------+--------+-------+----------------------------------------------------------------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+
1 row in set (0.00 sec)
6. 编写 gearman 的 worker 端
# vim worker.php
<?php
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction('syncToRedis', 'syncToRedis');
$redis = new Redis();
$redis->connect('127.0.0.1', 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); #这条语句就是将 id 作 KEY 和
name 作 VALUE 分开存储,需要和前面写的 php 测试代码的存取一致。
}
?>
后台运行 worker
# nohup php worker.php &
7. 更新 mysql 中的数据
mysql> update test set name='linux' where id=1;
查看 redis
# redis-cli
127.0.0.1:6379> get 1
"linux"
127.0.0.1:6379>
刷新测试页面数据同步