Redis的链表List可以用来做链表,高并发的特性非常适合做分布式的并行消息传递。
项目地址:https://github.com/huyanping/Zebra-PHP-Framework
左进右出
1
2
|
$redis
->lPush(
$key
,
$value
);
$redis
->rPop(
$key
);
|
以下程序已在生产环境中正式使用。
基于Redis的PHP消息队列封装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
<?php
/**
* Created by PhpStorm.
* User: huyanping
* Date: 14-8-19
* Time: 下午12:10
*
* 基于Redis的消息队列封装
*/
namespace
Zebra\MessageQueue;
class
RedisMessageQueue
implements
IMessageQueue
{
protected
$redis_server
;
protected
$server
;
protected
$port
;
/**
* @var 消息队列标志
*/
protected
$key
;
/**
* 构造队列,创建redis链接
* @param $server_config
* @param $key
* @param bool $p_connect
*/
public
function
__construct(
$server_config
=
array
(
'IP'
=>
'127.0.0.1'
,
'PORT'
=>
'6379'
),
$key
=
'redis_message_queue'
,
$p_connect
= false)
{
if
(
empty
(
$key
))
throw
new
\Exception(
'message queue key can not be empty'
);
$this
->server =
$server_config
[
'IP'
];
$this
->port =
$server_config
[
'PORT'
];
$this
->key =
$key
;
$this
->check_environment();
if
(
$p_connect
) {
$this
->pconnect();
}
else
{
$this
->connect();
}
}
/**
* 析构函数,关闭redis链接,使用长连接时,最好主动调用关闭
*/
public
function
__destruct()
{
$this
->close();
}
/**
* 短连接
*/
private
function
connect()
{
$this
->redis_server =
new
\Redis();
$this
->redis_server->connect(
$this
->server,
$this
->port);
}
/**
* 长连接
*/
public
function
pconnect()
{
$this
->redis_server =
new
\Redis();
$this
->redis_server->pconnect(
$this
->server,
$this
->port);
}
/**
* 关闭链接
*/
public
function
close()
{
$this
->redis_server->close();
}
/**
* 向队列插入一条信息
* @param $message
* @return mixed
*/
public
function
put(
$message
)
{
return
$this
->redis_server->lPush(
$this
->key,
$message
);
}
/**
* 向队列中插入一串信息
* @param $message
* @return mixed
*/
public
function
puts(){
$params
= func_get_args();
$message_array
=
array_merge
(
array
(
$this
->key),
$params
);
return
call_user_func_array(
array
(
$this
->redis_server,
'lPush'
),
$message_array
);
}
/**
* 从队列顶部获取一条记录
* @return mixed
*/
public
function
get()
{
return
$this
->redis_server->lPop(
$this
->key);
}
/**
* 选择数据库,可以用于区分不同队列
* @param $database
*/
public
function
select(
$database
)
{
$this
->redis_server->select(
$database
);
}
/**
* 获得队列状态,即目前队列中的消息数量
* @return mixed
*/
public
function
size()
{
return
$this
->redis_server->lSize(
$this
->key);
}
/**
* 获取某一位置的值,不会删除该位置的值
* @param $pos
* @return mixed
*/
public
function
view(
$pos
)
{
return
$this
->redis_server->lGet(
$this
->key,
$pos
);
}
/**
* 检查Redis扩展
* @throws Exception
*/
protected
function
check_environment()
{
if
(!\
extension_loaded
(
'redis'
)) {
throw
new
\Exception(
'Redis extension not loaded'
);
}
}
}
|
如果需要一次写入多个队列,可以使用如下调用方式:
1
2
3
4
|
<?php
$redis
=
new
RedisMessageQueue();
$redis
->puts(1, 2, 3, 4);
$redis
->puts(5, 6, 7, 8, 9);
|
模仿HTTPSQS输出结果的封装如下,提供了写入位置和读取位置记录的功能:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
<?php
/**
* Created by PhpStorm.
* User: huyanping
* Date: 14-9-5
* Time: 下午2:16
*
* 附加了队列状态信息的RedisMessageQueue
*/
namespace
Zebra\MessageQueue;
class
RedisMessageQueueStatus
extends
RedisMessageQueue {
protected
$record_status
;
protected
$put_position
;
protected
$get_position
;
public
function
__construct(
$server_config
=
array
(
'IP'
=>
'127.0.0.1'
,
'PORT'
=>
'6379'
),
$key
=
'redis_message_queue'
,
$p_connect
= false,
$record_status
=true
){
parent::__construct(
$server_config
,
$key
,
$p_connect
);
$this
->record_status =
$record_status
;
$this
->put_position =
$this
->key .
'_put_position'
;
$this
->get_position =
$this
->key .
'_get_position'
;
}
public
function
get(){
if
(
$queue
= parent::get()){
$incr_result
=
$this
->redis_server->incr(
$this
->get_position);
if
(!
$incr_result
)
throw
new
\Exception(
'can not mark get position,please check the redis server'
);
return
$queue
;
}
else
{
return
false;
}
}
public
function
put(
$message
){
if
(parent::put(
$message
)){
$incr_result
=
$this
->redis_server->incr(
$this
->put_position);
if
(!
$incr_result
)
throw
new
\Exception(
'can not mark put position,please check the redis server'
);
return
true;
}
else
{
return
false;
}
}
public
function
puts_status(){
$message_array
= func_get_args();
$result
= call_user_func_array(
array
(
$this
,
'puts'
),
$message_array
);
if
(
$result
){
$this
->redis_server->incrBy(
$this
->put_position,
count
(
$message_array
));
return
true;
}
return
false;
}
public
function
size(){
return
$this
->redis_server->lSize(
$this
->key);
}
public
function
status(){
$status
[
'put_position'
] = (
$put_position
=
$this
->redis_server->get(
$this
->put_position)) ?
$put_position
: 0;
$status
[
'get_position'
] = (
$get_position
=
$this
->redis_server->get(
$this
->get_position)) ?
$get_position
: 0;
$status
[
'unread_queue'
] =
$this
->size();
$status
[
'queue_name'
] =
$this
->key;
$status
[
'server'
] =
$this
->server;
$status
[
'port'
] =
$this
->port;
return
$status
;
}
public
function
status_normal(){
$status
=
$this
->status();
$message
=
'Redis Message Queue'
. PHP_EOL;
$message
.=
'-------------------'
. PHP_EOL;
$message
.=
'Message queue name:'
.
$status
[
'queue_name'
] . PHP_EOL;
$message
.=
'Put position of queue:'
.
$status
[
'put_position'
] . PHP_EOL;
$message
.=
'Get position of queue:'
.
$status
[
'get_position'
] . PHP_EOL;
$message
.=
'Number of unread queue:'
.
$status
[
'unread_queue'
] . PHP_EOL;
return
$message
;
}
public
function
status_json(){
return
\json_encode(
$this
->status());
}
}
|