Redis คิว
Redis คิวเป็นระบบจัดการข้อความที่ใช้ Redis เป็นฐานข้อมูล เพื่อรองรับการประมวลผลข้อความที่มีความช้า
การติดตั้ง
composer require webman/redis-queue
ไฟล์การกำหนดค่า
ไฟล์การกำหนดค่า Redis ถูกสร้างขึ้นที่ config/plugin/webman/redis-queue/redis.php
มีเนื้อหาที่คล้ายกันกับตัวอย่างต่อไปนี้:
<?php
return [
'default' => [
'host' => 'redis://127.0.0.1:6379',
'options' => [
'auth' => '', // รหัสผ่านที่เป็นตัวเลือก
'db' => 0, // ฐานข้อมูล
'max_attempts' => 5, // จำนวนครั้งในการลอง
'retry_seconds' => 5, // ช่วงเวลาในการลองอีกครั้ง หน่วยวินาที
]
],
];
การลองทำการกระทำอีกครั้งเมื่อล้มเหลว
ถ้าการกระทำล้มเหลว (เกิดข้อผิดพลาด) ข้อความจะถูกนำเข้าไปยังคิวที่ล่าช้าและรอการกระทำอีกครั้ง จำนวนครั้งในการลองใช้ได้จากพารามิเตอร์ max_attempts
และช่วงเวลาในการลองอีกครั้งจะได้จาก retry_seconds
อย่างเช่น max_attempts
เป็น 5, retry_seconds
เป็น 10, ช่วงเวลาในการลองอีกครั้งครั้งแรกคือ 1*10
วินาที, ครั้งที่ 2 คือ 2*10
วินาที, ครั้งที่ 3 คือ 3*10
วินาที และต่อไป โดยกรณีที่เกินจำนวนครั้งที่กำหนดไว้ยังทำการ ข้อความจะถูกนำไปยังควีลล้มเหลวที่มีชื่อว่า {redis-queue}-failed
การส่งข้อความ (ซิงโครนัส)
โปรดทราบ
จำเป็นต้องใช้ webman/redis >= 1.2.0, ต้องใช้งานภาคขยาย redis
<?php
namespace app\controller;
use support\Request;
use Webman\RedisQueue\Redis;
class Index
{
public function queue(Request $request)
{
// ชื่อคิว
$queue = 'send-mail';
// ข้อมูล, สามารถส่งแอเรย์ได้โดยตรง ไม่จำเป็นต้องดีซีเรียลไอ
$data = ['to' => 'tom@gmail.com', 'content' => 'hello'];
// ส่งข้อความ
Redis::send($queue, $data);
// ส่งข้อความที่ล่าช้า, ข้อความจะถูกดำเนินการหลังจาก 60 วินาที
Redis::send($queue, $data, 60);
return response('ทดสอบคิว Redis');
}
}
การส่งสำเร็จ Redis::send()
จะส่งค่า true มิฉะนั้นจะส่งค่า false หรือเกิดข้อผิดพลาด
เกร็ดความรู้
เวลาที่ข้อความที่ล่าช้าเป็นไปได้คำนึงถึงการผิดพลาดในการกระทำอีกครั้ง, เช่นการกระทำที่ช้ากว่าการผลิตโดยกำลังขยายคิวต่อไปซึ่งจะทำให้ข้อความเข้าสู่คิวในการทำอีกครั้ง วิธีการใช้งานหลักๆคือการเปิดผลิตภัณฑ์ขี้เสียหลายๆเรื่องให้ง่ายขึ้น<?php namespace app\controller;
use support\Request;
use Webman\RedisQueue\Client;
class Index
{
public function queue(Request $request)
{
// ชื่อคิว
$queue = 'send-mail';
// ข้อมูล, สามารถส่งแอเรย์ได้โดยตรง ไม่จำเป็นต้องดีซีเรียลไอ
$data = ['to' => 'tom@gmail.com', 'content' => 'hello'];
// ส่งข้อความ
Client::send($queue, $data);
// ส่งข้อความที่ล่าช้า, ข้อความจะถูกดำเนินการหลังจาก 60 วินาที
Client::send($queue, $data, 60);
return response('ทดสอบคิว Redis');
}
}
`Client::send()` ไม่มีค่าการส่งคืน, มันเป็นการส่งโดยอัตโนมัติทำให้ข้อความไปถึง Redis อย่างแน่นอน
> **เกร็ดความรู้**
> หลักการทำงานของ `Client::send()` คือการสร้างคิวในหน่วยความจำภายในเครื่อง และการส่งต่อข้อความโดยอัตโนมัติไปยัง Redis (การส่งเร็วแทบจะมีประมาณ 10,000 ข้อความต่อวินาที) หากโปรเซสร์หยุดทำงาน และคิวที่อยู่ในหน่วยความจำมันไม่ได้ส่งสิ้นสุด, จะทำให้ข้อความหายไปได้ `Client::send()` การส่งโดยอัตโนมัติเหมาะกับการส่งข้อความที่สำคัญน้อย
> **เกร็ดความรู้**
> `Client::send()` คือฟังก์ชันการส่งแบบอัสซิงโครนัส มันสามารถใช้ได้เฉพาะในสภาพแวดล้อมการทำงานของเวบมัน สำหรับสคริปต์ชนิด命令行โปรดใช้อินเตอเฟซการส่งที่ซิงโครนัส `Redis::send()`
## การส่งข้อความในโปรเจคอื่น
บางครั้งเวลาคุณอาจต้องการส่งข้อความไปยังคิวในโปรเจคอื่นและไม่สามารถใช้ `webman\redis-queue` คุณสามารถอ้างถึงฟังก์ชันต่อไปนี้เพื่อส่งข้อความไปยังคิว
```php
function redis_queue_send($redis, $queue, $data, $delay = 0) {
$queue_waiting = '{redis-queue}-waiting';
$queue_delay = '{redis-queue}-delayed';
$now = time();
$package_str = json_encode([
'id' => rand(),
'time' => $now,
'delay' => $delay,
'attempts' => 0,
'queue' => $queue,
'data' => $data
]);
if ($delay) {
return $redis->zAdd($queue_delay, $now + $delay, $package_str);
}
return $redis->lPush($queue_waiting.$queue, $package_str);
}
ซึ่งพารามิเตอร์ $redis
คืออินสแตนซ์ของ Redis เช่นการใช้งาน Redis คลาสการใช้ได้ดังตัวอย่างต่อไปนี้:
$redis = new Redis;
$redis->connect('127.0.0.1', 6379);
$queue = 'user-1';
$data= ['some', 'data'];
redis_queue_send($redis, $queue, $data);
การบริโภค
ไฟล์การกำหนดค่าสำหรับกระบวนการการบริโภคอยู่ที่ config/plugin/webman/redis-queue/process.php
ไดเรกทอรี่ของผู้บริโภคอยู่ที่ app/queue/redis/
การดำเนินการคำสั่ง php webman redis-queue:consumer my-send-mail
จะสร้างไฟล์ app/queue/redis/MyMailSend.php
โปรดทราบ
ถ้าคำสั่งไม่มีอาจาจะสร้างด้วยตนเอง
<?php
namespace app\queue\redis;
use Webman\RedisQueue\Consumer;
class MyMailSend implements Consumer
{
// ชื่อคิวที่จะบริโภค
public $queue = 'send-mail';
// ชื่อการเชื่อมต่อ, สอดคตุผลใน plugin/webman/redis-queue/redis.php ชื่อการเชื่อมต่อ`
public $connection = 'default';
// บริโภค
public function consume($data)
{
// ไม่จำเป็นต้องดีโซรีไอ
var_export($data); // ส่่งออก ['to' => 'tom@gmail.com', 'content' => 'hello']
}
}
โปรดทราบ
การบริโภคแล้วไม่มีการเกิดข้อผิดพลาด และขมริโภคการีรับว่าเป็นสำเร็จ, ไม่เช่นนั้นการบริโภคล้มเหลว จะถูกนำเข้าคิวที่ลองอีกครั้ง คิว Redis ไม่มีกลไก ack คุณสามารถเรียกคิวที่มันเป็นการ ack (ไม่มีการเกิดข้อผิดพลาดหรือข้อผิดพลาด) ถ้ากระบวนการการบริโภคต้องการทำเครื่องมือที่ไม่เสร็จสนิทคุณสามารถด่งตารายลุบออกความผิดพลาดเพื่อทำให้กระบวนการที่กำลังกระทำล้มเหลว ซึ่งแต่ทางทเ้อนทำอีกอย่าับถ้วนว่าม่ดีเหมือนกันเกร็ดความรู้
ผู้บริโภคสนับสนุนการทำงานในหลายเซิพเวอร์หลายกระบวน และข้อความที่แม่แน่นไม่ปรากฏซื้อสำหรับการบริโภคอีกครั้ง ข้อความที่ได้รับการบริโภคจะถูกยกเลิกอย่าบให้ยกเลิกด้วยตนเองเกรดความรู้
กระบวนการบริโภคสามารถบริโภคคิวหลาย ๆ และหลายคิว หมุนเวินให้เพิ่มท้ายคิวคือสิ่งที่ต้องการในการใช้งานคิวใหม่ไม่คงจำเป็นต้องแม้นการกำหนดค่าในprocess.php
แทนที่จะสมบรรทัดผู้บริโภคใหม่แค่ปรากฎในapp/queue/redis
ในหน้าตาชัให้เพื่มขอให้เรียนเขาว่า$queue
ลูกยของชนิดConsumer
เกรดความรู้
ผู้ใช้ของวินโดส จำเป็นต้องเรียกการบริโภค php windows.php เพื่อเรข้า webman หากไม่การี้เรเรเั้รดเขเข่เฒทาศัเข้ากระบวนการบริโภคกำหนดกระบวนการการบริโภคที่แตกต่างสำหรับคิวที่แตกต่างกัน
โดยปกติแล้ว ผู้บริโภคทั้งหมดใช้กระบวนการบริโภคเดียวกัน แต่บางครั้งเราอาจต้องการแยกผู้บริโภคของคิวบางชุดออก เช่น การบริโภคธุรกิจที่ช้านำเข้ากรุ๊ปละเอียดเป็นหมู่อีกของที่ผ่านมาดำเนินการบริโภคในกรุ๊ปอีกแหล่ว ในกรณีนี้ เราสามารถแบ่งผู้บริโภคออกเป็นโฟลเดอร์สองโฟลเดอร์ เช่น
app_path() . '/queue/redis/fast'
และapp_path() . '/queue/redis/slow'
(โปรดทราบว่าต้องทำการเปลี่ยนแปลง namespace ของคลาสบริโภคตามนั้น) ตัวอย่างเช่น:return [ ... ตัวอย่างการกำหนดค่าที่เหลือ...
'redis_consumer_fast' => [
'handler' => Webman\RedisQueue\Process\Consumer::class,
'count' => 8,
'constructor' => [
// โฟลเดอร์ของคลาสผู้บริโภค
'consumer_dir' => app_path() . '/queue/redis/fast'
]
],
'redis_consumer_slow' => [
'handler' => Webman\RedisQueue\Process\Consumer::class,
'count' => 8,
'constructor' => [
// โฟลเดอร์ของคลาสผู้บริโภค
'consumer_dir' => app_path() . '/queue/redis/slow'
]
]
];
โดยการจัดกลุ่มโฟลเดอร์และการกำหนดค่าที่เกี่ยวข้อง เราสามารถกำหนดกระบวนการการบริโภคที่แตกต่างสำหรับผู้บริโภคที่แตกต่างกันได้โดยง่ายดาย
## การกำหนดค่า Redis หลายรายการ
#### การกำหนดค่า
`config/plugin/webman/redis-queue/redis.php`
```php
<?php
return [
'default' => [
'host' => 'redis://192.168.0.1:6379',
'options' => [
'auth' => null, // รหัสผ่าน เป็นตัวหลักข้อความ ตัวเลือกที่สามารถใช้งานได้
'db' => 0, // ฐานข้อมูล
'max_attempts' => 5, // หลังจากการบริโภคล้มเหลว จำนวนครั้งในการลองบริโภคใหม่
'retry_seconds' => 5, // ระยะเวลาระหว่างการลองบริโภคใหม่ หน่วยเป็นวินาที
]
],
'other' => [
'host' => 'redis://192.168.0.2:6379',
'options' => [
'auth' => null, // รหัสผ่าน เป็นตัวหลักข้อความ ตัวเลือกที่สามารถใช้งานได้
'db' => 0, // ฐานข้อมูล
'max_attempts' => 5, // หลังจากการบริโภคล้มเหลว จำนวนครั้งในการลองบริโภคใหม่
'retry_seconds' => 5, // ระยะเวลาระหว่างการลองบริโภคใหม่ หน่วยเป็นวินาที
]
],
];
โปรดทราบว่าการกำหนดค่าได้เพิ่มขึ้นอีก Redis หนึ่งรายการที่เรียกว่า other
เป็น key
การบริโภคข้อความจาก Redis หลายรายการ
// บริโภคข้อความจากคิวที่เป็น key ตั้งเริ่มต้น
Client::connection('default')->send($queue, $data);
Redis::connection('default')->send($queue, $data);
// คือเหมือนกับ
Client::send($queue, $data);
Redis::send($queue, $data);
// บริโภคข้อความจากคิวที่เป็น key อื่น
Client::connection('other')->send($queue, $data);
Redis::connection('other')->send($queue, $data);
การบริโภคข้อความจาก Redis หลายรายการ
การกำหนดค่าการบริโภคข้อความจาก key other
ในกลุ่มแม้จะมีการบริโภค
namespace app\queue\redis;
use Webman\RedisQueue\Consumer;
class SendMail implements Consumer
{
// ชื่อคิวที่จะบริโภค
public $queue = 'send-mail';
// === ตั้งค่าเป็น other แทนการบริโภคจากคิวที่ key other ===
public $connection = 'other';
// การบริโภค
public function consume($data)
{
// ไม่จำเป็นต้องยึดค่ากลับ
var_export($data);
}
}
ปัญหาที่พบบ่อย
ทำไมมันขึ้นข้อผิดพลาด "Workerman\Redis\Exception: Workerman Redis Wait Timeout (600 seconds)"
ข้อผิดพลาดนี้จะเกิดขึ้นเมื่อใช้งานฟังก์ชัน Client::send()
แบบซิงโครนัส หรือเมื่อมีการส่งข้อความที่ใช้เวลานานในการส่งไปยังเซิร์ฟเวอร์ Redis หากข้อความที่ส่งไปยัง Redis มีความเร็วน้อยกว่าการส่งข้อความ หรือหน่วยความจำมีปัญหาในการเตรียมส่งข้อความ การสร้างการส่งข้อความนั้นจะทำให้ข้อผิดพลาดเกิดขึ้น หากมีความผิดพลาดในการสื่อสารเกิน 600 วินาที ข้อผิดพลาดนี้ก็จะเกิดขึ้น
วิธีการแก้ไข: ควรใช้ฟังก์ชันส่งข้อความแบบซิงโครนัส Redis::send()
แทน