太坑了!RabbitMQ+PHP开发的辛酸经历

server/2024/9/24 6:17:30/

博主介绍:全网粉丝10w+、CSDN合伙人、华为云特邀云享专家,阿里云专家博主、星级博主,51cto明日之星,热爱技术和分享、专注于Java技术领域
🍅文末获取源码联系🍅
👇🏻 精彩专栏推荐订阅👇🏻 不然下次找不到哟

大家好,我是小寒,一个热爱编程和分享的开发者。今天我想和大家聊聊我在使用RabbitMQ和PHP进行开发时的一些辛酸经历。如果你也正在或者即将使用RabbitMQ和PHP,希望我的经历能对你有所帮助,避免走一些弯路。

在这里插入图片描述

初识RabbitMQ

刚接触RabbitMQ的时候,我对它的功能和优势充满了期待。作为一个强大的消息中间件,RabbitMQ可以处理高并发的消息传递,支持多种协议和编程语言,对于分布式系统和微服务架构有很大的帮助。

一开始,我兴致勃勃地下载并安装了RabbitMQ,按照官方文档配置了环境。安装过程相对顺利,我还庆幸这次可能不会遇到太多问题。然而,现实总是和想象有很大差距。

初步配置的挫折

RabbitMQ的配置文件非常复杂,参数繁多。我试图按照官方文档进行配置,但文档并不友好,对新手不够友善。尤其是在处理一些高级配置时,文档缺乏详细的解释和实例。

经过一番摸索,我终于成功启动了RabbitMQ服务,但连接时却遇到了问题。无论我怎么修改配置,总是报错。经过数小时的搜索和调试,终于发现是因为防火墙的问题。原来,RabbitMQ使用的端口没有被正确开放,这导致我的客户端无法连接上服务端。

与PHP的整合

解决了RabbitMQ的初步配置问题后,我开始着手将其与PHP进行整合。RabbitMQ提供了多种语言的客户端库,但对于PHP来说,官方推荐的是php-amqplib。这是一个功能强大的库,但文档依然是个大问题。

基本的消息发送和接收

在编写代码时,我遇到了无数的坑。例如,如何正确地处理连接失败、如何确保消息的持久化、如何处理消息的确认机制等。这些问题都需要大量的时间和精力去研究和解决。

以下是一个简单的例子,展示如何使用php-amqplib进行消息发送和接收:

php"><?php
require_once __DIR__ . '/vendor/autoload.php';use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;// 建立连接
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();// 声明队列
$channel->queue_declare('hello', false, false, false, false);// 发送消息
$msg = new AMQPMessage('Hello World!');
$channel->basic_publish($msg, '', 'hello');echo " [x] Sent 'Hello World!'\n";$channel->close();
$connection->close();
?>

上面的代码展示了如何连接RabbitMQ服务器并发送一条消息。尽管看起来很简单,但在实际项目中,我们需要处理更多的细节。

消息接收端

php"><?php
require_once __DIR__ . '/vendor/autoload.php';use PhpAmqpLib\Connection\AMQPStreamConnection;$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();$channel->queue_declare('hello', false, false, false, false);echo " [*] Waiting for messages. To exit press CTRL+C\n";$callback = function ($msg) {echo ' [x] Received ', $msg->body, "\n";
};$channel->basic_consume('hello', '', false, true, false, false, $callback);while ($channel->is_consuming()) {$channel->wait();
}$channel->close();
$connection->close();
?>

上面的代码展示了如何从队列中接收消息,并使用回调函数处理接收到的消息。

性能调优的挑战

在解决了基本的功能问题后,我开始关注性能调优。毕竟,RabbitMQ的一个重要优势就是高性能。然而,在实际使用中,我发现性能并没有预期的那么好。

使用连接池

首先是连接池的问题。每次请求都重新建立连接会导致性能下降。我尝试使用连接池来复用连接,但在PHP中实现连接池并不是一件容易的事。以下是一个简单的连接池实现示例:

php">class ConnectionPool
{private $connections = [];private $maxConnections;public function __construct($maxConnections = 10){$this->maxConnections = $maxConnections;}public function getConnection(){if (empty($this->connections)) {return new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');} else {return array_pop($this->connections);}}public function releaseConnection($connection){if (count($this->connections) < $this->maxConnections) {$this->connections[] = $connection;} else {$connection->close();}}
}

消息的处理速度

其次是消息的处理速度。在高并发的情况下,RabbitMQ的性能瓶颈很容易显现出来。我不得不深入研究RabbitMQ的工作原理,尝试各种优化手段,例如调整队列的预取数量、使用消息批量确认等,才最终解决了这个问题。

php">$channel->basic_qos(null, 10, null); // 设置预取数量

日志和监控的烦恼

在开发和调试过程中,日志和监控是必不可少的工具。然而,RabbitMQ的日志配置和查看也是一个让人头疼的问题。默认的日志级别和格式并不能满足我的需求,我不得不手动修改配置文件,增加自定义的日志记录。

监控方面,RabbitMQ提供了一个管理插件,可以通过Web界面查看各种统计信息。然而,这个插件默认没有启用,需要手动安装和配置。

rabbitmq-plugins enable rabbitmq_management

启用管理插件后,可以通过http://localhost:15672访问RabbitMQ管理界面。

实际项目中的血泪教训

在一个实际项目中,我们需要处理大量的订单消息,这对RabbitMQ和PHP的稳定性和性能提出了很高的要求。刚开始的一段时间,一切似乎都很顺利,但很快问题就暴露出来。

消息的丢失问题

尽管我们启用了消息持久化和确认机制,但在高并发的情况下,仍然有部分消息丢失。经过深入排查,发现是因为网络波动和服务器资源不足导致的。为了解决这个问题,我们不得不增加服务器资源,并对网络进行优化。

php">$msg = new AMQPMessage('Hello World!', ['delivery_mode' => 2]); // 持久化消息

消息的重复消费

在某些情况下,RabbitMQ会重复发送消息,导致同一个订单被处理多次。这不仅增加了系统的负担,还可能引发数据的一致性问题。为了解决这个问题,我们引入了幂等性设计,确保每条消息只会被处理一次。

php">$callback = function ($msg) {$orderId = $msg->body;if (!isProcessed($orderId)) {processOrder($orderId);markAsProcessed($orderId);}
};

性能瓶颈

随着业务量的增加,RabbitMQ和PHP的性能瓶颈逐渐显现出来。为了提高系统的吞吐量,我们进行了多次优化,包括调整RabbitMQ的配置、优化PHP代码、增加服务器资源等。

# 优化RabbitMQ配置
vm_memory_high_watermark.relative = 0.8
disk_free_limit.absolute = 500MB

总结

通过这次RabbitMQ+PHP开发的经历,我深刻体会到开发过程中遇到的种种困难和挑战。尽管RabbitMQ作为一款强大的消息中间件有很多优势,但在实际使用中也有很多需要注意的地方。希望我的经历能对大家有所帮助,避免走一些弯路。

最后,还是要提醒大家,在选择技术方案时一定要充分评估其优缺点,并做好充分的准备。不要盲目跟风,只有选择适合自己项目的技术,才能事半功倍。

我是小寒,感谢大家的阅读。如果你对RabbitMQ和PHP有任何疑问或者经验分享,欢迎在评论区留言,我们一起讨论,共同进步!

大家点赞、收藏、关注、评论啦 、查看👇🏻获取联系方式👇🏻


http://www.ppmy.cn/server/95610.html

相关文章

《Unity3D网络游戏实战》学习与实践--制作一款大乱斗游戏

角色类 基类Base Human是基础的角色类&#xff0c;它处理“操控角色”和“同步角色”的一些共有功能&#xff1b;CtrlHuman类代表“操控角色”​&#xff0c;它在BaseHuman类的基础上处理鼠标操控功能&#xff1b;SyncHuman类是“同步角色”类&#xff0c;它也继承自BaseHuman&…

计时器(Python)

代码 import time from tkinter import ttk import threading from tkinter import scrolledtext import tkinter as tkclass TimerApp:def __init__(self, root):self.root rootself.root.title("计时器")self.screen_w, self.screen_h self.root.winfo_screenwi…

Mybatis面试

Mybatis 面试 1、Mybatis 的执行流程是什么&#xff1f; 1、读取MyBatis配置文件&#xff1a;mybatis-config.xml 加载运行环境 和 映射文件 2、构造会话工厂 SqlSessionFactory &#xff08;全局只有一个&#xff09; 3、会话工厂创建SqlSession对象&#xff08;项目与数据…

【c++】爬虫到底违不违法?

很多小伙伴都想知道爬虫到底违法吗&#xff0c;今天博主就给大家科普一下 爬虫本身并不违法&#xff0c;但使用爬虫采集数据可能涉及违法风险&#xff0c;具体取决于采集行为是否侵犯了他人的合法权益&#xff0c;尤其是隐私权和个人信息权。以下是对爬虫是否违法的详细分析&am…

C# 6.定时器 timer

使用控件&#xff1a; 开启定时器&#xff1a;timer1.Start(); 关闭定时器&#xff1a;timer1.Stop(); 定时间时间间隔:Interval timer1.Interval 1000; Interva等于1000是每一秒刷新一次 定时器默认时间间隔是100ms 代码创建定时器 ①创建 Timer t1 new Timer(); …

项目实战_表白墙(升级版)

你能学到什么 表白墙&#xff08;升级版&#xff09;Mybatis的一些简单应用 正文 前⾯的案例中, 我们写了表⽩墙, 但是⼀旦服务器重启, 数据就会丢失. 要想数据不丢失, 需要把数据存储在数据库中&#xff0c;接下来咱们借助MyBatis来实现数据库的操作。 数据准备 如果我们…

sais复杂推理能力评估笔记(一):baseline简介

赛题流程 初赛数据集为逻辑推理数据&#xff0c;其中训练集中包含500条训练数据&#xff0c;测试集中包含500条测试数据。每个问题包括若干子问题&#xff0c;每个子问题为单项选择题&#xff0c;选项不定&#xff08;最多5个&#xff09;。目标是为每个子问题选择一个正确答案…

【c++】用C++制作一个简易windows系统

源码: #include <iostream> #include <cstdlib> // 为了使用system #include<limits> void clearScreen() {system("cls"); }void displayMenu() {clearScreen();std::cout << "1.我的文件" << std::endl;std::cout <&…