运维实战 Redis与Mysql的业务衔接

本文介绍了如何在三台服务器上配置Redis和MySQL的业务衔接,实现实时数据同步。通过在MySQL上创建触发器,并结合Gearman Job Server和Worker,确保MySQL数据更改时能自动更新到Redis缓存中。详细步骤包括安装配置各个组件,编写PHP脚本,设置MySQL触发器以及使用Gearman进行任务分发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

运维实战 Redis与Mysql的业务衔接

Redis与MqSQL业务衔接

需要准备3台服务器

  • Server1开启redis
  • Server2安装phpnginx模拟同步信息用的数据用的Client
  • Server3安装mariadb充当mysql

业务逻辑是这样的, 写入mysql的数据通过Server2同步给redis

Server2上的操作

##编译安装nginx的过程略过

##安装php-fpm
[root@Server2 ~]# cd rhel7/
[root@Server2 rhel7]# yum install -y php-* libgearman-* libevent-*
[root@Server2 rhel7]# systemctl start php-fpm.service

##查看端口情况
[root@Server2 rhel7]# netstat -antulp  ##查看是否开启相关端口
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      4121/php-fpm: maste 

打开nginx配置文件中的对于php的相关支持

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
	root           html;
	fastcgi_pass   127.0.0.1:9000;
	fastcgi_index  index.php;
	#fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
	include        fastcgi.conf;
}

Server1上安装Redis并保持为MASTER

Server3上安装Mariadb

[root@Server2 ~]# cd rhel7
[root@Server2 rhel7]# ll test.php 
-rw-r--r-- 1 root root 1369 Apr 16 10:34 test.php

##复制测试文件到nginx默认发布目录
##并修改其内容
[root@Server2 rhel7]# cp test.php /usr/local/nginx/html/
[root@Server2 rhel7]# cd /usr/local/nginx/html/
[root@Server2 html]# vim test.php 

<?php
        $redis = new Redis();
        $redis->connect('172.25.5.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('172.25.5.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;
                }

在Server3上授权远程用户登录

[root@Server3 local]# mysql
MariaDB [(none)]> show databases;
MariaDB [(none)]> grant all on test.* to redis@'%' identified by 'westos'; 

##拷贝测试数据到Server3并导入数据库
[root@Server2 rhel7]# scp test.sql Server3: 
[root@Server3 ~]# mysql < test.sql

进行简单测试

root@Server3 ~]# mysql
MariaDB [(none)]> use test
MariaDB [test]> show tables;
MariaDB [test]> select * from test;

[root@Server1 ~]# redis-cli
127.0.0.1:6379> get 1
"test1"
127.0.0.1:6379> get 2
"test2"

在这里插入图片描述

发现可以正确取到信息.

不足与问题

  • 第一次访问时, 由于Redis中没有缓存, 看不到数据库中的值
  • 刷新页面后能够看到
  • 但是当更改MySQL内容后并不能反映在Redis上,这显然是不满足业务需求的
  • 必须删除Redis中已经存储的值, 再次刷新页面才能将新内容写入

实现自动同步

这里我们需要借助Gearman来进行数据同步.

Gearman是一个支持分布式的任务分发框架,分为Gearman Job Server, Gearman Job Server, Gearman Worker三个组成部分

工作流程

  • 编写MySQL触发器, 当出现插入修改操作时创建任务
  • 通过lib_mysqludf_json-udf库函数将关系数据映射为JSON格式
  • 通过gearman-mysql-udf插件将任务加入Gearman的队列中
  • 通过redis_worker.php完成数据库的更新

Server3操作

unzip lib_mysqludf_json-master.zip
cd lib_mysqludf_json-master/
yum install -y mysql-devel gcc

$$生成so文件
gcc $(mysql_config --cflags) -shared -fPIC -o lib_mysqludf_json.so lib_mysqludf_json.c

##拷贝安装
cp lib_mysqludf_json.so /usr/lib64/mysql/plugin/


##查看数据库的模块目录
mysql> show global variables like 'plugin_dir';
+---------------+-------------------------+
| Variable_name | Value |
+---------------+-------------------------+
| plugin_dir | /usr/lib64/mysql/plugin |
+---------------+-------------------------+

##注册添加该函数
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 |
+--------------------+-----+-------------------------+----------+

##编译安装gearman-mysql-udf
yum install -y libgearman-* libevent-devel-2.0.21-4.el7.x86_64.rpm
tar zxf gearman-mysql-udf-0.6.tar.gz
cd gearman-mysql-udf-0.6
./configure --libdir=/usr/lib64/mysql/plugin/
make
make install

##注册libgearman_mysql_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 |
+--------------------+-----+-------------------------+----------+

##指定Gearman的Server端
mysql> SELECT gman_servers_set('172.25.5.2:4730');

需要注意的是

  • GearmanServer端只负责接受MqSQL更改情况,不负责处理
  • 处理的流程交给Worker进程来处理

在Server2上配置GearmanWorker

[root@Server2 rhel7]# yum install -y gearmand-1.1.12-18.el7.x86_64.rpm
[root@Server2 rhel7]# systemctl start gearmand.service
[root@Server2 rhel7]# netstat -antlp | grep 4730
tcp        0      0 0.0.0.0:4730            0.0.0.0:*               LISTEN      19099/gearmand      
tcp6       0      0 :::4730                 :::*                    LISTEN      19099/gearmand      
[root@Server2 rhel7]# vim worker.php

<?php
$worker = new GearmanWorker();
$worker->addServer();
$worker->addFunction('syncToRedis', 'syncToRedis');
 
$redis = new Redis();
$redis->connect('172.25.5.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);
}
?>

[root@Server2 rhel7]# php -m | grep redis
redis
[root@Server2 rhel7]# nohup php worker.php &

在Server3上配置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

[root@Server3 ~]# mysql
MariaDB [(none)]> SHOW TRIGGERS FROM test;
MariaDB [(none)]> use test
MariaDB [test]> update test set name='NeuWings' where id=1;

此时在Server1上可以看到变化了

[root@Server1 ~]# redis-cli
127.0.0.1:6379> get 1
"NeuWings"

同样的,网页端也可以同步更新数据.
在这里插入图片描述

部分操作流程

MariaDB [test]> SHOW TRIGGERS FROM test;
+-------------+--------+-------+----------------------------------------------------------------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+
| Trigger     | Event  | Table | Statement                                                                                                      | Timing | Created | sql_mode | Definer        | character_set_client | collation_connection | Database Collation |
+-------------+--------+-------+----------------------------------------------------------------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+
| 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 | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
+-------------+--------+-------+----------------------------------------------------------------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+
1 row in set (0.00 sec)

MariaDB [test]> update test set name = 'Test1' where id =1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

MariaDB [test]> SELECT gman_servers_set('172.25.5.2:4730');
+-------------------------------------+
| gman_servers_set('172.25.5.2:4730') |
+-------------------------------------+
| 172.25.5.2:4730                     |
+-------------------------------------+
1 row in set (0.00 sec)

MariaDB [test]> exit
Bye
[root@Server4 ~]# systemctl restart mariadb.service 
[root@Server4 ~]# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 2
Server version: 5.5.60-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> update test set name = 'Test' where id =1;
ERROR 1046 (3D000): No database selected
MariaDB [(none)]> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [test]> update test set name = 'Test' where id =1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

MariaDB [test]> SELECT gman_servers_set('172.25.5.2:4730');
+-------------------------------------+
| gman_servers_set('172.25.5.2:4730') |
+-------------------------------------+
| 172.25.5.2:4730                     |
+-------------------------------------+
1 row in set (0.00 sec)

MariaDB [test]> SHOW TRIGGERS FROM test;
+-------------+--------+-------+----------------------------------------------------------------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+
| Trigger     | Event  | Table | Statement                                                                                                      | Timing | Created | sql_mode | Definer        | character_set_client | collation_connection | Database Collation |
+-------------+--------+-------+----------------------------------------------------------------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+
| 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 | utf8                 | utf8_general_ci      | latin1_swedish_ci  |
+-------------+--------+-------+----------------------------------------------------------------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+
1 row in set (0.00 sec)

MariaDB [test]> 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)

MariaDB [test]> SELECT gman_servers_set('172.25.5.2:4730');
+-------------------------------------+
| gman_servers_set('172.25.5.2:4730') |
+-------------------------------------+
| 172.25.5.2:4730                     |
+-------------------------------------+
1 row in set (0.00 sec)

MariaDB [test]> update test set name = 'westos' where id =1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
<think>好的,我现在要分析用户的问题,他想了解Redis和Cassandra组合在爬虫数据存储中的适用场景、优劣分析以及实际应用。首先,我需要回顾之前的对话,确保回答符合用户之前的提问和我的回答内容。 用户之前询问了爬虫使用哪种数据库好,我推荐了MySQL、MongoDB、Redis等,并提到了混合架构,比如Redis做缓存加其他数据库持久化。现在用户进一步想了解Redis和Cassandra的组合,特别是在爬虫中的优势和实践。 接下来,我需要参考用户提供的引用内容。引用[1]提到Redis用于去重和缓存,Cassandra用于存储海量数据。引用[2]中的案例显示他们用Cassandra存储原始数据,结合Kafka和RabbitMQ处理消息。引用[4]提到了NoSQL数据库的分类,Cassandra属于列存储,Redis是键值存储。 首先,我需要明确Redis和Cassandra各自的特点。Redis是内存数据库,读写速度快,适合临时数据和缓存;Cassandra是分布式列存储,适合海量数据和高可用性。结合两者的优势,可能在爬虫中用于不同的环节,比如Redis处理实时去重和任务队列,Cassandra存储大量爬取的数据。 接下来,适用场景方面,用户提到可能用于爬虫数据存储。需要分析这种组合在什么情况下适用,比如大规模爬虫需要高速写入和持久化存储,同时需要高效的实时查询和去重。优势可能包括高吞吐量、扩展性、灵活的数据模型,劣势可能有系统复杂性、数据一致性问题等。 然后,实践部分需要给出具体的实现方案,比如使用Redis进行URL管理和去重,Cassandra存储爬取结果。可能需要代码示例,比如使用Redis的集合或布隆过滤器进行去重,Cassandra的写入操作。 还要考虑用户提到的引用中的案例,比如引用[2]中的Cassandra集群存储网页数据,结合消息中间件。这可能涉及到数据分发的架构设计,如何将Redis处理后的数据转移到Cassandra中。 最后,需要确保回答结构清晰,分点列出优势、劣势、适用场景和实践方案,并引用提供的参考文献。同时,生成相关的问题,帮助用户深入思考。</think>### Redis + Cassandra 组合在爬虫数据存储中的深度分析 #### 一、**组合核心定位适用场景** **1. 典型爬虫需求痛点** - **高速写入**:分布式爬虫需处理百万级 URL/数据写入 - **持久化存储**:海量网页原始数据(HTML/JSON)需长期存储 - **实时去重**:避免重复抓取(URL 去重、内容指纹比对) - **高可用性**:集群容错自动故障恢复 **2. 组合适用场景** - **超大规模爬虫**(日抓取量 > 1 亿条) - **动态数据流处理**(如实时新闻、社交媒体流) - **混合架构需求**:短期高频操作 + 长期冷数据存储 --- #### 二、**技术优势分工** | 组件 | 核心角色 | 性能指标(参考) | 爬虫场景中的典型应用 | |-----------|-----------------------------------------|--------------------------------|--------------------------------------| | **Redis** | 实时数据处理层 | 读写吞吐量 $10^5$次/秒[^1] | URL 去重、任务队列、临时缓存 | | **Cassandra** | 持久化存储层 | 单集群支持 PB 级数据[^2] | 网页原始数据、结构化结果存储 | **分工逻辑**: 1. **Redis 处理热数据** - 使用 `SET`/`HyperLogLog` 实现 URL 去重,内存操作降低延迟[^1] - 通过 `List` 或 `Stream` 管理分布式爬虫的任务队列 ```python # Redis 去重示例 import redis r = redis.Redis() if r.sadd('crawled_urls', url) == 1: r.lpush('task_queue', url) # 新 URL 加入队列 ``` 2. **Cassandra 存储冷数据** - 利用 **宽列存储** 特性高效保存网页原始内容(含 HTML/JSON 等非结构化数据) - 通过 **分区键设计** 实现按时间/域名等维度的快速扫描 ```python # Cassandra 数据写入示例 from cassandra.cluster import Cluster cluster = Cluster(['node1', 'node2']) session = cluster.connect('crawler_db') session.execute(""" INSERT INTO pages (domain, url, content, timestamp) VALUES (%s, %s, %s, %s) """, ("example.com", "/page1", "<html>...", 1717020800)) ``` --- #### 三、**组合优势详解** 1. **性能互补** - **Redis**:毫秒级响应任务调度去重操作(避免 Cassandra 的 SSTable 压缩延迟) - **Cassandra**:线性扩展能力支撑海量数据存储(单节点故障不影响集群)[^2] 2. **成本优化** - Redis 仅需较小内存容量处理热数据,降低硬件成本 - Cassandra 使用廉价 HDD 实现冷数据存储( Hadoop 生态兼容) 3. **架构灵活性** - **数据生命周期管理**: ```mermaid graph LR A[爬虫节点] --> B(Redis: 去重+队列) B --> C{Cassandra: 原始数据存储} C --> D[数据分析平台] ``` - **无缝衔接流处理框架**(如 Kafka → Redis → Cassandra)[^2] --- #### 四、**潜在缺陷应对方案** | 挑战 | 解决方案 | |---------------------------|--------------------------------------------------------------------------| | **数据一致性风险** | - Redis 异步持久化 + Cassandra Quorum 写入[^4] | | **运维复杂度高** | - 使用 Kubernetes 统一管理容器化集群 | | **Cassandra 查询限制** | - 配合 Elasticsearch 建立二级索引(如全文搜索)[^2] | **典型容灾方案**: - Redis:启用 `AOF` + `RDB` 混合持久化,配置哨兵模式(Sentinel) - Cassandra:设置 `NetworkTopologyStrategy` 跨机房复制 --- #### 五、**实践案例参考** 某电商价格监控系统架构(日处理 2.3 亿页面)[^2]: 1. **数据流**: - 爬虫节点 → Redis 去重 → Kafka 分流 → Cassandra 存储 → Spark 分析 2. **关键配置**: - Redis Cluster(6 节点,32GB 内存/节点) - Cassandra(24 节点,3 数据中心部署) 3. **性能指标**: - 去重吞吐量:$1.2 \times 10^5$ 次/秒 - 数据写入延迟:Cassandra 平均 15ms --- ### 相关问题 1. 如何设计 Cassandra 的分区键以优化爬虫数据查询效率? 2. Redis 集群哨兵模式在爬虫系统中的取舍? 3. 如何利用 Cassandra 的 TTL 特性实现爬虫数据自动清理?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值