Amazon Simple Queue Service

Dạo gần đây (khoảng 2 3 tháng gì đấy) mình làm khá nhiều bên front-end, chủ yếu là ReactJS và cũng có biểu hiện chán chán và muốn đổi vị =)) Có lẽ bắt đầu từ tháng này mình sẽ tìm hiểu và viết bài về các dịch vụ của Amazon Web Service. Bao gồm AWS SQS, EC2, ElastiCache... Và bài viết đầu tiên của mình sẽ là về Simple Queue Service (AWS SQS).

1. Amazon Simple Queue Service là gì?

Amazon Simple Queue Service là dịch vụ cho phép bạn lưu trữ các messages dưới dạng queue. Với SQS bạn có thể chuyển dữ liệu giữa các components trong app của bạn mà không phải lo lắng việc mất dữ liệu. Các bạn có thể tìm hiểu cụ thể hơn ở link doc của SQS: http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/Welcome.html

2. Lợi ích khi sử dụng AWS SQS

AWS SQS cung cấp cho bạn những điều tuyêt vời dưới đây: * Multiple Reader and Writer: cho phép nhiều component cùng tham gia vào việc đọc và ghi vào queue: * Setting Queue: bạn có thể chỉnh setting cho queue với rất nhiều giá trị như delay time, visibility timeout... * Quản lý access queue: thiết lập xem những component nào được truy cập và nhận messages từ queue * Dung lượng message: có thể lên tới 256Kb. Còn nếu muốn lớn hơn bạn có thể sử dụng SQS kết hợp vs S3 hoặc SimpleDB. * ....

3. Cơ chế hoạt động của SQS

Cơ chế hoạt động của SQS rất đơn giản, như một queue bình thường: bạn enqueue message của bạn, sau đó components của bạn lần lượt lấy message từ queue ra và xử lý, sau khi xử lý xong thì bạn delete message đó hoặc vẫn để message đó trên queue để chờ xử lý lần nữa.

Đơn giản là như vậy nhưng SQS có những điểm sau mà bạn cần chú ý:

  1. Nhận biết Queue và Message

Đối với SQS thì có 3 giá trị sau bạn cần quan tâm: * Queue URLs: Khi bạn tạo queue thì bạn cần cung cấp tên của queue để tạo queue url, tên và url này là duy nhất. Ví dụ cho queue url:

http://sqs.us-east-1.amazonaws.com/123456789012/queue2 * Message IDs: Khi bạn request enqueue một message thì giá trị trả về cho bạn sẽ là id của message đó. Id này có nhiệm vụ để bạn nhận diện message khi mà bạn nhận message từ queue. Tuy nhiên để delete message thì bạn cần quan tâm đến giá trị thứ 3 dưới đây. * Receipt Handles: Khi bạn nhận message từ queue thì bạn sẽ nhận được 1 code của message. Sử dụng code này trong trường hợp bạn muốn delete message trên queue. Cần lưu ý là dù là một message tuy nhiên mỗi lần bạn nhận nó từ queue sẽ là một lần bạn nhận được Receipt Handles khác nhau. Ví dụ cho một Receipt Handles:

MbZj6wDWli+JvwwJaBV+3dcjk2YW2vA3+STFFljTM8tJJg6HRG6PYSasuWXPJB+CwLj1FjgXUv1uSj1gUPAWV66FU/WeR4mq2OKpEGYWbnLmpRCJVAyeMjeU5ZBdtcQ+QEauMZc8ZRv37sIW2iJKq3M9MFx1YvV11A2x/KSbkJ0=

  1. Visibility Timeout

Hình vẽ dưới đây sẽ cho bạn thấy được cách xử lý một message trên queue: bdf9e199308e0f39f25b49fed5aad27f.png

Đầu tiên cần lưu ý rằng sau khi message được lấy ra khỏi queue thì message đó không bị xóa khỏi queue mà vẫn nằm trong queue. Lý do là vì không có gì để đảm bảo rằng bạn đã nhận được message đó. Mất mạng, lỗi, bug... gì đó khiến cho bạn không thể nhận được message và vì thế mà SQS vẫn giữ message của bạn trên queue.

Tuy nhiên có thể bạn muốn một thời điểm chỉ có một components xử lý message của bạn, trong trườnghợp này bạn nên đặt giá trị Visibility Timeout cho queue của bạn. Chẳng hạn bạn đặt giá trị này là 45s, sau khi message được trả về cho request đầu tiên, nó sẽ được chuyển vào flight message trong 45s, và những request tiếp theo sẽ không nhận được kết quả nào cả... Sau 45s thì message đó quay về trạng thái avaiable và nó sẽ được trả về nếu có request đến queue.

  1. Message Lifecycle

Với việc setting Visibility Timeout như trên thì một vòng hoạt động của message sẽ như sau: * Components A gửi message A lên queue. * Components B request message và sẽ nhận đc message A. Lúc này bọ đếm Visibility Timeout bắt đầu chạy. * Trong thời gian Visibility Timeout tất cả các request đều không trả về message. * Sau khi xử lý xong message A, component B request xóa message A trên queue. * Queue xóa message A, quay lại chờ request enqueue hoặc dequeue message.

  1. Long Polling

Mục đích của Long Polling là để giảm thiểu những response empty từ phía queue. Khi có một request nhận message, nếu như trong queue ko có message nào cả, Amazon SQS sẽ chờ cho đến khi có một message có thể response lại. Thay vì connection bị timeout hoặc response trả về là empty, thì component sẽ nhận được message. Để enable tính năng này, khi tạo queue bạn chỉ cần set giá trị Receive Message Wait Time khác 0.

  1. ***Delay Queues ***

Mỗi khi có một message được gửi đến queue, nếu như bạn set delay queue là 45s thì message này sẽ không thể bị dequeue trong 45s sau khi enqueue. Giá trị này khác với Visibility Timeout ở chỗ giá trị này chỉ được đếm đối với lân đầu tiên message được cho vào queue, còn Visibility Timeout sẽ đếm với mỗi lần message enqueue.

  1. ***Messages Timer ***

Giá trị này giống với Delay Queues, tuy nhiên Delay Queues được set khi tạo queue, và áp dụng với mọi message. Còn nếu trong queue đó bạn muốn message nào đó có giá trị delay khác với delay queue thì khi enqueue, bạn sẽ cần sử dụng giá trị message timer set trực tiếp cho message đó.

4. Ví dụ trong Ruby

Dưới đây mình demo một vài vi dụ trong Ruby.

Để tạo queue thì đơn giản như code dưới đây:

 option = {
        visibility_timeout: 45,
        maximum_message_size: 65536,
        delay_seconds: 10,
      }
      queue = sqs.queues.create("test", option)
Giá trị ```delay_seconds``` ở đây chính là Delay Queue mà mình nói bên  trên.

Sau khi đã tạo được queue test như trên, để sử dụng được queue test thì có 2 cách sau đây để gọi

 # Sử dung tên của queue để gọi queue
 queue = sqs.queues.named "seo_keyword"

 # Sử dụng url của queue để gọi queue trong trường hợp dã biết url
 queue_url = http://sqs.us-east-1.amazonaws.com/123456789012/test
 queue = AWS::SQS.new.queues[queue_url]

Cũng giống như một vài service khác của AWS, khi bạn muốn insert data thì hỗ trợ cả việc gửi từng message hoặc send_batch để gửi nhiều message trong một request enqueue

 # Gửi từng message
 [0..100].each do |i|
   queue.send_message i
 end

 #Gửi nhiều message trong một request
 [0..100].each_slice(10) do |mess|
   queue.batch_send *mess
 end

Nhận message cũng có 2 cách như sau

  • Dùng hàm receive_mesage :
 while true
   message = queue.receive_message(wait_time_seconds: 10)
   break if message.blank?
   #code xử lý message
 end
  • Dùng hàm poll :
queue.poll() do |mess|
#code xử lý mess
end

Điểm hay của việc dùng poll ở đây là hàm của bạn sẽ luôn ở trạng thái waiting response từ queue. Có nghĩa là là nếu queue có message thì nó sẽ trả về luôn cho bạn, còn nếu không thì bạn sẽ ở trạng thái waiting. Tất nhiên là bạn có thể set timeout để nếu sau một khoảng thời gian không nhận được thì sẽ bỏ waiting

 queue.poll(idle_timeout: 3600) do |msg|
   #code xử lý msg
 end

Theo mình receive_message trong trường hợp mà bạn biết chắc chắn về thời điểm mà message enqueue hoặc việc enqueue diễn ra không thường xuyên, ví dụ component A gửi mess vào 10h hằng ngày, component B sẽ chạy vào 10h5 chẳng hạn để nhận mess và dùng receive_message.

Còn trong trường hợp mà cứ 5 phút 1 lần component A lại gửi mess, thì rõ ràng ở component B nên dùng poll() để nhận message, tránh phải cứ 5 min lại chạy lại hàm nhận message ở component B.

Ah quên, nếu muốn xóa hết message của queue thì dùng hàm purge_queue() Còn muốn delete queue thì đơn giản thôi, queue.delete là xong =))

5. Tổng kết

Với những ví dụ trên đây thì mình thấy AWS SQS sử dụng đơn giản, khá thuận tiện.

Ngoài ra nếu là truyền message giữa 2 component thì AWS chắc còn thằng ElastiCache với Redis. Tùy từng trường hợp mà bạn sử dụng service cho phù hợp.

Ví dụ như nếu trong trường hợp 1 component gửi mess nhưng có đến 4 thằng component chạy để xử lý mess đấy thì rõ ràng dùng SQS là đơn giản hơn. Đỡ phải lo việc 2 thằng xử lý cùng một mess.

Còn nếu mà mess có dung lượng lớn thì nên dùng Redis, đỡ phải lằng nhằng connect thằng SQS vs S3

Trên đây là toàn bộ bài viết của mình về AWS SQS. Trong bài viết tới mình sẽ giới thiệu về AWS EC2. Xin chào và hẹn gặp lại =))


All Rights Reserved