基於redis mysql php的簡單佇列實現

2021-08-04 07:15:17 字數 2771 閱讀 1611

訊息佇列在是分布式系統中必不可少的中介軟體,目前在生產環境,使用較多的訊息佇列有activemq,rabbitmq,kafka,rocketmq等。然而對於乙個要求不高的小型系統來說,單獨使用維護這些佇列系統代價有點大。而redis可以在做快取的同時也滿足佇列的需求。redis的list是有序的列表,加上其出隊入隊函式,利用其特性很簡單的就能實現乙個訊息佇列。

一、業務層郵件入佇列

入佇列使用redis的lpush指令

lpush key value1 [value2]

將乙個或多個值插入到列表頭部

先將郵件詳情寫入mysql儲存,再將該郵件id push到redis佇列頭部

function sendsysmail($userid, $type, $content)

else

}二、後台佇列監聽

後台執行乙個php程序,監聽佇列,對佇列迴圈進行出佇列操作。一旦佇列有資料,就從mysql中取對應的郵件詳細情況進行傳送。

出隊操作使用brpop命令

brpop key1 [key2 ] timeout

移出並獲取列表的最後乙個元素,

如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素為止。

使用過程中發生了件奇怪的事情,後台程序開啟後開始執行的好好的,並沒有什麼異常,但跑了一晚上,第二天再來看時便不正常了。

看了下redis的資料,都正常的出入佇列了,但是郵件並未傳送,日誌中也沒有傳送失敗的記錄。

一番折騰,發現是mysql連線這塊存在問題,mysql預設的連線超時時間是28800秒,即8小時,超過8小時,mysql連線就斷開了,過了一晚上,mysql自然就go away了。

於是在沒有佇列沒有資料的時候執行select 1來延長mysql連線的超時時間點,select 1執行異常時重新建立乙個mysql的連線替換之前的連線,以此來保持mysql的連線始終可用。

<?php

$config = include('config.php');

$redis = new redis();

$redis->connect($config['redis_host'], $config['redis_port']);

$pdo= new pdo($config['dsn'], $config['db_user'], $config['db_pwd'], array(pdo::attr_errmode => pdo::errmode_exception));

while (true)";

$res = $pdo->query($sql);

foreach ($res as $row)

else

}}else

catch (pdoexception $e) }

}?>

三、佇列監聽程式的守護程序

用shell寫的守護程序,方便佇列監聽程式的開啟關閉以及狀態檢視

#!/bin/bash#開啟

function start()

'`if [ "$pid" == "" ]

then

php -f mailqueue.php >> maillog &

echo "程式啟動成功"

else

echo "程式已經開啟過"fi}

#關閉function stop()

'`if [ "$pid" == "" ]

then

echo "程式未開啟"

else

kill -9 $pid

echo "程式關閉成功"fi}

#檢視開啟狀態

function status()

'`if [ "$pid" == "" ]

then

echo "程式未開啟"

else

echo "程式執行中,pid: $pid"fi}

#主程式

case "$1" in

"start")

start

;;"stop" )

stop

;;* )

echo "引數錯誤! usage: mailqueue [start|stop|status]";;

esac

四、執行演示

1.使用守護程序指令碼啟動佇列後台監聽程序

2.資料庫中新增一條測試資料

3.redis手動入隊資料,模擬業務入隊

4.檢視郵件傳送日誌

五、總結

這是乙個很簡單的訊息佇列程式,實現了訊息佇列最基本的功能。但要想穩定執行還有很多需要優化處理的地方。

1.程式只考慮了最簡單的狀況,對於郵件傳送失敗的情況只是打了日誌,並未做任何處理。可以在資料庫郵件詳情表增加記錄郵件傳送失敗次數的字段。郵件傳送失敗後,累加記錄失敗次數,設定乙個最大失敗次數,小於最大失敗次數則重新入佇列,再次傳送。直到達到最大失敗次數之後不再傳送,以此來提高郵件的傳送成功率。

2.重新啟動後資料的恢復,redis本身有完善資料備份機制,這點可以通過redis本身機制來實現。

AspectJ基於xml和基於註解

一 基於xml 執行的切入點中具體方法有返回值,則方法結束會立即執行後置通知,然後再執行環繞通知的放行之後的 2 連線點即所有可能的方法,切入點是正真被切的方法,連線點方法名 其中,只有環繞通知的切入點引數不一樣,是可以放行的切入點 3 異常通知是處理異常 切面類中的異常通知的方法引數列表中異常引數...

拓撲排序(基於dfs 基於佇列)

dfs函式的返回值表示是否成環,若存在有向環,則不存在拓撲排序。不包含有向環的有向圖稱為有向無環圖 dag 可以借助dfs完成拓撲排序,在訪問完乙個結點時把他加入當前拓撲序的首部。舉個栗子 比如乙個 1,2 1,3 2,3 的有向無環圖,就先搜尋1,再遞迴搜尋2,再搜尋3,3沒有出度了,於是放進拓撲...

基於insert update delete的注入

inset注入原理 所謂inset注入就是指我們前端註冊的資訊會被後台通過insert操作插入到資料庫裡邊去,若此時後台沒有做出相應的處理就會構成insert注入。insert注入方法 insert用法例如 insert into member username,pw,phonenum,email,...