2012-09-06 26 views
35

Tôi là reading about AsyncControllers trong ASP.NET MVC. Có vẻ như lý do duy nhất tại sao chúng tồn tại là để các luồng IIS có thể được lưu lại trong khi công việc chạy dài được giao cho các chủ đề CLR thông thường, điều đó dường như rẻ hơn.Tại sao các luồng IIS lại quá quý giá so với các luồng CLR thông thường?

Tôi có một vài câu hỏi ở đây:

  • Tại sao những bài IIS quá đắt để biện minh cho toàn bộ kiến ​​trúc này được xây dựng để hỗ trợ bộ điều khiển không đồng bộ?
  • Làm cách nào để biết/định cấu hình số lượng chuỗi IIS đang chạy trong nhóm ứng dụng IIS của tôi?

Trả lời

37

ASP.NET xử lý các yêu cầu bằng cách sử dụng các luồng từ nhóm chuỗi .NET. Hồ bơi thread duy trì một nhóm các chủ đề đã phát sinh chi phí khởi tạo luồng. Do đó, các chủ đề này dễ sử dụng lại. Hồ bơi thread .NET cũng tự điều chỉnh. Nó giám sát CPU và sử dụng tài nguyên khác, và nó thêm chủ đề mới hoặc cắt kích thước hồ bơi thread khi cần thiết. Nói chung, bạn nên tránh tạo các chuỗi thủ công để thực hiện công việc. Thay vào đó, hãy sử dụng các chủ đề từ nhóm luồng. Đồng thời, điều quan trọng là đảm bảo rằng ứng dụng của bạn không thực hiện các hoạt động chặn có thời gian dài có thể nhanh chóng dẫn đến sự đói khát của nhóm luồng và các yêu cầu HTTP bị từ chối.

I/O đĩa, cuộc gọi dịch vụ web, đều bị chặn. Có tối ưu hóa tốt nhất bằng cách sử dụng các cuộc gọi không đồng bộ. Khi bạn thực hiện cuộc gọi async, asp.net giải phóng luồng của bạn và yêu cầu sẽ được gán cho một chuỗi khác khi hàm gọi lại được gọi.

Để cấu hình số lượng bài bạn có thể đặt:

<system.web> 
    <applicationPool maxConcurrentRequestsPerCPU="50" maxConcurrentThreadsPerCPU="0" requestQueueLimit="5000"/> 
</system.web> 

Tham khảo: ASP.NET Thread Usage on IIS 7.5, IIS 7.0, and IIS 6.0

Đây là những thiết lập đó Microsoft best practices recommend:

  • Set maxconnection đến 12 * # CPU. Cài đặt này kiểm soát số lượng kết nối HTTP gửi đi tối đa mà bạn có thể bắt đầu từ ứng dụng khách. Trong trường hợp này, ASP.NET là máy khách. Đặt kết nối tối đa thành 12 * # CPU.
  • Đặt maxIoThread thành 100. Cài đặt này kiểm soát số lượng chủ đề I/O tối đa trong nhóm chủ đề .NET. Số này được tự động nhân với số lượng CPU có sẵn. Đặt maxloThreads thành 100.
  • Đặt maxWorkerThreads thành 100. Cài đặt này kiểm soát số lượng chuỗi công việc tối đa trong nhóm chủ đề. Số này sau đó sẽ tự động nhân với số lượng CPU có sẵn. Đặt maxWorkerThreads thành 100.
  • Đặt minFreeThreads thành 88 * # trong số CPU. Cài đặt này được sử dụng bởi quy trình công nhân để xếp hàng tất cả các yêu cầu đến nếu số lượng các chuỗi có sẵn trong nhóm chủ đề giảm xuống dưới giá trị cho cài đặt này. Cài đặt này giới hạn hiệu quả số lượng yêu cầu có thể chạy đồng thời với maxWorkerThreads - minFreeThreads. Đặt minFreeThreads thành 88 * # của CPU. Điều này giới hạn số lượng yêu cầu đồng thời đến 12 (giả sử maxWorkerThreads là 100).
  • Đặt minLocalRequestFreeThreads thành 76 * # trong số CPU. Thiết lập này được sử dụng bởi quy trình công nhân để xếp hàng các yêu cầu từ localhost (trong đó ứng dụng Web gửi các yêu cầu đến một dịch vụ Web cục bộ) nếu số lượng các luồng có sẵn trong nhóm luồng nằm dưới số này. Cài đặt này tương tự như minFreeThread nhưng nó chỉ áp dụng cho các yêu cầu lưu trữ cục bộ từ máy tính cục bộ. Đặt minLocalRequestFreeThreads thành 76 * # của CPU.

Lưu ý: Các đề xuất được cung cấp trong phần này không phải là quy tắc. Họ là một điểm khởi đầu.

Bạn sẽ phải đánh giá ứng dụng của mình để tìm ứng dụng nào hoạt động tốt nhất cho ứng dụng của bạn.

+1

Hãy quan tâm đến giá trị cài đặt từ các phương pháp hay nhất của Microsoft, bài viết này được viết vào năm 2004 (!). Tuy nhiên, câu trả lời hay! –

+1

Tinh chỉnh các số trên thực sự hoạt động – jbro91837

6

Chủ đề IIS được lấy từ nhóm chỉ mặc định, được giới hạn theo mặc định dựa trên số lõi bộ xử lý. Nếu hàng đợi của luồng này được sao lưu, IIS sẽ ngừng đáp ứng các yêu cầu. Bằng cách sử dụng mã async, thread thread thread có thể được trả về pool trong khi hoạt động async diễn ra, cho phép IIS phục vụ nhiều yêu cầu hơn.

Mặt khác, sinh sản một chủ đề mới của riêng bạn không sử dụng một chuỗi hồ bơi chủ đề. Sinh ra một số lượng các chủ đề độc lập không được kiểm soát cũng có thể là một vấn đề, do đó, nó không phải là một chữa bệnh tất cả các sửa chữa cho vấn đề hồ bơi IIS thread. Đồng bộ IO thường được ưu tiên theo cả hai cách.

Để thay đổi số lượng chủ đề trong nhóm chủ đề, check here. Tuy nhiên, có lẽ bạn nên thực hiện thực sự tránh làm như vậy.

+0

Thậm chí nếu bạn sử dụng mã async thread bơi thread vẫn trói trong suốt thời gian tải lên tệp, nhưng phản hồi (gọi lại) có thể không sử dụng cùng một chuỗi. Ứng dụng có thể sử dụng chuỗi ban đầu để phục vụ một yêu cầu mới và phản hồi của bạn đối với việc tải lên tệp có thể được xếp hàng đợi, đúng không? –

3

Thực ra nội dung được viết trong article you have linked không đúng. Mẫu không đồng bộ không có ở đó để giải phóng "Chủ đề công nhân IIS cực tốn kém" và sử dụng trong nền một số "chủ đề giá rẻ" khác.

Mẫu không đồng bộ chỉ đơn giản là có chủ đề miễn phí. Bạn có thể hưởng lợi từ nó trong các tình huống mà bạn không cần các chủ đề của bạn (và tốt nhất là ngay cả với máy cục bộ của bạn).

tôi có thể đặt tên cho hai kịch bản ví dụ (cả I/O):

Đầu tiên:

  1. BeginRequest
  2. Bắt đầu tập tin async đọc
  3. trong tập tin đọc bạn không cần phải chủ đề của bạn - vì vậy các yêu cầu khác có thể sử dụng nó.
  4. Kết thúc tệp đọc - bạn nhận được chuỗi từ nhóm ứng dụng.
  5. Yêu cầu hoàn tất.

Và gần như giống hệt thứ hai:

  1. BeginRequest
  2. Bắt đầu cuộc gọi async dịch vụ WCF.
  3. chúng tôi có thể rời khỏi máy của chúng tôi và không cần chủ đề của chúng tôi - vì vậy các yêu cầu khác có thể sử dụng nó.
  4. Chúng tôi nhận phản hồi từ dịch vụ từ xa - chúng tôi nhận được một số chủ đề từ nhóm ứng dụng để tiếp tục.
  5. Yêu cầu hoàn tất.

Thường an toàn khi đọc msdn. Bạn có thể nhận thông tin về mẫu không đồng bộ here.

+4

Xin chào, tác giả của bài viết được tham chiếu tại đây. Có hai cách phẫu thuật aysnchronous thể được thực hiện trong hệ thống bất kỳ: * I/cổng hoàn thành O (mà là làm thế nào Node.js công trình) * Offloading nhiệm vụ dài chạy vào chủ đề khác (song song) là gì không rõ ràng tại thời điểm tôi đã viết bài báo đó (một năm rưỡi trước) là cách mà AsyncControllers thực sự làm việc dưới mui xe. Tất cả các tài liệu mà tôi tìm thấy chỉ đến tùy chọn # 2 - tất cả AsnycController đã thực hiện yêu cầu chạy dài của nó tới một chủ đề CLR (chuỗi giá rẻ, "xanh") và chờ cuộc gọi trở lại trước khi tham gia một nhân viên IIS chủ đề. – Aaronontheweb

+0

Nếu không thể nhìn thấy nguồn đến AspNetSynchronizationContext, thật khó để xem chính xác phương thức nào được sử dụng. Các tài liệu MSDN cập nhật làm cho nó âm thanh như cổng hoàn thành I/O, có ý nghĩa cho sự nhấn mạnh trên async Microsoft đã có trong 18 tháng kể từ khi tôi đã viết bài báo đó. Nếu bạn quan tâm, đây là nguồn của cách các phương thức hành động được gọi trên một AsyncController trong MVC4: http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/4ed8b6e9c8d1#src%2fSystem.Web.Mvc%2fAsync % 2fAsyncControllerActionInvoker.cs – Aaronontheweb

1

Dịch vụ web của chúng tôi cần theo thời gian để phân phối 100 yêu cầu/giây trong khi thời gian còn lại là 1 yêu cầu/giây. Analazyng IIS bản ghi chúng tôi phát hiện ra nó mất khoảng 28s khi burst xảy ra để phục vụ các cuộc gọi như vậy.

Áp dụng Microsoft best practices như được trích dẫn bởi @nunespascal giảm đáng kể thời gian xuống 1s trong trường hợp của chúng tôi.

Dưới đây là tập lệnh Powershell mà chúng tôi hiện đang sử dụng khi triển khai máy chủ sản xuất của mình. Nó cập nhật machine.config lấy số lượng bộ xử lý logic.

<# Get and backup current machine.config #> 
$path = "C:\Windows\Microsoft.Net\Framework\v4.0.30319\Config\machine.config"; 
$xml = [xml] (get-content($path)); 
$xml.Save($path + "-" + (Get-Date -Format "yyyyMMdd-HHmm") + ".bak"); 

<# Get number of physical CPU #> 
$physicalCPUs = ([ARRAY](Get-WmiObject Win32_Processor)).Count; 

<# Get number of logical processors #> 
$logicalProcessors = (([ARRAY](Get-WmiObject Win32_Processor))[0] | Select-Object “numberOfLogicalProcessors").numberOfLogicalProcessors * $physicalCPUs; 

<# Set Number of connection in system.net/connectionManagement #> 
$systemNet = $xml.configuration["system.net"]; 
if (-not $systemNet){ 
    $systemNet = $xml.configuration.AppendChild($xml.CreateElement("system.net")); 
} 

$connectionManagement = $systemNet.connectionManagement; 
if (-not $connectionManagement){ 

    $connectionManagement = $systemNet.AppendChild($xml.CreateElement("connectionManagement")); 
} 

$add = $connectionManagement.add; 
if(-not $add){ 
    $add = $connectionManagement.AppendChild($xml.CreateElement("add")) ; 
} 
$add.SetAttribute("address","*"); 
$add.SetAttribute("maxconnection", [string]($logicalProcessors * 12)); 

<# Set several thread settings in system.web/processModel #> 
$systemWeb = $xml.configuration["system.web"]; 
if (-not $systemWeb){ 
    $systemWeb = $xml.configuration.AppendChild($xml.CreateElement("system.web")); 
} 

$processModel = $systemWeb.processModel; 
if (-not $processModel){ 
    $processModel = $systemWeb.AppendChild($xml.CreateElement("processModel")); 
} 
$processModel.SetAttribute("autoConfig","true"); 
$processModel.SetAttribute("maxWorkerThreads","100"); 
$processModel.SetAttribute("maxIoThreads","100"); 
$processModel.SetAttribute("minWorkerThreads","50"); 
$processModel.SetAttribute("minIoThreads","50"); 

<# Set other thread settings in system.web/httRuntime #> 
$httpRuntime = $systemWeb.httpRuntime; 
if(-not $httpRuntime){ 
    $httpRuntime = $systemWeb.AppendChild($xml.CreateElement("httpRuntime")); 
} 
$httpRuntime.SetAttribute("minFreeThreads",[string]($logicalProcessors * 88)); 
$httpRuntime.SetAttribute("minLocalRequestFreeThreads",[string]($logicalProcessors * 76)); 

<#Save modified machine.config#> 
$xml.Save($path); 

Giải pháp này đến với chúng ta từ một blog article witten by Stuart Brierley trở lại trong năm 2009. Chúng tôi thành công thử nghiệm nó với Windows Server 2008 R2 từ đến 2016.

Các vấn đề liên quan