Chinaunix首页 | 论坛 | 博客
  • 博客访问: 361879
  • 博文数量: 45
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 885
  • 用 户 组: 普通用户
  • 注册时间: 2015-05-06 21:07
个人简介

做好自己,不卑不亢,持之以恒!!

文章分类

全部博文(45)

分类: 架构设计与优化

2015-06-30 16:59:18


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>
刷新测试页面数据同步



阅读(3123) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~