php redis做mysql的缓存,怎么异步redis同步到mysql数据库?

 我来答
在晴天的雨伞
2016-06-13 · TA获得超过6869个赞
知道大有可为答主
回答量:5761
采纳率:86%
帮助的人:1245万
展开全部

  对于变化频率非常快的数据来说,如果还选择传统的静态缓存方式(Memocached、File System等)展示数据,可能在缓存的存取上会有很大的开销,并不能很好的满足需要,而Redis这样基于内存的NoSQL数据库,就非常适合担任实时数据的容器。
  但是往往又有数据可靠性的需求,采用MySQL作为数据存储,不会因为内存问题而引起数据丢失,同时也可以利用关系数据库的特性实现很多功能。
  所以就会很自然的想到是否可以采用MySQL作为数据存储引擎,Redis则作为Cache。而这种需求目前还没有看到有特别成熟的解决方案或工具,因此采用Gearman+PHP+MySQL UDF的组合异步实现MySQL到Redis的数据复制。
  MySQL到Redis数据复制方案
  无论MySQL还是Redis,自身都带有数据同步的机制,比较常用的MySQL的Master/Slave模式,就是由Slave端分析Master的binlog来实现的,这样的数据复制其实还是一个异步过程,只不过当服务器都在同一内网时,异步的延迟几乎可以忽略。
  那么理论上也可以用同样方式,分析MySQL的binlog文件并将数据插入Redis。但是这需要对binlog文件以及MySQL有非常深入的理解,同时由于binlog存在Statement/Row/Mixedlevel多种形式,分析binlog实现同步的工作量是非常大的。
  因此这里选择了一种开发成本更加低廉的方式,借用已经比较成熟的MySQL UDF,将MySQL数据首先放入Gearman中,然后通过一个自己编写的PHP Gearman Worker,将数据同步到Redis。比分析binlog的方式增加了不少流程,但是实现成本更低,更容易操作。
  Gearman的安装与使用
  Gearman是一个支持分布式的任务分发框架。设计简洁,获得了非常广泛的支持。一个典型的Gearman应用包括以下这些部分:

  Gearman Job Server:Gearman核心程序,需要编译安装并以守护进程形式运行在后台

  Gearman Client:可以理解为任务的收件员,比如在后台执行一个发送邮件的任务,可以在程序中调用一个Gearman Client并传入邮件的信息,然后就可以将执行结果立即展示给用户,而任务本身会慢慢在后台运行。

  Gearman Worker:任务的真正执行者,一般需要自己编写具体逻辑并通过守护进程方式运行,Gearman Worker接收到Gearman Client传递的任务内容后,会按顺序处理。

  以前曾经介绍过类似的后台任务处理项目Resque。两者的设计其实非常接近,简单可以类比为:

  Gearman Job Server:对应Resque的Redis部分

  Gearman Client:对应Resque的Queue操作

  Gearman Worker:对应Resque的Worker和Job

  这里之所以选择Gearman而不是Resque是因为Gearman提供了比较好用的MySQL UDF,工作量更小。

  安装Gearman及PHP Gearman扩展
  以下均以Ubuntu12.04为例。

  apt-get install gearman gearman-server libgearman-dev

  检查Gearman的运行状况:

  /etc/init.d/gearman-job-server status
  * gearmand is running

  说明Gearman已经安装成功。
  PHP的Gearman扩展可以通过pecl直接安装

  pecl install gearman
  echo "extension=gearman.so">/etc/php5/conf.d/gearman.ini
  service php5-fpm restart

  但是实测发现ubuntu默认安装的gearman版本过低,直接运行pecl install gearman会报错

  configure: error: libgearman version 1.1.0or later required

  因此Gearman + PHP扩展建议通过编译方式安装,这里为了简单说明,选择安装旧版本扩展:

  pecl install gearman-1.0.3

  Gearman + PHP实例
  为了更容易理解后文Gearman的运行流程,这里不妨从一个最简单的Gearman实例来说明,比如要进行一个文件处理的操作,首先编写一个Gearman Client并命名为client.php:

  <?php
  $client =newGearmanClient();
  $client->addServer();
  $client->doBackground('writeLog','Log content');
echo '文件已经在后台操作';

  运行这个文件,相当于模拟用户请求一个Web页面后,将处理结束的信息返回用户:

  php client.php

  查看一下Gearman的状况:

  (echo status ; sleep 0.1)| netcat127.0.0.14730

  可以看到输出为

  writeLog        100.

  说明已经在Gearman中建立了一个名为writeLog的任务,并且有1个任务在队列等待中。
而上面的4列分别代表当前的Gearman的运行状态:

  任务名称

  在等待队列中的任务

  正在运行的任务

  正在运行的Worker进程

  可以使用watch进行实时监控:

  watch -n 1"(echo status; sleep 0.1) | nc 127.0.0.1 4730"

  然后我们需要编写一个Gearman Worker命名为worker.php:

  <?php
  $worker =newGearmanWorker();
  $worker->addServer();
  $worker->addFunction('writeLog','writeLog');while($worker->work());function   writeLog($job){
       $log = $job->workload();file_put_contents(__DIR__ .'/gearman.log', $log ."\n",   FILE_APPEND | LOCK_EX);}

  Worker使用一个while死循环实现守护进程,运行

  php worker.php

  可以看到Gearman状态变为:

  writeLog        001


  同时查看同目录下gearman.log,内容应为从Client传入的值Log content。
  通过MySQL UDF + Trigger同步数据到Gearman
  MySQL要实现与外部程序互通的最好方式还是通过MySQL UDF(MySQL user defined functions)来实现。为了让MySQL能将数据传入Gearman,这里使用了lib_mysqludf_json和gearman-mysql-udf的组合。
  安装lib_mysqludf_json
  使用lib_mysqludf_json的原因是因为Gearman只接受字符串作为入口参数,可以通过lib_mysqludf_json将MySQL中的数据编码为JSON字符串

  apt-get install libmysqlclient-dev
  wget https://github.com/mysqludf/lib_mysqludf_json/archive/master.zip
  unzip master.zip
  cd lib_mysqludf_json-master/
  rm lib_mysqludf_json.so
  gcc $(mysql_config --cflags)-shared -fPIC -o lib_mysqludf_json.so   lib_mysqludf_json.c

  可以看到重新编译生成了 lib_mysqludf_json.so 文件,此时需要查看MySQL的插件安装路径:

  mysql -u root -pPASSWORD --execute="show variables like '%plugin%';"+---------------+------------------------+|Variable_name|Value|+---------------+------------------------+| plugin_dir    |/usr/lib/mysql/plugin/|+---------------+------------------------+

  然后将 lib_mysqludf_json.so 文件复制到对应位置:

  cp lib_mysqludf_json.so /usr/lib/mysql/plugin/

  最后登入MySQL运行语句注册UDF函数:

  CREATE FUNCTION json_object RETURNS STRING SONAME 'lib_mysqludf_json.so';

  安装gearman-mysql-udf
  方法几乎一样:

  apt-get install libgearman-dev
  wget https://launchpad.net/gearman-mysql-  udf/trunk/0.6/+download/gearman-  mysql-udf-0.6.tar.gz
  tar -xzf gearman-mysql-udf-0.6.tar.gz
  cd gearman-mysql-udf-0.6./configure --with-mysql=/usr/bin/mysql_config 

  -libdir=/usr/lib/mysql/plugin/

  make && make install

  登入MySQL运行语句注册UDF函数:

  CREATE FUNCTION gman_do_background RETURNS STRING SONAME   'libgearman_mysql_udf.so';
  CREATE FUNCTION gman_servers_set RETURNS STRING SONAME   'libgearman_mysql_udf.so';

  最后指定Gearman服务器的信息:

  SELECT gman_servers_set('127.0.0.1:4730');

  通过MySQL触发器实现数据同步
最终同步哪些数据,同步的条件,还是需要根据实际情况决定,比如将数据表data的数据在每次更新时同步,那么编写Trigger如下:

  DELIMITER $$
  CREATE TRIGGER datatoredis AFTER UPDATE ON data
  FOR EACH ROW BEGIN
  SET @ret=gman_do_background('syncToRedis', json_object(NEW.id as`id`,   NEW.volume as`volume`));END$$
  DELIMITER ;

  尝试在数据库中更新一条数据查看Gearman是否生效。

  Gearman PHP Worker将MySQL数据异步复制到Redis
Redis作为时下当热的NoSQL缓存解决方案无需过多介绍,其安装及使用也非常简单:

  apt-get install redis-server
  pecl install redis
  echo "extension=redis.so">/etc/php5/conf.d/redis.ini

  然后编写一个Gearman Worker:redis_worker.php

  #!/usr/bin/env php<?
  $worker =newGearmanWorker();
  $worker->addServer();
  $worker->addFunction('syncToRedis','syncToRedis');

  $redis =newRedis();
  $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)){returnfalse;}
       $redis->set($work->id, $workString);}

  最后需要将Worker在后台运行:

  nohup php redis_worker.php &

  通过这种方式将MySQL数据复制到Redis,经测试单Worker基本可以瞬时完成。

最黑的是眼
2016-01-26 · TA获得超过9062个赞
知道大有可为答主
回答量:3537
采纳率:0%
帮助的人:995万
展开全部
正常情况下是没有问题的,
但是有人用恶意脚本进行刷奖,也就是同一个人发起大量请求,1秒可能一两百的请求甚至更多,而且不只一个人刷奖。
问题出在1这一步
举个例子,假设每人只能抽一次奖,因为请求太快,同一人的a,b两个请求几乎同时来,a走完抽奖逻辑了,并且在抽奖表中插入记录的过程时,因为mysql的性能的问题,b去走1这一步是读不到表中的记录的,因为a的插入根本没有完成。所以b请求会再走一次抽奖逻辑。造成同一人抽奖两次,然后再插入抽奖表。
我关心的是能否a插入抽奖表的瞬间,b就能判断出抽奖表有数据。
所以我觉得问题是mysql写入的不够快,读取的不够快,所以我要采用redis做一层快速缓存。
我们做的抽奖是单一奖品百分之百中奖,只限制奖品数量,所以必须保证每人只能抽一次,而且尽量在程序层面去解决。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
艺博教育官方帐号
2016-01-21 · 知道合伙人教育行家
艺博教育官方帐号
知道合伙人教育行家
采纳数:218 获赞数:1238
陈琳,曾担任过蒙特梭利幼儿园的老师,2007年开始专心家庭教育,取得国家高师级心理咨询师资格。

向TA提问 私信TA
展开全部
我感觉就是读脏数据的问题,楼主希望判断是否抽奖,抽奖逻辑,写抽奖表,这个过程中不能有第二相同用户来抽奖,实际上这个过程中,抽奖逻辑肯定要占大部分时间,至少要执行一次生成随机数的操作吧,在这个过程中,还没写表,所以其他请求读取数据库显示自己还没抽奖能够走抽奖逻辑。我的想法是第一步执行后加一个行锁,第三步执行后再释放这个锁,防止在这个过程中再有请求读取数据。
本回答被提问者采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 更多回答(1)
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式