redis与数据库结合,作为数据库数据的缓存提供给前端
一.实现数据库,php,nginx和redis的架构
server1提供nginx服务,使用php语言,server2提供redis缓存服务,server3提供后端数据库服务…
整体思想是:客户端通过nginx和php访问后端数据库时,先在redis这个数据库缓存中赵,查看是否含有想要的数据,如果没有就去后端数据库查找,将查找到数据返回给客户端一份,另外在redis中缓存一份….下次如果访问相同的数据就直接去redis,缩短时间同时也减轻数据库的查找压力
(一)在server1前端中
1.安装nginx和php
yum install -y nginx-1.8.0-1.el6.ngx.x86_64.rpm php-*
2.在php的配置文件中修改时区为上海
cd /etc/php.d/
vim /etc/php.ini
timezone = “Asia/Shanghai”
3.因为php作为nginx的前端服务,我们将php网页代码也限制在nginx的用户空间中
cd /etc/php-fpm.d/
vim www.conf 修改用户为nginx
4.查看端口情况
netstat -antlp
5.修改nginx的配置文件
cd /etc/nginx/conf.d
vim default.conf
location / {
root /usr/share/nginx/html;
index index.php index.html index.htm; # 设置index.php为默认发布文件
location ~ \.php$ {
root 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;
}
6.将php测试页面的代码(该代码是查询数据库中数据)放在默认发布目录下
cd /usr/share/nginx/html/
cp test.php /usr/share/nginx/html/index.php
test.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'); # 利用redis用户访问数据库
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>";
}
?>
7.源码编译php与redis的连接软件—phpredis-master.zip
yum install unzip # 安装解压工具
unzip phpredis-master.zip
cd phpredis-master
phpize # 创建预编译环境
./configure
make
make install # 源码编译安装
8.在php中动态加载redis模块
cd /etc/php.d
cp mysql.ini redis.ini # 拷贝数据库的模版
vim redis.ini
extension=redis.so # 将redis模块加入php中
9.重新加载nginx,php和redis服务
/etc/init.d/php-fpm reload
nginx-s reload
/etc/init.d/redis stop
/etc/init.d/redis start
10.在数据库中建数据库建表,对所有ip上的nginx用户授权(因为在php前端我们是利用nginx用户来访问数据库的)
11.在浏览器处输入提供nginx服务和php服务的主句ip,因为redis里边没有数据缓存,所以得去后端服务器拿数据,刷新页面,会看到第二次是去redis中拿数据,同时我们在提供redis的主机中利用redis-cli命令行也可以看到数据(说明数据是真的存在了redis缓存中)
数据库:
网页第二次去redis:
提供redis服务的主机:
可是做到这儿,我们可以发现问题,当在数据库中修改了数据之后,网页中的数据和 redis缓存处的数据均不改变,这样当然是不行的,所以我们解决这个问题…
二.利用Gearman进行Mysql到Redis的同步复制:
Gearman是一个开源的Map/Reduce分布式计算框架,具有丰富的client sdk,而且它支持MySQL UDF。
当有数据发生变化时,通过MySQL Trigger实时异步调用Gearman的UDF提交一个job给JobServer,当job执行的时候会去更新redis;从而保证redis与MySQL中的数据是同步的。
(一)在server1中:
1.安装Gearmand(服务端)及其很多很多的依赖项,之后打开gearmand服务
yum install -y gearmand-1.1.8-2.el6.x86_64.rpm libgearman-* libevent-*
yum install php-devel-5.3.3-38.el6.x86_64.rpm php-5.3.3-38.el6.x86_64.rpm
/etc/init.d/gearmand start
netstat -antlp # 查看对应端口是否打开
2.scp gearman-mysql-udf-0.6.tar.gz server3:
scp lib_mysqludf_json-master.zip server3:
scp libgearman-* server3:
scp libevent-* server3:
3.在php中动态加入模块gearman
cp worker.php /usr/local/ # work是中间搬运数据的“进程”,由php语言编写
ll gearman-1.1.2.tgz
tar zxf gearman-1.1.2.tgz # 在php中动态加入Gearman的模块,并进行源码编译
cd gearman-1.1.2
phpize
make make
install
vim worker.php
<?php
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction('syncToRedis', 'syncToRedis');
$redis = new Redis();
$redis->connect('172.25.1.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);
# 这条语句就是将 id 作 KEY 和name 作 VALUE 分开存储,需要和前面写的 php 测试代码的存取一致。
}
?>
4.将添加的动态模块加进php的模块目录中,当然也可选择直接写入配置文件中
cd /usr/lib64/php/modules/ # php的模块目录
ll gearman.so # 刚刚源码编译成功的gearman模块
cp redis.ini gearman.ini # 利用redis的模版,编写gearman的模块配置文件
vim gearman.ini
gearman.so
5.查看个gearman模块是否添加成功
/etc/init.d/php-fpm reload # 重载服务
php -m | grep gearman # 如果有则表明成功
6.启动worker进程并将其打入后台
nohup php /usr/local/worker.php &
ps ax
(二)在server3(后端数据库)中:
1.安装把mysql关系型数据转换成json格式的UDF工具—lib_mysqludf_json-master
(mysql里的数据格式转成json格式,通常使用php的json扩展实现。如果使用udf,会有更快的速度。)
unzip lib_mysqludf_json-master.zip # 解压源码包
cd lib_mysqludf_json-master
yum install gcc mysql-devel -y # 安装依赖性
gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c
cd /usr/lib64/mysql/plugin/ # 存放数据库服务的所有插件位置
cd /root/lib_mysqludf_json-master
cp lib_mysqludf_json.so /usr/lib64/mysql/plugin/ # 拷贝 lib_mysqludf_json.so 模块到数据库的插件目录中
2.登陆mysql,注册 json_object函数:
show global variables like 'plugin_dir'; # 查看数据库服务存放插件的目录
CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so'; # 注册 UDF 函数 json_object(作用是利用该函数可以将数据库中的数据构造为json格式)
3.安装 gearman-mysql-udf,这个插件是用来管理调用 Gearman 的分布式的队列。
tar zxf gearman-mysql-udf-0.6.tar.gz
cd gearman-mysql-udf-0.6
yum install libgearman-* libevent-* # 解决依赖性
./configure --libdir=/usr/lib64/mysql/plugin/ # 创建预编译环境,指定安装目录在默认数据库插件目录中
make # 源码编译
make install
4.登陆mysql,再次注册函数
CREATE FUNCTION gman_do_background RETURNS STRING SONAME 'libgearman_mysql_udf.so'; # 用Gearman做队列来实现消息推送
CREATE FUNCTION gman_servers_set RETURNS STRING SONAME 'libgearman_mysql_udf.so';
select * from mysql.func; # 查看数据库中注册的函数
SELECT gman_servers_set('172.25.1.1:4730'); # 指定 gearman 的服务信息
5.编辑触发器文件
什么是触发器: 触发器(trigger)是SQL server
提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作(insert,delete, update)时就会激活它执行。触发器经常用于加强数据的完整性约束和业务规则等
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 ;
将触发器程序导入数据库中:mysql < test.sql
登陆mysql:SHOW TRIGGERS FROM test; 查看触发器是否导入
测试:
在数据库中修改数据,在redis和网页中查看数据是否更新….
数据库中:
网页:
redis:
说明三处数据已经达到一致!!!