Phục vụ các tác vụ nền trên một trang web lớn


49

Chúng tôi đang xử lý một vấn đề thú vị trên StackOverflow.

Chúng tôi đã có một loạt các nhiệm vụ "cần phải hoàn thành sớm". Một ví dụ đang cập nhật danh sách "Câu hỏi liên quan". Những gì chúng ta đã làm trong quá khứ là cõng những nhiệm vụ đó lên tải trang của một số người dùng.

Điều này không bao giờ lý tưởng, nhưng nó không thực sự đáng chú ý. Bây giờ SO đã vượt qua mốc 1.000.000 câu hỏi, những người dùng không may mắn đó đang bắt đầu cảm thấy nó.

Giải pháp tự nhiên là thực sự đẩy những nhiệm vụ này vào nền. Có hai cách rộng rãi để làm điều này tôi đang xem xét.

1. Trong IIS dưới dạng một luồng chủ đề / nhóm công việc tùy chỉnh

Về cơ bản, chúng tôi tạo ra một số chủ đề (không phải ThreadPool , để không can thiệp vào IIS) và cung cấp cho họ các dịch vụ mà một số bộ sưu tập chúng tôi đang đưa Func vào.

Các pro lớn ở đây là sự đơn giản. Chúng tôi không phải lo lắng về việc sắp xếp bất cứ điều gì, chúng tôi cũng không phải đảm bảo rằng một số dịch vụ bên ngoài đã hoạt động và đáp ứng.

Chúng tôi cũng có quyền truy cập vào tất cả các mã phổ biến của chúng tôi.

Con lừa, tốt, chúng ta không nên sử dụng chủ đề nền. Tất cả những phản đối mà tôi biết đều tập trung vào việc bỏ đói IIS (nếu bạn sử dụng ThreadPool) và các luồng bị chết ngẫu nhiên (do tái chế AppPool).

Về cơ bản, chúng tôi đã có cơ sở hạ tầng để biến cái chết của luồng ngẫu nhiên thành một vấn đề (về cơ bản có thể phát hiện một nhiệm vụ đã bị bỏ rơi) và việc giới hạn số lượng luồng (và sử dụng các luồng không phải ThreadPool) cũng không khó.

Tôi có thiếu bất kỳ sự phản đối nào khác trong IIS trong quá trình xử lý tổng hợp luồng / hàng đợi công việc không?

Đã chuyển sang StackOverflow , vì nó không thực sự được giải quyết ở đây.

2. Là một dịch vụ

Hoặc một số giải pháp của bên thứ ba, hoặc một giải pháp tùy chỉnh.

Về cơ bản, chúng tôi sắp xếp một nhiệm vụ xuyên qua ranh giới quy trình cho một số dịch vụ và chỉ cần quên nó đi. Có lẽ chúng tôi đang liên kết một số mã trong hoặc bị hạn chế đối với SQL thô + chuỗi kết nối.

Chuyên nghiệp là "cách đúng đắn" để làm điều này.

Nhược điểm là chúng tôi hoặc rất hạn chế trong những gì chúng tôi có thể làm hoặc chúng tôi sẽ phải tìm ra một số hệ thống để giữ dịch vụ này đồng bộ với cơ sở mã của chúng tôi. Chúng tôi cũng cần phải kết nối tất cả các hoạt động theo dõi và đăng nhập lỗi của chúng tôi bằng cách nào đó mà chúng tôi nhận được miễn phí với tùy chọn "Trong IIS".

Có bất kỳ lợi ích hoặc vấn đề khác với cách tiếp cận dịch vụ?

Tóm lại, có những vấn đề chưa được giải quyết và không thể khắc phục được khiến cho cách tiếp cận số 1 không khả thi và nếu có thì có dịch vụ bên thứ ba nào tốt mà chúng ta nên xem xét cho cách tiếp cận số 2 không?


Cách đúng đắn là cách mà khi bạn quyết định đi theo con đường khác, bạn nhìn lại và nói rằng chúng ta nên làm điều đó đúng cách. Chọn một cách khôn ngoan. Tôi không đủ quen thuộc với thế giới IIS để bình luận về vấn đề đặc biệt này.
Chris

2
Tôi tò mò vì tôi có một kịch bản tương tự (ở quy mô nhỏ hơn nhiều) và tôi cũng chỉ ủng hộ một số người dùng ngẫu nhiên kết nối không may mắn. Tôi không quen với giải pháp tốt nhất, vì vậy tôi sẽ theo dõi ở đây. :-)
pc1oad1etter

7
Tôi không hiểu tại sao điều này không có trên StackOverflow. Đây là một sự đánh đổi kỹ thuật, không phải là một định giá chủ quan. Bạn đang yêu cầu phân tích các phương pháp khác nhau - đó là tất cả khách quan. Chỉ khi phân tích đã làm rõ chính xác sự đánh đổi là gì, liệu có sự chủ quan nào với nó không, và theo như tôi có thể thấy câu hỏi của bạn không phải là 'tôi nên tìm gì quan trọng hơn, tài nguyên máy chủ và thời gian của tôi, hay thời gian của người dùng? ' hoặc một cái gì đó tương tự.
Joren

@Kevin Montrose - từ nhận xét của bạn, có vẻ như bạn đang phân biệt giữa "cần phải hoàn thành sớm" và "lên lịch trong một khoảng thời gian". Bạn có thể xây dựng trên những lý do tại sao hai khác nhau các loại nhiệm vụ nền mà đòi hỏi một mô hình khác nhau / cơ sở hạ tầng?
Portman

@Portman - Sự khác biệt cơ bản là các nhiệm vụ "sắp hoàn thành" không thể được thực hiện một cách cụ thể, chúng tôi thực sự cần phải đợi cho đến khi chúng tôi biết rằng chúng cần phải được thực hiện. Một số mặt sau của tính toán đường bao cho thấy rằng nếu chúng ta chuyển các truy vấn "Câu hỏi liên quan" (chỉ một trong số nhiều) sang tab cron "câm", thì sẽ mất khoảng. một tuần thực hiện vững chắc để làm việc thông qua tất cả các câu hỏi. Nói chung, chúng tôi cũng muốn chúng chạy càng sớm càng tốt (không ảnh hưởng đến trải nghiệm người dùng), trong khi các tác vụ trong khoảng thời gian của chúng tôi có thể nhận được bằng cách chạy không thường xuyên hơn một lần trong 5 phút (và thường ít thường xuyên hơn).
Kevin Montrose

Câu trả lời:


17

Vài tuần trước tôi đã hỏi một câu hỏi tương tự về SO. Tóm lại, cách tiếp cận của tôi trong một thời gian bây giờ là phát triển Dịch vụ Windows. Tôi sẽ sử dụng NServiceBus (về cơ bản là MSMQ dưới vỏ bọc) để yêu cầu nguyên soái từ ứng dụng web của tôi đến dịch vụ của tôi. Tôi đã từng sử dụng WCF nhưng để một giao dịch phân tán hoạt động chính xác qua WCF luôn có vẻ như là một nỗi đau ở mông. NServiceBus đã thực hiện thủ thuật này, tôi có thể cam kết dữ liệu và tạo các tác vụ trong giao dịch và không lo lắng liệu dịch vụ của mình có hoạt động hay không. Một ví dụ đơn giản, nếu tôi cần gửi email (ví dụ email đăng ký), tôi sẽ tạo tài khoản người dùng và gửi tín hiệu đến Dịch vụ Windows của tôi (để gửi email) trong giao dịch. Trình xử lý tin nhắn ở phía dịch vụ sẽ nhận tin nhắn và xử lý tương ứng.

Kể từ khi ASP .NET 4.0 và AppFoven được phát hành, có một số lựa chọn thay thế khả thi cho cơ chế trên. Nhắc lại câu hỏi tôi đã đề cập ở trên, giờ đây chúng ta có AppInitialize của AppFoven (thông qua net.pipe) cũng như tính năng Tự động khởi động của ASP .NET 4.0, giúp phát triển Windows Services thành ứng dụng web thay thế. Tôi đã bắt đầu làm điều này ngay bây giờ vì một số lý do (một lý do lớn nhất đang được triển khai không còn là vấn đề khó khăn nữa):

  1. Bạn có thể phát triển giao diện người dùng web qua dịch vụ của mình (vì nó chạy như một ứng dụng web). Điều này cực kỳ hữu ích để xem những gì đang xảy ra trong thời gian chạy.
  2. Mô hình triển khai cho các ứng dụng web của bạn sẽ hoạt động cho ứng dụng dịch vụ của bạn.
  3. IIS cung cấp một vài tính năng gọn gàng để xử lý các lỗi ứng dụng (tương tự ở một số khía cạnh với Dịch vụ Windows).
  4. Các nhà phát triển web rất quen thuộc với việc phát triển các ứng dụng web (một cách tự nhiên), hầu hết không biết nhiều về thực tiễn tốt nhất khi phát triển Dịch vụ Windows.
  5. Nó cung cấp một số lựa chọn thay thế để hiển thị API cho các ứng dụng khác tiêu thụ.

Nếu bạn đi theo con đường này (tha thứ cho tôi vì sao chép và dán từ bài viết gốc của tôi) tôi chắc chắn sẽ xem xét việc chạy logic nền trong một ứng dụng web riêng biệt. Có nhiều lý do cho việc này:

  1. An ninh . Có thể có một mô hình bảo mật khác nhau cho giao diện người dùng hiển thị thông tin về các quy trình nền đang chạy. Tôi không muốn tiết lộ UI này cho bất kỳ ai khác ngoài nhóm ops. Ngoài ra, ứng dụng web có thể chạy như một người dùng khác có bộ quyền cao.
  2. Bảo trì . Thật tuyệt vời khi có thể triển khai các thay đổi cho ứng dụng lưu trữ các quy trình nền mà không ảnh hưởng đến người dùng sử dụng trang web giao diện người dùng.
  3. Hiệu suất . Việc tách ứng dụng khỏi các yêu cầu người dùng xử lý trang chính có nghĩa là các luồng nền sẽ không làm giảm khả năng của IIS để xử lý hàng đợi yêu cầu đến. Hơn nữa, ứng dụng xử lý các tác vụ nền có thể được triển khai đến một máy chủ riêng nếu cần.

Làm điều này trở lại khía cạnh đầm lầy. WCF, NServiceBus / RabbitMQ / ActiveMQ, v.v., vanilla MSMQ, RESTful API (nghĩ rằng MVC) đều là các tùy chọn. Nếu bạn đang sử dụng Windows Workflow 4.0, bạn có thể hiển thị điểm cuối máy chủ mà ứng dụng web của bạn có thể sử dụng.

Cách tiếp cận lưu trữ web cho các dịch vụ vẫn còn khá mới đối với tôi, chỉ có thời gian mới trả lời được liệu đó có phải là lựa chọn chính xác hay không. Cho đến nay rất tốt mặc dù. Nhân tiện, nếu bạn không muốn sử dụng AppFoven (Tôi không thể vì một số lý do kỳ lạ, Windows Server Web Edition không được hỗ trợ), khả năng Tự động khởi động được đề cập trong bài đăng của Gu hoạt động rất tốt. Tuy nhiên, tránh xa tệp applicationationhost.config, mọi thứ trong bài đăng đó đều có thể được thiết lập thông qua bảng điều khiển IIS (Trình chỉnh sửa cấu hình ở cấp máy chủ chính).

Lưu ý: Ban đầu tôi đã đăng thêm một vài liên kết trong tin nhắn này nhưng than ôi, đây là bài viết đầu tiên của tôi để trao đổi này và chỉ có một liên kết được hỗ trợ! Về cơ bản có hai người khác, để đưa họ Google "Death to Windows Services ... Long Live AppFoven!" và "tự động khởi động-asp-net-ứng dụng". Xin lỗi vì điều đó.


Ý tưởng cơ bản về việc sử dụng một trang web riêng biệt làm dịch vụ là một điều thú vị mà tôi chưa từng xem xét ...
Kevin Montrose

Rohland, tôi có thể đang thiếu một cái gì đó ở đây, nhưng dường như bạn đang nói rằng bạn đang tương tác với một Dịch vụ Windows từ bên trong trình xử lý NServiceBus của bạn, dịch vụ sau đó sẽ gửi email. Nếu tôi đúng, tôi có thể hỏi tại sao bạn không gửi email từ trình xử lý tin nhắn NServiceBus, việc này rất dễ phát triển, kiểm tra và triển khai không?
Sean Kearon

Trang web sẽ gửi một thông báo tới Dịch vụ Windows. Trình xử lý thông báo NServiceBus của Windows Service nhận tin nhắn và gửi tin nhắn. Về bản chất, đó là giống như quá trình bạn được mô tả.
Rohland

22

Thực sự có một cách thứ ba trong Windows để chạy các dịch vụ nền và nó rất phổ biến trong thế giới UNIX. Cách thứ ba là một CRONcông việc chạy một phần cơ sở hạ tầng của bạn. Trong Windows, điều này được gọi là task schedulervà rất phổ biến để chạy mã trên cơ sở theo lịch trình. Để sử dụng điều này, bạn sẽ tạo một ứng dụng dòng lệnh được thực thi theo lịch trình được xác định trước. Ưu điểm của việc này là bạn không phải lo lắng nếu quy trình được duy trì và chạy như một dịch vụ, bởi vì nếu nó không thành công vì một lý do nào đó, nó sẽ chỉ khởi động vào lần tới.

Đối với việc sắp xếp các tác vụ cụ thể, bạn thực sự chỉ cần lưu trữ các tác vụ này trong bộ lưu trữ nhị phân liên tục. Cho đến khi ứng dụng dòng lệnh chọn chúng ra khỏi bộ lưu trữ và thực thi chúng. Tôi đã thực hiện điều này trong quá khứ bằng cách sử dụng cơ sở dữ liệu Cassandra làm Nhà cung cấp trạng thái phiên để nhồi các tác vụ nền cho người dùng cụ thể trong cơ sở dữ liệu Cassandra, và sau đó có dòng lệnh chọn chúng và thực hiện chúng cho người dùng.

Đây có thể không phải là giải pháp đầm lầy điển hình, nhưng nó hoạt động rất tốt đối với tôi và hóa ra đó là một giải pháp rất thanh lịch, bởi vì các tác vụ theo lịch trình vẫn tồn tại khi tắt máy, sự cố mạng và bất kỳ máy nào cũng có thể thực hiện tác vụ vì nó nằm ở trung tâm lưu trữ.

Quảng cáo không biết xấu hổ, nhưng đây là dự án của tôi và giải pháp tôi chỉ nêu chi tiết ngắn gọn là lý do tôi tạo dự án: http://github.com/managedfusion/fluentcassandra/


2
Tôi làm điều này với dịch vụ lưu trữ được chia sẻ của mình vì tôi không có quyền truy cập shell. Viết một trang PHP thực hiện một việc quan trọng và sau đó có một công việc định kỳ tải trang bằng wget hoặc lynx theo định kỳ. Điều này nghe có vẻ chính xác là loại điều sẽ hoạt động trong trường hợp này và cực kỳ đơn giản, hầu như không yêu cầu thay đổi cách thức hiện tại.
Ricket

Thật là một giải pháp đơn giản. Nó đã khơi dậy những ý tưởng cho dự án của riêng tôi mà tôi thậm chí chưa xem xét. Thêm vào đó bạn có toàn quyền truy cập vào cơ sở mã hiện tại của bạn. Chỉ cần thêm một dự án giao diện điều khiển vào giải pháp và tham khảo các dự án hiện có.
Tim Murphy

10

Ứng dụng web +

Đây là một thiết kế được thử nghiệm chiến đấu theo tỷ lệ ngang với trang trại của bạn và đảm bảo rằng bạn đang sử dụng ngăn xếp công nghệ web mà bạn đã biết.

Đây là cách nó hoạt động:

  1. Tạo một bộ điều khiển / hành động trong ứng dụng web của bạn để xử lý các tác vụ nền được lên lịch. Theo quy ước, tôi thường gọi của tôi http://mydomain.com/system/cron.
  2. Để bảo mật, hành động này nên được khóa chỉ với các địa chỉ IP được xác thực trên mạng cục bộ.
  3. Trên một máy riêng biệt, cài đặt Wget và thiết lập Tác vụ theo lịch trình để wget tìm nạp tài nguyên từ bước 1. Bạn có thể thực hiện tác vụ chạy thường xuyên như bạn muốn (tôi thường chọn trong 30 giây). Đừng quên chuyển đối số cookie thích hợp cho Wget để nó xác thực với ứng dụng web của bạn.
  4. Để dự phòng, bạn cũng có thể cài đặt wget theo lịch trình thứ hai trên máy thứ hai.

Hoan hô! Bây giờ bạn có một tuyến đường sẽ được gọi cứ sau 30 giây. Và nếu yêu cầu mất 5 phút để xử lý, sẽ không có ai quan tâm, vì đó không phải là một phần của yêu cầu trang của người dùng.

Các cronhành động kết thúc lên tìm kiếm rất đơn giản: ông có một danh sách các phương pháp để thực thi trên một tần số nhất định. Khi một yêu cầu đến, anh ta thấy nếu có một phương thức cần được thực thi và gọi phương thức thích hợp. Điều này có nghĩa là bạn có thể kiểm soát lịch biểu trong cơ sở dữ liệu của mình , nơi bạn có thể đã có rất nhiều dữ liệu cấu hình quan trọng khác cho trang web của mình.

Quan trọng hơn (đối với bạn), điều này có nghĩa là công việc của bạn không phải được gọi theo lịch trình cố định. Bạn có thể viết bất kỳ logic nào bạn muốn xác định khi nào thực hiện một phương thức.

Ưu và nhược điểm

Ưu
  • Bạn đã rất giỏi trong việc viết mã ASP.NET MVC, vì vậy điều này cho phép bạn viết các tác vụ nền của mình trong cùng một nền tảng mà bạn viết phần còn lại của giải pháp.
  • Các tác vụ chạy trong cùng ngữ cảnh với ứng dụng web của bạn, vì vậy bạn có thể chia sẻ bộ đệm và sử dụng các phương thức trợ giúp đã tồn tại.
  • Nếu bạn đã tìm nạp URI cân bằng tải , thì các tác vụ nền của bạn giờ cũng được cân bằng tải.
  • Triển khai đồng thời - bạn không phải lo lắng về việc đồng bộ hóa ứng dụng web của mình với logic tác vụ nền, bởi vì tất cả chúng đều nằm trong cùng một triển khai.
Nhược điểm
  • Trong nhiều năm, một vài người đã nói với tôi rằng thiết kế này là "rất khớp", nhưng khi nhấn họ không thể nói rõ tại sao đó là một điều xấu.

Lưu ý: Nếu có bất kỳ câu hỏi hoặc mối quan tâm, xin vui lòng thêm một nhận xét . Tôi rất vui được giải thích.


7

Tôi đã thử và sử dụng mọi cách có thể để làm điều này trong ứng dụng hiện tại của mình. Tôi bắt đầu làm điều tương tự như bạn hiện đang làm, cõng theo yêu cầu của người dùng để điền dữ liệu và sau đó lưu trữ bộ đệm. Tôi nhận ra đây cũng là một ý tưởng tồi (đặc biệt là khi bạn mở rộng quy mô cho nhiều máy chủ web, nhiều người dùng sẽ gặp khó khăn hơn).

Tôi cũng đã có một công việc được lên lịch truy cập một URL trong ứng dụng ASP.NET - đây là một giải pháp hợp lý nhưng nó bắt đầu phá vỡ phút bạn mở rộng quy mô 1 máy chủ web.

Hiện tại tôi sử dụng hai phương pháp khác nhau, cả hai đều sử dụng Quartz.NET, đây là một thư viện nhỏ tuyệt vời. Đầu tiên là Quartz.NET chạy trong tiến trình với ASP.NET, nó được thiết lập trong global.asax và chạy cứ sau vài phút. Tôi sử dụng điều này để cập nhật bộ đệm ASP.NET ra khỏi băng tần, đó là lý do duy nhất nó được chạy như một phần của ASP.NET.

Thứ hai là tôi đã viết một thư viện để bọc Quartz.NET có tên là DaemonMaster - nó giúp dễ dàng thả một DLL vào một thư mục và để nó chạy trong một dịch vụ Windows. Tôi thấy nó giúp tránh một số phần khó chịu khi làm việc với Dịch vụ Windows và cũng dọn sạch một số ứng dụng Quartz.NET. Các dịch vụ chạy qua DaemonMaster có hai hương vị khác nhau, đầu tiên là các công việc cần chạy mỗi đêm hoặc mỗi X phút. Các công việc khác hoạt động theo hàng đợi dựa trên dữ liệu đến từ ứng dụng ASP.NET. Ứng dụng ASP.NET loại bỏ các đối tượng JSON trên RabbitMQ và các dịch vụ thăm dò RabbitMQ sau đó xử lý dữ liệu.

Dựa trên điều này, tôi khuyên bạn nên sử dụng dịch vụ Windows (và kiểm tra DaemonMaster) và nếu cần sử dụng hàng đợi như RabbitMQ để truyền dữ liệu từ ứng dụng ASP.NET sang các dịch vụ - nó đã hoạt động tốt nhất trong tất cả các giải pháp này . Nếu bạn đang tải bộ đệm thì chạy trong ASP.NET có ý nghĩa, nếu không tôi không nghĩ vậy.


6

Tôi sẽ thực hiện đúng cách và có một Dịch vụ Windows đang chạy theo dõi "hàng đợi". Tôi nói "xếp hàng" bởi vì lập trình w / MSMQ gần giống với việc dán những con pokemon nóng bỏng vào nhãn cầu của bạn.

Tôi đã yêu sự đơn giản của Delayed :: Job in Rails, và một cái gì đó tương tự có thể dễ dàng được thực hiện trong .NET.

Về cơ bản, bạn thêm bất kỳ loại nào SomethingOperation(một cái gì đó có một Perform()phương thức). Sau đó, chỉ cần tuần tự hóa các tham số có liên quan, ưu tiên nó, một số loại hành vi thử lại mặc định và nhét nó vào cơ sở dữ liệu.

Dịch vụ của bạn sẽ chỉ giám sát điều này và thực hiện các công việc trong hàng đợi.


Việc nối tiếp các tham số có liên quan không thực sự là "chỉ", nó gần như là "tất cả". Đây là một trong những bảo lưu lớn hơn của tôi về cách tiếp cận quá trình riêng biệt ...
Kevin Montrose

Vâng, đó là loại giải pháp tương tự mà tôi đã sử dụng, tuy nhiên tôi đã tuần tự hóa toàn bộ đối tượng vào cơ sở dữ liệu dưới dạng nhị phân và sau đó kéo chúng ra để thực thi. Tôi đã sử dụng Cassandra làm bộ lưu trữ liên tục và Trình lập lịch tác vụ làm trình lập lịch CRON của mình cho ứng dụng dòng lệnh sẽ chạy và thực thi các tác vụ.
Nick Berardi

Chúng tôi bắt đầu bằng cách chỉ bao gồm một mẩu dữ liệu đơn giản trong tin nhắn và cuối cùng ném toàn bộ đối tượng. Nó vẫn làm việc tuyệt vời. Tôi sẽ xem xét sự tách biệt vì nó cũng có những lợi ích khác.
Nathan Palmer

@Kevin - nếu chúng ta có một số người có nhiều lịch sử tuần tự ....
Marc Gravell

4

Chúng tôi đã khá hài lòng với cách tiếp cận Dịch vụ / Hàng đợi Tin nhắn / Dịch vụ. Kiến trúc cơ bản là thế này.

Trang web gửi tin nhắn để xếp hàng

bus.Send(new ProjectApproved()); // returns immediately

Dịch vụ Windows nhận và xử lý tin nhắn trong thời gian riêng của mình

public class DoesSomethingAwesome : ConsumerOf<ProjectApproved>
{
   public void Consume(ProjectApproved Message)
   {
      // Do something "offline"
   }
}

Ưu điểm là không có độ trễ cho dịch vụ front-end mà người dùng cũng được kết nối. Dịch vụ windows có thể được tắt và được nâng cấp mà không bị gián đoạn đến trang chính. Thêm vào đó, nó cực kỳ nhanh .

Nếu bạn không thể lưu trữ tất cả dữ liệu của mình trong tin nhắn, bạn luôn có thể lưu trữ và truy xuất dữ liệu đó sau. Tôi đề nghị sử dụng một cơ chế lưu trữ tài liệu, chẳng hạn như: RavenDB hoặc MongoDB , nơi rất dễ dàng để lưu trữ các lớp của bạn mà không thay đổi.

Trang web gửi tin nhắn để xếp hàng

// Save your object
store.Save(completeProject);

// Send a message indicating its ready to be processed
bus.Send(new ProjectApproved() { ProjectId = completeProject.Id });

Dịch vụ Windows nhận và xử lý tin nhắn trong thời gian riêng của mình

public class DoesSomethingAwesome : ConsumerOf<ProjectApproved>
{
   public void Consume(ProjectApproved Message)
   {
      // Retrieve your object back
      var completeProject = store.Get(Message.ProjectId);
   }
}

Để làm cho mọi thứ đơn giản, chúng tôi sử dụng: Rhino ESBTopshelf . Cấu hình cực kỳ đơn giản và áp dụng điều này cho một ứng dụng hiện có đã chứng tỏ mất rất ít thời gian.


Dù sao, sử dụng xe buýt dịch vụ với CQRS luôn là một cách tốt để cải thiện khả năng mở rộng của bạn
thinkbeforecoding

3

Tôi tò mò tại sao sự kết hợp của cả hai không phải là một lựa chọn khả thi. Ngay bây giờ, bạn kích hoạt công việc trên lượt xem trang, với một số sap không may bị kẹt chờ 10 giây để trang xuất hiện. Ít nhất đó là sự hiểu biết của tôi về phương pháp hiện tại của bạn.

Tuy nhiên, những công việc đó đang mất nhiều thời gian hơn để chạy khi trang web phát triển và bạn không muốn làm hỏng trải nghiệm người dùng trên trang web. Thậm chí không dành cho một số ít (hoặc có thể rất nhiều) người dùng xui xẻo suốt cả ngày, vì vậy bây giờ bạn đang nghĩ về việc lên lịch cho các công việc trong nền.

Tôi không thấy lý do tại sao một công việc nền chạy đều đặn không thể bắt chước khách truy cập. Bây giờ tôi không phải là lập trình viên Windows, nhưng trong thế giới Linux, tôi sẽ thiết lập một công việc định kỳ chạy ở một khoảng thời gian thông thường và nó sẽ có 2 dòng mã.

#!/bin/bash
wget -O /dev/null http://stackoverflow.com/specially_crafted_url

Nó kết hợp những ưu điểm của cả hai hệ thống. Nó được thực hiện trong nền. Nó không ảnh hưởng đến người dùng. Nó vẫn sử dụng chế độ xem trang để khởi động công việc. Tôi đã thấy cách tiếp cận này được sử dụng trước đây. Nó có xu hướng là trung gian giữa những cách đơn giản cũ và những cách phức tạp hơn đi xuống đường.

Cập nhật

Tôi nghĩ bạn có thể giải quyết vấn đề cân bằng tải bằng cách chạy các trình chạy công việc trên các máy chủ web. Người chạy công việc kéo một URL ra khỏi hàng đợi công việc và chạy nó như vậy:

wget -O /dev/null http://localhost/specially_crafted_url

Do tính chất của hàng đợi công việc / nhắn tin, các công việc sẽ được phân bổ đồng đều giữa những người chạy công việc, điều đó có nghĩa là Special_crafted_url cuối cùng được phân phối giữa các máy chủ web của bạn.


Chúng tôi đã làm điều đó cho tất cả mọi thứ chạy trong khoảng thời gian dự đoán, những gì chúng tôi còn lại là những thứ không thể dự đoán trước quá xa. Chẳng hạn, "khối câu hỏi liên quan" chỉ được cập nhật cho những câu hỏi đã được xem gần đây. Các câu hỏi được gắn thẻ cũng tương tự chỉ được lưu trong bộ nhớ cache nếu có ai đó quan tâm để kiểm tra các thẻ đó. Vì chúng tôi có hơn một triệu câu hỏi và tiếp cận thẻ 25 nghìn, chúng tôi không thể chạy tất cả các tác vụ liên quan (và đó chỉ là 2 ví dụ) "chỉ trong trường hợp."
Kevin Montrose

Ngoài ra còn có vấn đề cân bằng tải, vì SO được phân chia trên nhiều máy chủ. Về cơ bản, nếu bạn goto stackoverflow.com, bạn sẽ luôn truy cập cùng một máy chủ. Cách tiếp cận wget sẽ buộc chúng ta sắp xếp tất cả các nhiệm vụ cho một máy chủ (hoặc thực sự làm lại thiết lập cân bằng tải của chúng tôi), điều này sẽ thực sự đau đớn.
Kevin Montrose

Trở nên tốt đẹp nếu mọi thứ đã chạy đều đặn, phải không? Tôi hiểu những gì bạn đang nói, nhưng phương pháp được nêu ở trên (và tôi nghĩ được đề cập bởi một vài người khác) không thay đổi. Khi một lượt xem trang cho biết "đã đến lúc chạy công việc này", bạn sẽ dán công việc vào hàng đợi tin nhắn. Một công việc nền chạy dài chạy các công việc nó tìm thấy. Trong trường hợp này, các công việc không có gì nhiều hơn các URL cần được yêu cầu. hehe Bạn có thể có thể thiết lập điều này trên một máy chủ được chia sẻ 20 đô la một tháng, vì nó không cần cơ sở mã của bạn để chạy. Hãy xem Amazon SQS để biết dịch vụ nhắn tin dễ sử dụng.
gió mùa

Về vấn đề cân bằng tải. Ở đâu có ý chí, có một cách! Thay vì thực hiện yêu cầu stackoverflow.com, bạn có thể truy cập máy chủ một cách ngẫu nhiên bằng cách sử dụng địa chỉ IP của nó. Nếu bộ cân bằng tải kiểm tra cookie theo yêu cầu đường ống, bạn có thể giả mạo cookie. Nếu nó kiểm tra địa chỉ IP, bạn thậm chí có thể giả mạo điều đó (vì bạn không quan tâm đến phản hồi từ máy chủ).
mellow gió

Đồng ý rằng cân bằng tải không phải là một lý do không thực hiện điều này. Vì yêu cầu specially_crafted_urlđến từ một IP đã biết, bạn có thể thêm quy tắc vào bộ cân bằng tải của mình để thực hiện quay vòng chỉ cho các yêu cầu từ IP đó.
Portman

2

Tôi nghĩ rằng con với cách tiếp cận dịch vụ thuần túy là bạn có mã nằm rải rác trong dịch vụ và tránh xa ứng dụng cốt lõi.

Dưới đây là những gì chúng tôi đã thực hiện với các công việc không nhạy cảm với thời gian lớn, giúp giữ mã cùng nhau và đơn giản hóa dịch vụ:

  1. Tạo một hàng đợi công việc (trong bộ nhớ hoặc DB, bất kỳ sự kiên trì nào là cần thiết cho các loại công việc)
  2. Tạo một dịch vụ web sẽ thực thi các công việc được xếp hàng
  3. Ứng dụng dịch vụ đơn giản đã chết gọi dịch vụ web theo một khoảng thời gian xác định, để lại tất cả những thứ phức tạp (truy xuất công việc và thực thi) cho dịch vụ web trong cơ sở mã cơ sở của bạn.

Thậm chí đơn giản hơn, chỉ cần thực hiện cuộc gọi trong ứng dụng bảng điều khiển và sử dụng Trình lập lịch tác vụ hoặc VisualCron để biến cuộc gọi thành "dịch vụ".


1
Tôi đã có chính xác điều này trong một ứng dụng quan trọng tại nơi làm việc - Dịch vụ Windows kích hoạt ứng dụng web theo chu kỳ. Ứng dụng web vẫn không trạng thái, kéo trạng thái từ cơ sở dữ liệu theo yêu cầu. Làm việc một điều trị.
Bevan

1

Tôi thích TopShelf. Giữ sự đơn giản, nhưng vẫn thực hiện theo cách phù hợp khi chạy như một Dịch vụ Windows. Về cơ bản tạo Ứng dụng Console, thêm khoảng 15-20 dòng mã, sau đó cài đặt dưới dạng dịch vụ.

http://code.google.com.vn/p/topshelf/


1

Làm thế nào về việc có một dịch vụ Windows rất đơn giản chạy trên máy chủ web và định kỳ truy cập một URL bảo trì thực hiện các nhiệm vụ linh tinh của bạn. Có nó điều tiết bao nhiêu công việc nó làm trong bất kỳ yêu cầu nhất định.


1

Tôi sẽ nắm bắt xu hướng rõ ràng ở đây và đề nghị sử dụng mô hình trong IIS. Tôi đã sử dụng nó cho mình và nó hoạt động thực sự tốt. Thực sự không khó để thực hiện một lớp nhóm luồng tốt (trong nhiều năm qua, tôi đã mở rộng lớp nhóm luồng của mình để hỗ trợ tạo động và phá hủy các luồng, thử lại các công việc, v.v.). Ưu điểm là:

  • Không có dịch vụ bên ngoài để giám sát
  • Đơn giản thực hiện: không có quy trình xử lý chéo, không giám sát công việc nâng cao
  • Bạn vẫn còn trong quy trình IIS của mình, vì vậy bạn có thể thực hiện tất cả các hoạt động ghi nhật ký thông thường của mình, v.v. (không cần nhiều tệp nhật ký)
  • Triển khai đơn giản hóa mạnh mẽ (khi bạn cập nhật một dịch vụ, bạn phải dừng dịch vụ, sao chép các tệp, khởi động dịch vụ - đây là ngoài các cập nhật thông thường của bạn cho mã trang web)

Theo tôi, một giải pháp trong IIS chỉ đơn giản là "bước tiếp theo" từ việc cõng công việc lên các lượt xem trang ngẫu nhiên.


1

Resque là tốt đẹp. Hoặc thậm chí Kthxbye nếu bạn cần được thông báo về giá trị kết quả sau khi hoàn thành.

Cả Redis / Ruby dựa tho.

Thành thật mà nói, nếu bạn đang thực hiện một cách tiếp cận dựa trên dịch vụ, nó thực sự không cần phải được tích hợp siêu với nền tảng hiện tại của bạn, điều mà tôi cảm thấy là một lợi thế. Tôi hy vọng nó có thể là một hệ thống quên và sẽ chạy (với sự giám sát của một số loại) và hoàn thành công việc. Tôi không chắc chắn nó phải được chạy trên cùng một nền tảng vì nó chỉ cập nhật / sửa đổi thông tin cơ sở dữ liệu.

Khá chắc chắn rằng bạn có thể thoát khỏi nhiều hơn với chi phí thấp hơn rất nhiều nếu bạn nuôi loại này làm việc với một thực thể riêng biệt, đặc biệt là vì có vẻ như bạn đang xử lý các vấn đề luồng. Cả ResqueKthxbye đều chuyển việc xử lý ra các quy trình riêng biệt để cho phép HĐH xử lý đồng thời.

Resque

Kthxbye


Tôi phải thử Kthxbye nếu chỉ vì cái tên tuyệt vời!
Nathan Palmer

khá nhiều tuyệt vời. tiếp theo sẽ là ORLY? thư viện. có lẽ để theo dõi số liệu thống kê của một số loại ...;)
Lukas

0

Tôi sẽ sử dụng dịch vụ WCF được lưu trữ trên WAS để nghe Hàng đợi MSMQ.

Chuyên nghiệp

  • Cháy và quên tin nhắn một chiều từ ứng dụng web

  • Điều chỉnh và thử lại MSMQ / WCF

  • Đảm bảo giao hàng; D

  • Quản lý thư chết

  • Quá trình đóng góp

  • Kích hoạt WAS / MSMQ

Con

  • MSMQ (nó chưa chết ... Tuy nhiên)

Các tính năng MSMQ trong WCF làm cho việc sử dụng MSMQ thực sự tốt. Có bạn sẽ chảy máu trên cấu hình nhưng lợi ích sẽ lớn hơn sự hy sinh.


0

Tôi đã gặp phải điều này một vài lần khi phát triển các ứng dụng web. Chúng tôi đã giải quyết nó bằng cách tạo một ứng dụng bảng điều khiển windows thực hiện nhiệm vụ và tạo một tác vụ theo lịch trình chạy thường xuyên để thực hiện nhiệm vụ.


0

Bạn có thể chuyển sang một luồng nền (hoặc nhiều luồng nền) bằng Rx và một cái gì đó như sau:

var scheduler = new EventLoopScheduler( SchedulerThreadName );
_workToDo = new Subject<Action>();
var queueSubscription = _workToDo.ObserveOn( scheduler ).Subscribe( work => work() );
_cleanup = new CompositeDisposable( queueSubscription, scheduler );

Để sử dụng:

var work = () => { ... };
_workToDo.OnNext( work ); // Can also put on error / on complete in here

Lưu trữ tất cả những gì bên trong một lớp chỉ có một (hay còn gọi là đơn lẻ, nhưng thực hiện đúng cách - sử dụng bộ chứa IoC của bạn để xác định lối sống).

Bạn có thể kiểm soát kích thước của nhóm luồng, v.v. bằng cách viết lịch trình tùy chỉnh thay vì sử dụng EventLoopScheduler (chạy một luồng).


0

Tôi đã thực hiện loại điều này một vài lần. Trên các cửa sổ, tôi thiết lập một chương trình dòng lệnh python thực hiện một số thứ vào nhiều thời điểm khác nhau. Chương trình này cũng hiển thị giao diện xmlrpc trên một cổng. Sau đó, một công việc được lên lịch chạy mỗi phút và truy vấn các giao diện xmlrpc. Nếu họ không lên, nó cố gắng khởi động chúng. Nếu không thể, nó sẽ gửi email cho tôi.

Ưu điểm là công việc chạy không phải là cron hoặc lịch trình bị ràng buộc. Tôi có một công việc xử lý chạy mỗi giây, nhưng sẽ chờ đợi lâu hơn và lâu hơn giữa khi bắt đầu một công việc mới tùy thuộc vào việc nó có công việc phải làm hay không. Ngoài ra, nó có thể được sử dụng để hành động thông minh dựa trên kết quả. Có một lỗi 500? Có một sự chậm trễ thực sự dài? Làm việc gì khác. Thông báo cho dịch vụ khác. Vân vân.

Và cùng một hệ thống hoạt động trên unix, với những sửa đổi nhỏ.


0

Bản thân tôi không có câu trả lời cho bạn, nhưng vấn đề rung chuông - tôi nhớ một số người ngẫu nhiên thảo luận về nó trên một podcast .

Spolsky: Tôi nhận thấy một trong những câu hỏi bạn đã hỏi trên blog là bạn nên xử lý các nhiệm vụ định kỳ bảo trì nói chung như thế nào?

Atwood: Vâng.

Spolsky: Đó có phải là một đặc tính công bằng? Mỗi trang web đều có một số tác vụ mà bạn không muốn thực hiện tại thời điểm trang web đang tải, nhưng bạn muốn thực hiện với một số lần lặp lại.

Atwood: Ya, loại nhiệm vụ nền tảng của điều.

Spolsky: Ya, vậy bạn đã tìm ra điều gì?

Atwood: Chà, ban đầu tôi đã hỏi trên Twitter, vì tôi chỉ muốn một cái gì đó nhẹ cân. Tôi thực sự không muốn viết một dịch vụ windows. Tôi cảm thấy như đó là ra khỏi mã ban nhạc. Cộng với mã thực sự làm việc là một trang web trên thực tế, bởi vì với tôi đó là một đơn vị công việc hợp lý trên một trang web là một trang web. Vì vậy, nó thực sự giống như chúng tôi đang gọi lại vào trang web, nó giống như một yêu cầu khác trong trang web, vì vậy tôi đã xem nó như một thứ gì đó nên giữ nguyên, và cách tiếp cận nhỏ mà chúng tôi đã đưa ra được đề xuất cho tôi trên Twitter về cơ bản là để thêm một cái gì đó vào bộ đệm của ứng dụng khi hết hạn cố định, sau đó bạn có một cuộc gọi lại để khi hết hạn, nó sẽ gọi một chức năng nhất định, sau đó bạn thêm nó vào bộ đệm với cùng thời hạn.


1
Vâng, nó hoạt động cho các trang web nhỏ hơn nhiều so với StackOverflow đã trở thành. Quy mô là một vấn đề lớn ở đây, thật không may (hoặc may mắn thay, tùy thuộc vào cách bạn nhìn vào nó).
Kevin Montrose

@Kevin Montrose, tôi xin hoàn toàn không biết gì về tên miền ở đây. Bạn có thể giải thích lý do tại sao một (các) trang web bí mật thực hiện công việc (có thể trong các đơn vị nhỏ) và được gọi bởi một công việc trang / cron làm mới ở một nơi khác không thể mở rộng? Tôi không nghi ngờ bạn đúng, nhưng tôi rất thích học.
Oddthinking

đề xuất cụ thể của bạn (hết hạn bộ nhớ cache) không mở rộng vì tất cả các hết hạn bộ đệm (trong ASP.NET) chạy một luồng duy nhất (đó là một cách hack thông minh cho các trang web nhỏ hơn, như SO đã từng). Một tác vụ cron không mở rộng quy mô vì chúng tôi đã vượt quá một máy chủ (SO hiện 3 và vẫn đang phát triển) và bất kỳ tác vụ cron nào cũng sẽ tấn công một máy chủ (ít nhất, việc thay đổi bất biến đó sẽ thực sự đau đớn với tải của chúng tôi- thiết lập cân bằng). Một tác vụ cron cũng sẽ phải chạy thực sự thường xuyên, vì các tác vụ này được lặp lại theo thứ tự phút.
Kevin Montrose

Cần lưu ý rằng chúng tôi sử dụng lập lịch "kiểu cron" cho việc chạy thường xuyên hơn, khoảng thời gian cố định, các tác vụ đã có, những thứ như cấp huy hiệu và thông báo e-mail hàng ngày.
Kevin Montrose

0

Tổng quan về API Java hàng đợi

Khái niệm nhiệm vụ
Trong xử lý nền của Máy ứng dụng, tác vụ là mô tả đầy đủ về một đơn vị công việc nhỏ. Mô tả này bao gồm hai phần:

  • Một tải trọng dữ liệu tham số hóa nhiệm vụ.
  • Mã mà thực hiện các nhiệm vụ.

Các tác vụ như các móc nối web ngoại tuyến
May mắn thay, Internet đã cung cấp một giải pháp như vậy, dưới dạng một yêu cầu HTTP và phản hồi của nó. Tải trọng dữ liệu là nội dung của yêu cầu HTTP, chẳng hạn như các biến của biểu mẫu web, XML, JSON hoặc dữ liệu nhị phân được mã hóa. Tham chiếu mã là chính URL; mã thực tế là bất cứ logic nào mà máy chủ thực thi trong việc chuẩn bị phản hồi.


Tôi không đề xuất sử dụng api hàng đợi nhiệm vụ GAE, nhưng theo mô hình của họ. Họ đã suy nghĩ về nó trong một thời gian và đã viết một triển khai về nó.
antony.trupe

0

Làm tất cả

Thêm một tham số tùy chọn vào đường dẫn câu hỏi thực hiện công việc mà bạn hiện đang cõng theo yêu cầu của người dùng:

Phục vụ các tác vụ nền trên một trang web lớn

Tạo một ứng dụng bảng điều khiển chạy trên mỗi máy chủ và mở tệp nhị phân chia sẻ nhật ký IIS và đọc nó đến cuối tệp hiện tại. Sử dụng một trình theo dõi hệ thống tập tin hoặc một khoảng thời gian để đọc chuyển tiếp để thu thập các bản cập nhật khi IIS xóa nhật ký.

Sử dụng thông tin này để xác định những trang nào hiện đang được xem.

Sử dụng các url trang từ nhật ký được phân tích cú pháp để gọi phiên bản "extrastuff" của url trên localhost với một đối tượng webclient.

Thêm vào một số mã để chuyển đổi tệp vào cuối mỗi kỳ đăng nhập hoặc khởi động lại quy trình mỗi giai đoạn nhật ký.

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.