Cách quản lý email tự động được gửi từ ứng dụng web


11

Tôi đang thiết kế một ứng dụng web và tôi đang tự hỏi làm thế nào để thiết kế kiến ​​trúc để quản lý việc gửi email tự động.

Hiện tại tôi có tính năng này được tích hợp vào ứng dụng web của mình và các email được gửi dựa trên đầu vào / tương tác của người dùng (như tạo người dùng mới). Vấn đề là việc kết nối trực tiếp với máy chủ thư mất vài giây. Mở rộng ứng dụng của tôi lên, đây sẽ là một cổ chai đáng kể trong tương lai.

Cách tốt nhất để quản lý gửi một lượng lớn email tự động trong kiến ​​trúc hệ thống của tôi là gì?

Sẽ không có một lượng lớn email được gửi (tối đa 2000 một ngày). Email không cần phải gửi ngay lập tức, độ trễ tối đa 10 phút là ổn.

Cập nhật: Hàng đợi tin nhắn đã được đưa ra như một câu trả lời, nhưng làm thế nào điều này sẽ được thiết kế? Điều này sẽ được xử lý trong ứng dụng và được xử lý trong một khoảng thời gian yên tĩnh, hoặc tôi có cần tạo một 'ứng dụng thư' hoặc dịch vụ web mới để chỉ quản lý hàng đợi không?


Bạn có thể cho chúng tôi một cảm giác thô về quy mô? Hàng trăm, hàng ngàn hoặc hàng triệu thư? Ngoài ra, các email nên được gửi ngay lập tức hay là một độ trễ nhỏ có thể chấp nhận?
yannis

Gửi email liên quan đến việc chuyển một tin nhắn SMTP đến một máy chủ nhận thư, nhưng điều đó không có nghĩa là thư thực sự đã được gửi. Vì vậy, hiệu quả, tất cả việc gửi email là không đồng bộ và không có lý do gì để giả vờ "chờ đợi thành công".
Kilian Foth

1
Tôi không "chờ đợi thành công", nhưng tôi phải đợi máy chủ smtp chấp nhận yêu cầu của tôi. @YannisRizos xem cập nhật RE bình luận của bạn
Gaz_Edge

Trong năm 2000 (đó là tối đa được mô tả của bạn), nó sẽ chỉ hoạt động. Khi chúng xảy ra trong 10 giờ làm việc, 3 thư mỗi phút là rất khả thi. Chỉ cần đảm bảo rằng bạn thiết lập tốt bản ghi DNS của mình và nhà cung cấp chấp nhận bạn gửi chúng với số tiền này. Cũng nghĩ về: "máy chủ bị hỏng là gì?". Tải trọng của việc gửi 2000 thư không phải là điều đáng lo ngại.
Luc Franken

Câu trả lời là CRONTAB
Tulains Córdova 19/03/13

Câu trả lời:


15

Cách tiếp cận phổ biến, như Ozz đã đề cập , là một hàng đợi tin nhắn . Từ phối cảnh thiết kế, hàng đợi tin nhắn về cơ bản là hàng đợi FIFO , đây là kiểu dữ liệu khá cơ bản:

Hàng đợi hàng năm

Điều làm cho một hàng đợi tin nhắn trở nên đặc biệt là trong khi ứng dụng của bạn chịu trách nhiệm cho việc xếp hàng, một quy trình khác sẽ chịu trách nhiệm hủy xếp hàng. Trong xếp hàng biệt ngữ, ứng dụng của bạn là người gửi tin nhắn và quá trình hủy xếp hàng là người nhận. Ưu điểm rõ ràng là toàn bộ quá trình không đồng bộ, người nhận hoạt động độc lập với người gửi, miễn là có thông điệp cần xử lý. Nhược điểm rõ ràng là bạn cần một thành phần phụ, người gửi, để toàn bộ hoạt động.

Vì kiến ​​trúc của bạn bây giờ phụ thuộc vào hai thành phần trao đổi thông điệp, bạn có thể sử dụng thuật ngữ giao tiếp giữa các quá trình ưa thích cho nó.

Làm thế nào để giới thiệu một hàng đợi ảnh hưởng đến thiết kế ứng dụng của bạn?

Một số hành động trong ứng dụng của bạn tạo ra email. Giới thiệu hàng đợi tin nhắn có nghĩa là những hành động đó bây giờ sẽ đẩy tin nhắn đến hàng đợi thay thế (và không có gì nữa). Những thư đó sẽ mang lượng thông tin tối thiểu tuyệt đối cần thiết để tạo email khi người nhận của bạn xử lý chúng.

Định dạng và nội dung của tin nhắn

Định dạng và nội dung tin nhắn của bạn hoàn toàn phụ thuộc vào bạn, nhưng bạn nên nhớ rằng càng nhỏ càng tốt. Hàng đợi của bạn phải càng nhanh để viết và xử lý càng tốt, việc ném một lượng lớn dữ liệu vào đó có thể sẽ tạo ra một nút cổ chai.

Hơn nữa, một số dịch vụ xếp hàng dựa trên đám mây có các hạn chế về kích thước thư và có thể phân chia các thư lớn hơn. Bạn sẽ không nhận thấy, các tin nhắn chia sẽ được phục vụ như một khi bạn yêu cầu chúng, nhưng bạn sẽ bị tính phí cho nhiều tin nhắn (giả sử tất nhiên bạn đang sử dụng một dịch vụ yêu cầu phải trả phí).

Thiết kế của người nhận

Vì chúng ta đang nói về một ứng dụng web, một cách tiếp cận phổ biến cho người nhận của bạn sẽ là một tập lệnh cron đơn giản. Nó sẽ chạy mỗi xphút (hoặc giây) và nó sẽ:

  • Pop nlượng thông điệp từ hàng đợi,
  • Xử lý các tin nhắn (tức là gửi email).

Lưu ý rằng tôi đang nói pop thay vì lấy hoặc tìm nạp, đó là vì người nhận của bạn không chỉ nhận các mục từ hàng đợi, mà còn xóa chúng (tức là xóa chúng khỏi hàng đợi hoặc đánh dấu chúng là đã xử lý). Chính xác điều đó sẽ xảy ra như thế nào tùy thuộc vào việc bạn thực hiện hàng đợi tin nhắn và nhu cầu cụ thể của ứng dụng.

Tất nhiên những gì tôi mô tả về cơ bản là một hoạt động hàng loạt , cách đơn giản nhất để xử lý hàng đợi. Tùy thuộc vào nhu cầu của bạn, bạn có thể muốn xử lý tin nhắn theo cách phức tạp hơn (điều đó cũng sẽ gọi cho một hàng đợi phức tạp hơn).

Giao thông

Người nhận của bạn có thể xem xét lưu lượng truy cập và điều chỉnh số lượng tin nhắn mà nó xử lý dựa trên lưu lượng truy cập tại thời điểm nó chạy. Một cách tiếp cận đơn giản sẽ là dự đoán số giờ lưu lượng truy cập cao của bạn dựa trên dữ liệu lưu lượng truy cập trong quá khứ và giả sử bạn đã sử dụng tập lệnh cron chạy mỗi xphút bạn có thể làm điều gì đó như sau:

if( 
    now() > 2pm && now() < 7pm
) {
    process(10);
} else {
    process(100);
}

function process(count) {
    for(i=0; i<=count; i++) {
        message = dequeue();
        mail(message)
    }
}

Một cách tiếp cận rất ngây thơ và bẩn thỉu, nhưng nó hoạt động. Nếu không, tốt, cách tiếp cận khác sẽ là tìm ra lưu lượng truy cập hiện tại của máy chủ của bạn ở mỗi lần lặp và điều chỉnh số lượng mục xử lý cho phù hợp. Vui lòng không tối ưu hóa vi mô nếu điều đó không thực sự cần thiết, bạn sẽ lãng phí thời gian của mình.

Lưu trữ hàng đợi

Nếu ứng dụng của bạn đã sử dụng cơ sở dữ liệu, thì một bảng duy nhất trên đó sẽ là giải pháp đơn giản nhất:

CREATE TABLE message_queue (
  id int(11) NOT NULL AUTO_INCREMENT,
  timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  processed enum('0','1') NOT NULL DEFAULT '0',
  message varchar(255) NOT NULL,
  PRIMARY KEY (id),
  KEY timestamp (timestamp),
  KEY processed (processed)
) 

Nó thực sự không phức tạp hơn thế. Tất nhiên bạn có thể làm cho nó phức tạp như bạn cần, ví dụ, bạn có thể thêm một trường ưu tiên (điều đó có nghĩa là đây không còn là hàng đợi FIFO, nhưng nếu bạn thực sự cần nó, ai quan tâm?). Bạn cũng có thể làm cho nó đơn giản hơn, bằng cách bỏ qua trường được xử lý (nhưng sau đó bạn phải xóa các hàng sau khi bạn xử lý chúng).

Một bảng cơ sở dữ liệu sẽ lý tưởng cho 2000 tin nhắn mỗi ngày, nhưng có lẽ nó sẽ không mở rộng tốt cho hàng triệu tin nhắn mỗi ngày. Có một triệu yếu tố để xem xét, mọi thứ trong cơ sở hạ tầng của bạn đóng một vai trò trong khả năng mở rộng tổng thể của ứng dụng của bạn.

Trong mọi trường hợp, giả sử bạn đã xác định hàng đợi dựa trên cơ sở dữ liệu là một nút cổ chai, bước tiếp theo sẽ là xem xét một dịch vụ dựa trên đám mây. Amazon SQS là một dịch vụ tôi đã sử dụng và đã làm những gì nó hứa hẹn. Tôi chắc chắn có khá nhiều dịch vụ tương tự ngoài kia.

Hàng đợi dựa trên bộ nhớ cũng là một cái gì đó để xem xét, đặc biệt là đối với hàng đợi ngắn. memcached là tuyệt vời như lưu trữ hàng đợi tin nhắn.

Bất cứ lưu trữ nào bạn quyết định xây dựng hàng đợi của mình, hãy thông minh và trừu tượng hóa nó. Cả người gửi và người nhận của bạn đều không nên bị ràng buộc với một bộ lưu trữ cụ thể, nếu không, việc chuyển sang một bộ lưu trữ khác sau đó sẽ là một PITA hoàn chỉnh.

Cách tiếp cận thực tế cuộc sống

Tôi đã tạo một hàng đợi tin nhắn cho các email rất giống với những gì bạn đang làm. Đó là một dự án PHP và tôi đã xây dựng nó xung quanh Zend Queue , một thành phần của Khung công tác Zend cung cấp một số bộ điều hợp cho các kho lưu trữ khác nhau. Kho của tôi đâu:

  • Mảng PHP để thử nghiệm đơn vị,
  • Amazon SQS đang sản xuất,
  • MySQL trên dev và môi trường thử nghiệm.

Thông điệp của tôi đơn giản như có thể, ứng dụng của tôi đã tạo ra các mảng nhỏ với thông tin cần thiết ( [user_id, reason]). Kho lưu trữ thư là phiên bản tuần tự của mảng đó (đầu tiên là định dạng tuần tự hóa nội bộ của PHP, sau đó là JSON, tôi không nhớ tại sao tôi lại chuyển đổi). Đây reasonlà một hằng số và tất nhiên tôi có một bảng lớn ở đâu đó ánh xạ reasontới các giải thích đầy đủ hơn (tôi đã quản lý để gửi khoảng 500 email cho khách hàng bằng mật mã reasonthay vì tin nhắn đầy đủ một lần).

đọc thêm

Tiêu chuẩn:

Công cụ:

Thú vị đọc:


Ồ Chỉ là về câu trả lời tốt nhất mà tôi từng nhận được ở đây! Không thể cảm ơn đủ!
Gaz_Edge

Tôi và chắc chắn hàng triệu người khác sử dụng FIFO này với Gmail & Google Apps Script. bộ lọc Gmail dán nhãn bất kỳ thư đến nào dựa trên một tiêu chí và đó là tất cả, xếp hàng chúng. Tập lệnh Google Apps chạy mọi thời lượng X, nhận được tin nhắn y đầu tiên, gửi chúng, loại bỏ chúng. Rửa sạch và lặp lại.
DavChana

6

Bạn cần một số loại hệ thống xếp hàng.

Một cách đơn giản có thể là ghi vào bảng cơ sở dữ liệu và có một hàng quy trình ứng dụng bên ngoài khác trong bảng này, nhưng có nhiều công nghệ xếp hàng khác mà bạn có thể sử dụng.

Bạn có thể có tầm quan trọng đối với email để một số email nhất định được xử lý gần như ngay lập tức (ví dụ đặt lại mật khẩu) và những email có tầm quan trọng thấp hơn có thể được gửi theo đợt để gửi sau.


Bạn có một sơ đồ kiến ​​trúc hoặc ví dụ cho thấy cách thức này hoạt động không? Ví dụ: hàng đợi có nằm trong một ứng dụng thư 'ứng dụng' khác hay ứng dụng đó có xử lý từ bên trong ứng dụng web trong một khoảng thời gian yên tĩnh. Hoặc tôi nên tạo ra một loại dịch vụ web để xử lý chúng?
Gaz_Edge

1
@Gaz_Edge Ứng dụng của bạn đẩy các mục vào hàng đợi. Một quá trình nền (rất có thể là tập lệnh cron) bật x các mục từ hàng đợi mỗi n giây và xử lý chúng (trong trường hợp của bạn, gửi email). Một bảng cơ sở dữ liệu duy nhất hoạt động tốt như lưu trữ hàng đợi cho một lượng nhỏ các mặt hàng, nhưng nói chung, các thao tác ghi trên cơ sở dữ liệu rất tốn kém và với số lượng lớn hơn bạn có thể muốn xem các dịch vụ như SQS của Amazon .
yannis

1
@Gaz_Edge Tôi không chắc mình có thể lập sơ đồ đơn giản hơn những gì tôi đã viết "... ghi vào bảng cơ sở dữ liệu và có một hàng quy trình ứng dụng bên ngoài khác trong bảng này ...." và đối với bảng, hãy đọc "bất kỳ hàng đợi nào "Bất cứ công nghệ nào có thể.
ozz

1
(tiếp ...) Bạn có thể xây dựng quy trình nền để xóa hàng đợi theo cách xem xét lưu lượng truy cập của mình, ví dụ: bạn có thể hướng dẫn nó xử lý ít mục hơn (hoặc không có gì) vào lúc máy chủ của bạn bị căng thẳng . Bạn sẽ phải dự đoán những thời điểm căng thẳng đó bằng cách xem dữ liệu lưu lượng truy cập trong quá khứ của bạn (dễ hơn âm thanh nhưng có lỗi lớn) hoặc bằng cách kiểm tra trạng thái lưu lượng truy cập mỗi khi nó chạy (chính xác hơn, nhưng chính xác hơn chi phí bổ sung hiếm khi cần thiết).
yannis

@YannisRizos muốn kết hợp ý kiến ​​của bạn thành một câu trả lời? Ngoài ra, sơ đồ và thiết kế kiến ​​trúc sẽ hữu ích (tôi quyết tâm lấy chúng từ câu hỏi này lần này! ;-))
Gaz_Edge

2

Sẽ không có một lượng lớn email được gửi (tối đa 2000 một ngày).

Ngoài việc xếp hàng, điều thứ hai mà bạn nên xem xét là gửi email thông qua các dịch vụ chuyên biệt: MailChimp chẳng hạn (Tôi không liên kết với dịch vụ này). Nếu không, nhiều dịch vụ thư, chẳng hạn như gmail, sẽ sớm gửi thư của bạn vào thư mục thư rác.


2

Tôi đã mô hình hóa hệ thống xếp hàng của mình trong 2 bảng khác nhau như;

CREATE TABLE [dbo].[wMessages](
  [Id] [uniqueidentifier]  NOT NULL,
  [FromAddress] [nvarchar](255) NOT NULL,
  [FromDisplayName] [nvarchar](255) NULL,
  [ToAddress] [nvarchar](255) NOT NULL,
  [ToDisplayName] [nvarchar](255) NULL,
  [Graph] [xml] NOT NULL,
  [Priority] [int] NOT NULL,
  PRIMARY KEY CLUSTERED ( [Id] ASC ))

CREATE TABLE [dbo].[wMessageStates](
  [MessageId] [uniqueidentifier] NOT NULL,
  [Status] [int] NOT NULL,
  [LastChange] [datetimeoffset](7) NOT NULL,
  [SendAfter] [datetimeoffset](7) NULL,
  [SendBefore] [datetimeoffset](7) NULL,
  [DeleteAfter] [datetimeoffset](7) NULL,
  [SendDate] [datetimeoffset](7) NULL,
  PRIMARY KEY CLUSTERED ( [MessageId] ASC )) ON [PRIMARY]
) ON [PRIMARY]

Có mối quan hệ 1-1 giữa các bảng này.

Bảng tin nhắn để lưu trữ nội dung tin nhắn. Nội dung thực tế (To, CC, BCC, Chủ đề, Phần thân, v.v.) được tuần tự hóa thành trường Biểu đồ ở định dạng XML. Khác Từ, Để thông tin chỉ được sử dụng để báo cáo các vấn đề mà không khử lưu đồ thị. Việc sắp xếp bảng này cho phép phân vùng nội dung bảng sang một bộ lưu trữ đĩa khác. Khi bạn đã sẵn sàng gửi tin nhắn, bạn cần đọc tất cả thông tin do đó không có gì sai với việc tuần tự hóa tất cả nội dung vào một cột với chỉ mục khóa chính.

Bảng MessageState để lưu trữ trạng thái nội dung thư với thông tin dựa trên ngày bổ sung. Việc sắp xếp bảng này cho phép cơ chế truy cập nhanh với các chỉ mục bổ sung trên bộ lưu trữ IO nhanh. Các cột khác đã tự giải thích.

Bạn có thể sử dụng một nhóm luồng riêng biệt quét các bảng này. Nếu ứng dụng và nhóm tồn tại trong cùng một máy, bạn có thể sử dụng lớp EventWaitHandle để báo hiệu nhóm từ ứng dụng về thứ gì đó được chèn vào các bảng này, nếu không thì quét định kỳ với thời gian chờ là tốt nhất.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.