การเขียนเว็บแอปพลิเคชันโดยใช้ ASP.NET นั้นง่ายอย่างไม่น่าเชื่ออย่างไม่น่าเชื่อ เนื่องจากความเรียบง่ายนี้ นักพัฒนาจำนวนมากจึงไม่ใช้เวลาในการจัดโครงสร้างแอปพลิเคชันของตนเพื่อประสิทธิภาพที่ดีขึ้น ในบทความนี้ ฉันจะกล่าวถึงเคล็ดลับ 10 ข้อในการเขียนเว็บแอปพลิเคชันประสิทธิภาพสูง แต่ฉันจะไม่จำกัดคำแนะนำเหล่านี้ไว้เฉพาะแอปพลิเคชัน ASP.NET เนื่องจากแอปพลิเคชันเหล่านี้เป็นเพียงส่วนหนึ่งของเว็บแอปพลิเคชันเท่านั้น บทความนี้ไม่ได้มีจุดมุ่งหมายเพื่อเป็นแนวทางขั้นสุดท้ายในการปรับแต่งประสิทธิภาพเว็บแอปพลิเคชัน หนังสือทั้งเล่มไม่สามารถครอบคลุมหัวข้อนี้ได้อย่างง่ายดาย ถือว่าบทความนี้เป็นจุดเริ่มต้นที่ดี
ก่อนที่ฉันจะกลายเป็นคนบ้างาน ฉันเคยสนุกกับการปีนหน้าผา ก่อนที่จะปีนครั้งใหญ่ ฉันเริ่มต้นด้วยการดูเส้นทางในหนังสือคู่มืออย่างละเอียด และอ่านคำแนะนำจากผู้เยี่ยมชมคนก่อน แต่ไม่ว่าคู่มือจะดีแค่ไหน คุณต้องมีประสบการณ์การปีนหน้าผาจริงก่อนที่จะลองปีนหน้าผาที่ท้าทายเป็นพิเศษ ในทำนองเดียวกัน คุณสามารถเรียนรู้วิธีเขียนแอปพลิเคชันเว็บประสิทธิภาพสูงได้ก็ต่อเมื่อต้องเผชิญกับการแก้ไขปัญหาด้านประสิทธิภาพหรือใช้งานไซต์ที่มีปริมาณงานสูง
ประสบการณ์ส่วนตัวของฉันมาจากการทำงานเป็น Infrastructure Program Manager ในแผนก ASP.NET ที่ Microsoft ซึ่งฉันดูแลและจัดการ www.ASP.NET และช่วยออกแบบเซิร์ฟเวอร์ชุมชน ซึ่งเป็นหนึ่งในหลาย ๆ ที่รู้จักกันดี
แอปพลิเคชัน ASP.NET (ฟอรัม ASP.NET, .Text และ nGallery รวมกันเป็นแพลตฟอร์มเดียว) ฉันแน่ใจว่าเคล็ดลับบางอย่างที่ช่วยฉันจะช่วยคุณได้เช่นกัน
คุณควรพิจารณาแบ่งแอปพลิเคชันของคุณออกเป็นหลายเลเยอร์เชิงตรรกะ คุณอาจเคยได้ยินคำว่าสถาปัตยกรรมทางกายภาพ 3 ระดับ (หรือ n ระดับ) โดยทั่วไปแนวทางทางสถาปัตยกรรมที่กำหนดไว้จะแยกการทำงานทางกายภาพระหว่างกระบวนการและ/หรือฮาร์ดแวร์ เมื่อระบบจำเป็นต้องขยายก็สามารถเพิ่มฮาร์ดแวร์ได้มากขึ้นได้อย่างง่ายดาย อย่างไรก็ตาม มีปัญหาด้านประสิทธิภาพที่เกี่ยวข้องกับการข้ามกระบวนการและการข้ามเครื่อง และควรหลีกเลี่ยง ดังนั้น หากเป็นไปได้ ให้ลองเรียกใช้เพจ ASP.NET และส่วนประกอบที่เกี่ยวข้องร่วมกันในแอปพลิเคชันเดียวกัน
เนื่องจากการแยกโค้ดและขอบเขตระหว่างเลเยอร์ การใช้บริการเว็บหรือระยะไกลจะลดประสิทธิภาพลง 20% หรือมากกว่า
ชั้นข้อมูลจะแตกต่างกันเล็กน้อย เนื่องจากโดยทั่วไปแล้ว ควรมีฮาร์ดแวร์สำหรับฐานข้อมูลโดยเฉพาะจะดีกว่า อย่างไรก็ตาม ต้นทุนของกระบวนการกระโดดไปยังฐานข้อมูลยังคงสูง ดังนั้นประสิทธิภาพของชั้นข้อมูลจึงเป็นประเด็นแรกที่คุณควรพิจารณาเมื่อปรับโค้ดให้เหมาะสม
ก่อนที่คุณจะเจาะลึกการแก้ไขประสิทธิภาพสำหรับแอปพลิเคชันของคุณ ขั้นแรกตรวจสอบให้แน่ใจว่าคุณได้โปรไฟล์แอปพลิเคชันของคุณเพื่อระบุปัญหาเฉพาะ ตัวนับประสิทธิภาพหลัก เช่น เปอร์เซ็นต์ของเวลาที่ต้องใช้ในการดำเนินการรวบรวมขยะ ยังมีประโยชน์ในการค้นหาว่าแอปพลิเคชันใช้เวลาหลักที่ใด อย่างไรก็ตาม การใช้เวลาไปกับสถานที่นั้นมักจะไม่เป็นไปตามสัญชาตญาณมากนัก
บทความนี้อธิบายการปรับปรุงประสิทธิภาพสองชนิด: การเพิ่มประสิทธิภาพขนาดใหญ่ (เช่น การใช้แคช ASP.NET) และการเพิ่มประสิทธิภาพเล็กน้อยที่ทำซ้ำตัวเอง การเพิ่มประสิทธิภาพเล็กๆ น้อยๆ เหล่านี้บางครั้งก็น่าสนใจเป็นพิเศษ คุณทำการเปลี่ยนแปลงโค้ดเพียงเล็กน้อยและคุณจะได้รับเวลามากมาย ด้วยการเพิ่มประสิทธิภาพครั้งใหญ่ คุณอาจเห็นประสิทธิภาพโดยรวมเพิ่มขึ้นอย่างมาก ด้วยการปรับให้เหมาะสมเพียงเล็กน้อย คุณอาจประหยัดเวลาได้เพียงไม่กี่มิลลิวินาทีสำหรับคำขอหนึ่งๆ แต่เมื่อรวมเข้ากับคำขอทั้งหมดทุกวัน ก็สามารถปรับปรุงได้อย่างมาก
ประสิทธิภาพของชั้นข้อมูล
เมื่อพูดถึงการปรับแต่งประสิทธิภาพของแอปพลิเคชัน มีการทดสอบก้านวัดที่คุณสามารถใช้เพื่อจัดลำดับความสำคัญงานของคุณ: โค้ดเข้าถึงฐานข้อมูลหรือไม่ ถ้าเป็นเช่นนั้นความถี่ใด? โปรดทราบว่าการทดสอบเดียวกันนี้สามารถนำไปใช้กับโค้ดที่ใช้บริการเว็บหรือระยะไกลได้ แต่บทความนี้ไม่ครอบคลุมถึงสิ่งเหล่านี้
หากจำเป็นต้องมีการร้องขอฐานข้อมูลในเส้นทางรหัสเฉพาะ และคุณคิดว่าคุณจำเป็นต้องปรับพื้นที่อื่นๆ ให้เหมาะสมก่อน (เช่น การจัดการสตริง) ให้หยุดแล้วดำเนินการทดสอบก้านวัดนี้ หากปัญหาด้านประสิทธิภาพการทำงานของคุณไม่รุนแรง เป็นความคิดที่ดีที่จะใช้เวลาเพิ่มประสิทธิภาพเวลาที่ใช้โดยสัมพันธ์กับฐานข้อมูล จำนวนข้อมูลที่ส่งคืน และความถี่ของการเดินทางไปกลับจากฐานข้อมูล
เมื่อคำนึงถึงข้อมูลทั่วไปนี้แล้ว เรามาดูเคล็ดลับ 10 ประการที่อาจช่วยปรับปรุงประสิทธิภาพของแอปพลิเคชันกันดีกว่า ก่อนอื่น ฉันจะพูดถึงการเปลี่ยนแปลงที่อาจสร้างความแตกต่างมากที่สุด
เคล็ดลับ 1 — ส่งคืนชุดผลลัพธ์หลายชุด
ดูโค้ดฐานข้อมูลของคุณอย่างละเอียดเพื่อดูว่ามีหลายเส้นทางคำขอในฐานข้อมูลหรือไม่ การเดินทางไปกลับแต่ละครั้งจะลดจำนวนคำขอต่อวินาทีที่แอปพลิเคชันสามารถให้บริการได้ ด้วยการส่งคืนชุดผลลัพธ์หลายชุดในคำขอฐานข้อมูลเดียว คุณจะประหยัดเวลาโดยรวมที่ต้องใช้ในการสื่อสารกับฐานข้อมูลได้ ขณะเดียวกันยังทำให้ระบบสามารถปรับขนาดได้มากขึ้นโดยลดการทำงานของเซิร์ฟเวอร์ฐานข้อมูลในการจัดการคำขอ
แม้ว่าจะเป็นไปได้ที่จะใช้ไดนามิก SQL เพื่อส่งคืนชุดผลลัพธ์หลายชุด แต่วิธีที่ฉันชอบคือการใช้กระบวนงานที่เก็บไว้ มีการถกเถียงกันว่าตรรกะทางธุรกิจควรอยู่ใน Stored Procedure หรือไม่ แต่ฉันคิดว่ามันจะดีกว่าถ้าตรรกะใน Stored Procedure สามารถจำกัดข้อมูลที่ส่งคืนได้ (ลดขนาดของชุดข้อมูล ลดเวลาที่ใช้ใน เครือข่ายโดยไม่ต้องกรองข้อมูลผ่านชั้นตรรกะ) สิ่งนี้ควรได้รับการสนับสนุน
เมื่อเติมคลาสธุรกิจที่พิมพ์อย่างยิ่งโดยใช้อินสแตนซ์ SqlCommand และวิธีการ ExecuteReader คุณสามารถย้ายตัวชี้ชุดผลลัพธ์ไปข้างหน้าได้โดยการเรียก NextResult รูปที่ 1 แสดงเซสชันตัวอย่างโดยใช้คลาสประเภทเพื่อเติมข้อมูล ArrayLists หลายรายการ การส่งคืนเฉพาะข้อมูลที่คุณต้องการจากฐานข้อมูลจะลดการจัดสรรหน่วยความจำบนเซิร์ฟเวอร์เพิ่มเติม
รูปที่ 1 แยกชุดผลลัพธ์หลายชุดออกจาก DataReader
// อ่านชุดผลลัพธ์แรก
reader = command.ExecuteReader();
// อ่านข้อมูลจากชุดผลลัพธ์นั้น
ในขณะที่ (reader.Read()) {
ซัพพลายเออร์เพิ่ม (PopulateSupplierFromIDataReader (ผู้อ่าน));
}
// อ่านชุดผลลัพธ์ถัดไป
reader.NextResult();
// อ่านข้อมูลจากชุดผลลัพธ์ที่สองนั้น
ในขณะที่ (reader.Read()) {
ผลิตภัณฑ์เพิ่ม (PopulateProductFromIDataReader (ผู้อ่าน));
}
เคล็ดลับ 2 - การเข้าถึงข้อมูลแบบแบ่งหน้า
ASP.NET DataGrid มีคุณลักษณะที่ดี: รองรับการแบ่งหน้าข้อมูล เมื่อเปิดใช้งานเพจใน DataGrid จำนวนเรกคอร์ดคงที่จะแสดงในแต่ละครั้ง นอกจากนี้ UI การเพจจะแสดงที่ด้านล่างของ DataGrid เพื่ออำนวยความสะดวกในการนำทางระหว่างเรกคอร์ด UI การเพจช่วยให้คุณสามารถนำทางไปข้างหน้าและย้อนกลับผ่านข้อมูลที่แสดง และแสดงจำนวนเรกคอร์ดคงที่ในแต่ละครั้ง
นอกจากนี้ยังมีการบิดเล็กน้อย การแบ่งหน้าโดยใช้ DataGrid กำหนดให้ข้อมูลทั้งหมดถูกผูกไว้กับตาราง ตัวอย่างเช่น หากชั้นข้อมูลของคุณจำเป็นต้องส่งคืนข้อมูลทั้งหมด DataGrid จะกรองบันทึกทั้งหมดที่แสดงตามหน้าปัจจุบัน หากส่งคืนระเบียน 100,000 รายการเมื่อเพจผ่าน DataGrid ระเบียน 99,975 รายการจะถูกละทิ้งสำหรับแต่ละคำขอ (สมมติว่ามีขนาดหน้า 25 ระเบียน) เมื่อจำนวนบันทึกเพิ่มขึ้น ประสิทธิภาพของแอปพลิเคชันจะลดลง เนื่องจากต้องส่งข้อมูลมากขึ้นเรื่อยๆ พร้อมคำขอแต่ละรายการ
วิธีที่ยอดเยี่ยมในการเขียนโค้ดการแบ่งหน้าที่มีประสิทธิภาพดีขึ้นคือการใช้ขั้นตอนการจัดเก็บ รูปที่ 2 แสดงตัวอย่างขั้นตอนการจัดเก็บสำหรับเพจตาราง Order ในฐานข้อมูล Northwind กล่าวโดยสรุป สิ่งที่คุณต้องทำ ณ จุดนี้คือส่งดัชนีหน้าและขนาดหน้า ชุดผลลัพธ์ที่เหมาะสมจะถูกคำนวณและส่งกลับ
รูปที่ 2 การเพจผ่านตารางคำสั่งซื้อ
สร้างขั้นตอน northwind_OrdersPaged
-
@PageIndex int,
@PageSize int
-
เช่น
เริ่ม
ประกาศ @PageLowerBound int
ประกาศ @PageUpperBound int
DECLARE @RowsToReturn int
-- ขั้นแรกให้ตั้งค่าจำนวนแถว
SET @RowsToReturn = @PageSize * (@PageIndex + 1)
SET ROWCOUNT @RowsToReturn
-- ตั้งค่าขอบเขตหน้า
SET @PageLowerBound = @PageSize * @PageIndex
SET @PageUpperBound = @PageLowerBound + @PageSize + 1
-- สร้างตารางชั่วคราวเพื่อจัดเก็บผลลัพธ์ที่เลือก
สร้างตาราง #PageIndex
-
IndexId int IDENTITY (1, 1) ไม่เป็นโมฆะ
รหัสคำสั่งซื้อ int
)
-- แทรกลงในตารางชั่วคราว
ใส่ลงใน #PageIndex (รหัสคำสั่งซื้อ)
เลือก
รหัสคำสั่งซื้อ
จาก
คำสั่งซื้อ
สั่งซื้อโดย
OrderID DESC
-- ส่งคืนจำนวนรวม
SELECT COUNT(OrderID) จากคำสั่งซื้อ
-- กลับผลลัพธ์แบบเพจ
เลือก
อ.*
จาก
คำสั่งโอ้
#ดัชนีเพจ ดัชนีเพจ
ที่ไหน
O.OrderID = PageIndex.OrderID และ
PageIndex.IndexID > @PageLowerBound และ
PageIndex.IndexID < @PageUpperBound
สั่งซื้อโดย
PageIndex.IndexID
END
ในเซิร์ฟเวอร์ชุมชน เราได้เขียนการควบคุมเซิร์ฟเวอร์เพจจิ้งเพื่อทำให้เพจข้อมูลทั้งหมดเสร็จสมบูรณ์ ดังที่คุณจะเห็น ฉันกำลังใช้แนวคิดที่กล่าวถึงในเคล็ดลับ 1 เพื่อส่งคืนชุดผลลัพธ์สองชุดจากขั้นตอนการจัดเก็บ: จำนวนบันทึกทั้งหมดและข้อมูลที่ร้องขอ
จำนวนบันทึกทั้งหมดที่ส่งคืนอาจแตกต่างกันไปขึ้นอยู่กับแบบสอบถามที่ดำเนินการ ตัวอย่างเช่น สามารถใช้ส่วนคำสั่ง WHERE เพื่อจำกัดข้อมูลที่ส่งคืนได้ ในการคำนวณจำนวนหน้าทั้งหมดที่แสดงใน UI ที่มีการแบ่งหน้า คุณต้องทราบจำนวนเรกคอร์ดทั้งหมดที่จะส่งคืน ตัวอย่างเช่น หากมีทั้งหมด 1,000,000 เรกคอร์ด และคุณต้องการใช้ส่วนคำสั่ง WHERE เพื่อกรองเหลือ 1,000 เรกคอร์ด ตรรกะการเพจจำเป็นต้องทราบจำนวนเรกคอร์ดทั้งหมดเพื่อแสดง UI การเพจอย่างถูกต้อง
เคล็ดลับ 3 — การรวมการเชื่อมต่อ
การตั้งค่าการเชื่อมต่อ TCP ระหว่างเว็บแอปพลิเคชันและ SQL Server อาจเป็นการดำเนินการที่ต้องใช้ทรัพยากรมาก นักพัฒนาซอฟต์แวร์ที่ Microsoft สามารถใช้การรวมการเชื่อมต่อมาระยะหนึ่งแล้ว ซึ่งช่วยให้พวกเขาสามารถใช้การเชื่อมต่อฐานข้อมูลซ้ำได้ แทนที่จะตั้งค่าการเชื่อมต่อ TCP ใหม่สำหรับทุกคำขอ พวกเขาตั้งค่าการเชื่อมต่อใหม่เฉพาะเมื่อไม่มีการเชื่อมต่อในกลุ่มการเชื่อมต่อเท่านั้น เมื่อการเชื่อมต่อถูกปิด การเชื่อมต่อจะกลับไปยังพูลการเชื่อมต่อซึ่งจะรักษาการเชื่อมต่อกับฐานข้อมูล แทนที่จะทำลายการเชื่อมต่อ TCP ทั้งหมด
แน่นอนว่าคุณต้องระมัดระวังหากคุณพัฒนาการเชื่อมต่อที่รั่ว เมื่อคุณใช้การเชื่อมต่อเสร็จแล้ว อย่าลืมปิดการเชื่อมต่อเหล่านั้น หากต้องการทำซ้ำ: ไม่ว่าใครจะพูดอะไรเกี่ยวกับการรวบรวมขยะใน Microsoft® .NET Framework อย่าลืมเรียกปิดหรือกำจัดการเชื่อมต่ออย่างชัดเจนเมื่อคุณใช้งานเสร็จแล้ว อย่าเชื่อถือ Common Language Runtime (CLR) เพื่อเคลียร์และปิดการเชื่อมต่อให้คุณตามเวลาที่กำหนดไว้ แม้ว่าในที่สุด CLR จะทำลายคลาสและบังคับให้ปิดการเชื่อมต่อ แต่ก็ไม่มีการรับประกันเมื่อการรวบรวมขยะของวัตถุเกิดขึ้นจริง
หากต้องการใช้การรวมการเชื่อมต่ออย่างเหมาะสม มีกฎบางอย่างที่ต้องปฏิบัติตาม ขั้นแรกให้เปิดการเชื่อมต่อ ดำเนินการ จากนั้นจึงปิดการเชื่อมต่อ หากคุณต้อง ให้เปิดและปิดการเชื่อมต่อหลายครั้งต่อคำขอ (ควรใช้เคล็ดลับที่ 1) แต่อย่าเปิดการเชื่อมต่อไว้ตลอดเวลาและส่งผ่านเข้าออกโดยใช้วิธีการต่างๆ ประการที่สอง ใช้สตริงการเชื่อมต่อเดียวกัน (และ ID เธรดเดียวกัน หากใช้การรับรองความถูกต้องแบบรวม) หากคุณไม่ได้ใช้สตริงการเชื่อมต่อเดียวกัน เช่น การปรับแต่งสตริงการเชื่อมต่อตามผู้ใช้ที่เข้าสู่ระบบ คุณจะไม่ได้รับค่าการปรับให้เหมาะสมแบบเดียวกับที่พูลการเชื่อมต่อมีให้ หากคุณใช้การรับรองความถูกต้องแบบรวมและเลียนแบบผู้ใช้จำนวนมาก ประสิทธิภาพของพูลการเชื่อมต่อก็จะลดลงอย่างมากเช่นกัน ตัวนับประสิทธิภาพข้อมูล .NET CLR จะมีประโยชน์เมื่อพยายามติดตามปัญหาด้านประสิทธิภาพใดๆ ที่เกี่ยวข้องกับการรวมพูลการเชื่อมต่อ
เมื่อใดก็ตามที่แอปพลิเคชันของคุณเชื่อมต่อกับทรัพยากร เช่น ฐานข้อมูลที่ทำงานในกระบวนการอื่น คุณควรปรับให้เหมาะสมโดยเน้นไปที่เวลาที่ใช้ในการเชื่อมต่อกับทรัพยากรนั้น เวลาที่ใช้ในการส่งหรือดึงข้อมูล และจำนวนการเดินทางไปกลับ การเพิ่มประสิทธิภาพการกระโดดกระบวนการใดๆ ในแอปพลิเคชันของคุณเป็นจุดแรกเพื่อให้ได้ประสิทธิภาพที่ดีขึ้น
ชั้นแอปพลิเคชันประกอบด้วยตรรกะในการเชื่อมต่อกับชั้นข้อมูลและแปลงข้อมูลให้เป็นอินสแตนซ์คลาสและกระบวนการทางธุรกิจที่มีความหมาย ตัวอย่างเช่น เซิร์ฟเวอร์ชุมชนที่คุณต้องการเติมข้อมูลในฟอรัมหรือคอลเลกชัน Threads ให้ใช้กฎทางธุรกิจ (เช่น สิทธิ์) และที่สำคัญที่สุด ดำเนินการแคชตรรกะที่นั่น
เคล็ดลับ 4 — ASP.NET Caching API
ก่อนที่จะเขียนบรรทัดโค้ดแอปพลิเคชัน สิ่งแรกที่ต้องทำคือจัดโครงสร้างเลเยอร์แอปพลิเคชันเพื่อใช้ประโยชน์สูงสุดจากความสามารถในการแคชของ ASP.NET
หากส่วนประกอบของคุณทำงานในแอปพลิเคชัน ASP.NET คุณจะต้องรวมการอ้างอิงถึง System.Web.dll ในโครงการแอปพลิเคชันเท่านั้น เมื่อคุณต้องการเข้าถึงแคช ให้ใช้คุณสมบัติ HttpRuntime.Cache (ออบเจ็กต์นี้ยังสามารถเข้าถึงได้ผ่าน Page.Cache และ HttpContext.Cache)
มีกฎหลายข้อสำหรับการแคชข้อมูล ประการแรก หากข้อมูลมีแนวโน้มที่จะถูกใช้หลายครั้ง นี่เป็นทางเลือกที่ดีแทนการใช้แคช ประการที่สอง หากข้อมูลเป็นแบบทั่วไปและไม่เฉพาะเจาะจงสำหรับคำขอหรือผู้ใช้เฉพาะ ข้อมูลนี้ก็เป็นตัวเลือกที่ดีสำหรับการแคชเช่นกัน หากข้อมูลนั้นเจาะจงสำหรับผู้ใช้หรือคำขอ แต่มีอายุยืนยาว ก็ยังสามารถแคชได้ แต่อาจไม่ได้ใช้บ่อยนัก ประการที่สาม กฎที่มักถูกมองข้ามคือบางครั้งคุณสามารถแคชได้มากเกินไป โดยทั่วไปในคอมพิวเตอร์ x86 เพื่อลดโอกาสที่จะเกิดข้อผิดพลาดหน่วยความจำไม่เพียงพอ คุณจะต้องเรียกใช้กระบวนการที่มีไบต์ส่วนตัวไม่เกิน 800MB ดังนั้นแคชควรมีขีดจำกัด กล่าวอีกนัยหนึ่ง คุณอาจสามารถนำผลลัพธ์ของการคำนวณกลับมาใช้ใหม่ได้ แต่หากการคำนวณนั้นใช้พารามิเตอร์ 10 ตัว คุณอาจพยายามแคชการเรียงสับเปลี่ยน 10 รายการ ซึ่งอาจทำให้คุณประสบปัญหาได้ คำร้องขอการสนับสนุน ASP.NET ที่พบบ่อยที่สุดประการหนึ่งคือข้อผิดพลาดหน่วยความจำไม่เพียงพอที่เกิดจากการแคชมากเกินไป โดยเฉพาะชุดข้อมูลขนาดใหญ่
การแคชมีคุณสมบัติที่ยอดเยี่ยมหลายประการที่คุณต้องรู้ ขั้นแรก แคชใช้อัลกอริธึมที่ใช้น้อยที่สุด ทำให้ ASP.NET บังคับให้ล้างแคช - ลบรายการที่ไม่ได้ใช้ออกจากแคชโดยอัตโนมัติ - เมื่อหน่วยความจำทำงานมีประสิทธิภาพน้อยลง ประการที่สอง แคชรองรับการขึ้นต่อกันที่หมดอายุแล้วซึ่งสามารถบังคับให้หมดอายุได้ การขึ้นต่อกันเหล่านี้รวมถึงเวลา คีย์ และไฟล์ มักใช้เวลา แต่ด้วย ASP.NET 2.0 จึงมีการแนะนำประเภทการทำให้ใช้ไม่ได้ใหม่และมีประสิทธิภาพยิ่งขึ้น: การทำให้แคชฐานข้อมูลใช้งานไม่ได้ หมายถึงการลบรายการในแคชโดยอัตโนมัติเมื่อข้อมูลในฐานข้อมูลเปลี่ยนแปลง สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการทำให้แคชฐานข้อมูลใช้ไม่ได้ โปรดดูคอลัมน์ Dino Esposito Cutting Edge ในนิตยสาร MSDN เดือนกรกฎาคม 2547 หากต้องการทำความเข้าใจสถาปัตยกรรมของแคช โปรดดูแผนภาพด้านล่าง
เคล็ดลับ 6 — การประมวลผลเบื้องหลัง
Path to Code ควรเร็วที่สุดเท่าที่จะเป็นไปได้ใช่ไหม? อาจมีบางครั้งที่คุณรู้สึกว่างานที่ดำเนินการกับทุกคำขอหรือทุกๆ n คำขอต้องใช้ทรัพยากรจำนวนมาก การส่งอีเมลหรือการวิเคราะห์และตรวจสอบข้อมูลขาเข้าเป็นเพียงตัวอย่างบางส่วน
เมื่อวิเคราะห์ ASP.NET Forums 1.0 และออกแบบสถาปัตยกรรมเนื้อหาที่ประกอบขึ้นเป็นเซิร์ฟเวอร์ชุมชนใหม่ เราพบว่าการเพิ่มเส้นทางรหัสการลงรายการบัญชีใหม่ทำได้ช้ามาก แต่ละครั้งที่มีการเพิ่มโพสต์ใหม่ แอปพลิเคชันจะต้องตรวจสอบให้แน่ใจก่อนว่าไม่มีโพสต์ที่ซ้ำกัน จากนั้นจะต้องวิเคราะห์โพสต์โดยใช้ตัวกรอง "คำที่ไม่เหมาะสม" วิเคราะห์อิโมติคอนตัวละครที่โพสต์ แท็กและจัดทำดัชนีโพสต์ และเพิ่ม โพสต์เมื่อมีการร้องขอ ไปที่คิวที่เหมาะสม ตรวจสอบสิ่งที่แนบมา และเมื่อโพสต์ครั้งสุดท้าย ให้ส่งการแจ้งเตือนทางอีเมลไปยังสมาชิกทุกคนทันที เห็นได้ชัดว่ามีส่วนเกี่ยวข้องมากมาย
หลังจากการวิจัยพบว่าเวลาส่วนใหญ่ถูกใช้ไปกับการจัดทำดัชนีตรรกะและการส่งอีเมล การโพสต์ดัชนีเป็นการดำเนินการที่ใช้เวลานานมาก และพบว่าฟังก์ชัน System.Web.Mail ในตัวเชื่อมต่อกับเซิร์ฟเวอร์ SMYP แล้วส่งอีเมลอย่างต่อเนื่อง เมื่อจำนวนสมาชิกสำหรับโพสต์หรือหัวข้อเฉพาะเพิ่มขึ้น ฟังก์ชัน AddPost จะใช้เวลาดำเนินการนานขึ้นเรื่อยๆ
ไม่จำเป็นต้องจัดทำดัชนีอีเมลสำหรับทุกคำขอ ตามหลักการแล้ว เราต้องการรวมการดำเนินการนี้เข้าด้วยกัน โดยจัดทำดัชนีการโพสต์ 25 รายการในแต่ละครั้ง หรือส่งอีเมลทั้งหมดทุกๆ ห้านาที เราตัดสินใจใช้โค้ดที่เราเคยใช้ก่อนหน้านี้เพื่อสร้างต้นแบบของการทำให้แคชข้อมูลใช้ไม่ได้ซึ่งใช้สำหรับสิ่งที่ลงเอยใน Visual Studio® 2005
คลาส Timer ในเนมสเปซ System.Threading มีประโยชน์มาก แต่ไม่ค่อยเป็นที่รู้จักใน .NET Framework อย่างน้อยก็ในหมู่นักพัฒนาเว็บ เมื่อสร้างแล้ว คลาส Timer นี้จะเรียกการเรียกกลับที่ระบุในช่วงเวลาที่กำหนดได้สำหรับเธรดใน ThreadPool ซึ่งหมายความว่าคุณสามารถตั้งค่าโค้ดของคุณให้ดำเนินการโดยไม่ต้องร้องขอขาเข้าไปยังแอปพลิเคชัน ASP.NET ซึ่งเหมาะสำหรับการประมวลผลในเบื้องหลัง คุณยังสามารถดำเนินการต่างๆ เช่น การจัดทำดัชนีหรือการส่งอีเมลในกระบวนการเบื้องหลังนี้ได้
อย่างไรก็ตาม มีปัญหาหลายประการเกี่ยวกับเทคโนโลยีนี้ หากถอนการติดตั้งโดเมนแอปพลิเคชัน อินสแตนซ์ตัวจับเวลานี้จะหยุดการทำงานของเหตุการณ์ นอกจากนี้ เนื่องจาก CLR มีมาตรฐานที่เข้มงวดสำหรับจำนวนเธรดต่อกระบวนการ อาจมีสถานการณ์ที่เซิร์ฟเวอร์มีการโหลดจำนวนมาก โดยที่ตัวจับเวลาอาจไม่มีเธรดให้ดำเนินการให้เสร็จสิ้น ในระดับหนึ่ง จะทำให้เกิดความล่าช้า ASP.NET พยายามลดโอกาสของเหตุการณ์นี้ให้เหลือน้อยที่สุด โดยการรักษาจำนวนเธรดที่พร้อมใช้งานในกระบวนการ และใช้เพียงส่วนหนึ่งของเธรดทั้งหมดสำหรับการประมวลผลคำขอ อย่างไรก็ตาม นี่อาจเป็นปัญหาได้หากคุณมีการดำเนินการแบบอะซิงโครนัสจำนวนมาก
พื้นที่ไม่เพียงพอสำหรับโค้ดนี้ แต่คุณสามารถดาวน์โหลดตัวอย่างที่อ่านได้ที่ www.rob-howard.net ดูสไลด์และการสาธิตจากการนำเสนอของ Blackbelt TechEd 2004
เคล็ดลับ 7 — การแคชเอาต์พุตเพจและพร็อกซีเซิร์ฟเวอร์
ASP.NET คือเลเยอร์การนำเสนอของคุณ (หรือควรเป็นเลเยอร์การนำเสนอของคุณ) ประกอบด้วยเพจ การควบคุมผู้ใช้ การควบคุมเซิร์ฟเวอร์ (HttpHandlers และ HttpModules) และเนื้อหาที่สร้างขึ้น หากคุณมีเพจ ASP.NET ที่สร้างเอาต์พุต (HTML, XML, รูปภาพหรือข้อมูลอื่น ๆ ) และเมื่อคุณเรียกใช้โค้ดนี้กับทุกคำขอ มันจะสร้างเอาต์พุตเดียวกัน แสดงว่าคุณมีเครื่องมือที่สามารถใช้กับ A ทางเลือกที่ดีสำหรับการแคชเอาต์พุตหน้า
เพิ่มบรรทัดเนื้อหานี้ที่ด้านบนของเพจ <%@ Page OutputCache VaryByParams="none" Duration="60" %>
คุณสามารถสร้างผลลัพธ์สำหรับเพจนี้ได้อย่างมีประสิทธิภาพเพียงครั้งเดียว แล้วนำมาใช้ใหม่หลายครั้งเป็นเวลาสูงสุด 60 วินาที ซึ่งในเวลานั้นเพจจะถูกดำเนินการอีกครั้ง และเอาต์พุตจะถูกเพิ่มลงในแคช ASP.NET อีกครั้ง ลักษณะการทำงานนี้สามารถทำได้โดยใช้ API แบบเป็นโปรแกรมระดับต่ำบางตัว มีการตั้งค่าที่สามารถกำหนดค่าได้หลายอย่างสำหรับการแคชเอาต์พุต เช่น คุณสมบัติ VaryByParams ที่เพิ่งกล่าวถึง VaryByParams เป็นเพียงการร้องขอ แต่ยังอนุญาตให้คุณระบุพารามิเตอร์ HTTP GET หรือ HTTP POST เพื่อเปลี่ยนรายการแคช ตัวอย่างเช่น เพียงตั้งค่า VaryByParam="Report" เป็นแคชเอาต์พุตสำหรับ default.aspx?Report=1 หรือ default.aspx?Report=2 สามารถระบุพารามิเตอร์เพิ่มเติมได้โดยการระบุรายการที่คั่นด้วยเครื่องหมายอัฒภาค
หลายๆ คนไม่ทราบว่าเมื่อมีการใช้เอาต์พุตแคช เพจ ASP.NET ยังสร้างส่วนหัว HTTP บางส่วนที่อยู่ที่ดาวน์สตรีมของเซิร์ฟเวอร์แคช เช่น ส่วนหัวที่ใช้โดย Microsoft Internet Security and Acceleration Server หรือ Akamai หลังจากตั้งค่าส่วนหัวแคช HTTP แล้ว เอกสารสามารถถูกแคชไว้บนทรัพยากรเครือข่ายเหล่านี้ และสามารถตอบสนองคำขอของไคลเอ็นต์ได้โดยไม่ต้องกลับไปยังเซิร์ฟเวอร์ต้นทาง
ดังนั้น การใช้แคชเอาต์พุตเพจจะไม่ทำให้แอปพลิเคชันของคุณมีประสิทธิภาพมากขึ้น แต่อาจลดภาระบนเซิร์ฟเวอร์ได้เนื่องจากเทคโนโลยีแคชดาวน์สตรีมแคชเอกสาร แน่นอนว่านี่อาจเป็นเพียงเนื้อหาที่ไม่ระบุชื่อ เมื่อส่งต่อไป คุณจะไม่เห็นคำขอเหล่านั้นอีก และคุณจะไม่สามารถดำเนินการตรวจสอบสิทธิ์เพื่อป้องกันการเข้าถึงได้อีกต่อไป
เคล็ดลับ 8 — เรียกใช้ IIS 6.0 (ใช้สำหรับแคชเคอร์เนล)
หากคุณไม่ได้ใช้ IIS 6.0 (Windows Server? 2003) คุณจะพลาดการปรับปรุงประสิทธิภาพที่ยอดเยี่ยมใน Microsoft Web Servers ในเคล็ดลับที่ 7 ฉันพูดถึงการแคชเอาต์พุต ใน IIS 5.0 คำขอจะผ่าน IIS จากนั้นเข้าสู่ ASP.NET เมื่อพูดถึงการแคช HttpModule ใน ASP.NET ได้รับการร้องขอและส่งกลับเนื้อหาของแคช
หากคุณใช้ IIS 6.0 คุณจะพบคุณลักษณะเล็กๆ น้อยๆ ที่เรียกว่าเคอร์เนลแคช ซึ่งไม่จำเป็นต้องเปลี่ยนโค้ดใดๆ ใน ASP.NET เมื่อมีการร้องขอสำหรับการแคชเอาต์พุตโดย ASP.NET แคชเคอร์เนล IIS จะได้รับสำเนาของข้อมูลที่แคชไว้ เมื่อคำขอมาจากไดรเวอร์เครือข่าย ไดรเวอร์ระดับเคอร์เนล (โดยไม่ต้องสลับบริบทไปยังโหมดผู้ใช้) จะได้รับคำขอ จากนั้นล้างข้อมูลแคชไปยังการตอบสนองหากแคชไว้ จากนั้นจึงดำเนินการให้เสร็จสิ้น ซึ่งหมายความว่าเมื่อคุณใช้การแคชโหมดเคอร์เนลกับการแคชเอาต์พุต IIS และ ASP.NET คุณจะเห็นผลลัพธ์ด้านประสิทธิภาพที่น่าทึ่ง ในระหว่างการพัฒนา ASP.NET ใน Visual Studio 2005 ฉันเป็นผู้จัดการโปรแกรมที่รับผิดชอบด้านประสิทธิภาพของ ASP.NET นักพัฒนาทำงานเฉพาะด้าน แต่ฉันได้เห็นการรายงานทั้งหมดที่เกิดขึ้นทุกวัน ผลลัพธ์แคชของโหมดเคอร์เนลนั้นน่าสนใจที่สุดเสมอ ลักษณะที่พบบ่อยที่สุดคือเครือข่ายเต็มไปด้วยคำขอ/การตอบกลับ ในขณะที่ IIS ทำงานโดยใช้ CPU เพียงประมาณ 5% เท่านั้น นี่มันน่าตกใจ! แน่นอนว่ามีเหตุผลอื่นในการใช้ IIS 6.0 แต่การแคชโหมดเคอร์เนลเป็นเหตุผลที่ชัดเจนที่สุด
เคล็ดลับ 9 — ใช้การบีบอัด Gzip
แม้ว่าการใช้ gzip จะไม่ใช่เคล็ดลับประสิทธิภาพของเซิร์ฟเวอร์เสมอไป (เนื่องจากคุณอาจเห็นการใช้งาน CPU เพิ่มขึ้น) การใช้การบีบอัด gzip สามารถลดจำนวนไบต์ที่เซิร์ฟเวอร์ส่งได้ ส่งผลให้ความเร็วของเพจเพิ่มขึ้นอย่างเห็นได้ชัดและลดการใช้แบนด์วิธ ขึ้นอยู่กับข้อมูลที่ถูกส่ง จำนวนที่สามารถบีบอัดได้ และเบราว์เซอร์ไคลเอนต์รองรับหรือไม่ (IIS จะส่งเฉพาะเนื้อหาที่บีบอัด gzip ไปยังไคลเอนต์ที่รองรับการบีบอัด gzip เช่น Internet Explorer 6.0 และ Firefox) เซิร์ฟเวอร์ของคุณสามารถให้บริการได้ คำขอเพิ่มเติม ในความเป็นจริง เกือบทุกครั้งที่คุณลดปริมาณข้อมูลที่ส่งคืน คุณจะเพิ่มจำนวนคำขอต่อวินาที
การบีบอัด Gzip มีอยู่ใน IIS 6.0 และประสิทธิภาพดีกว่าการบีบอัด gzip ที่ใช้ใน IIS 5.0 มาก ซึ่งเป็นข่าวดี ขออภัย เมื่อพยายามเปิดการบีบอัด gzip ใน IIS 6.0 คุณอาจไม่พบการตั้งค่าในกล่องโต้ตอบคุณสมบัติของ IIS ทีมงาน IIS ได้สร้างฟังก์ชัน gzip ที่ยอดเยี่ยมไว้ในเซิร์ฟเวอร์ แต่ลืมใส่ UI การดูแลระบบเพื่อเปิดใช้งาน หากต้องการเปิดใช้งานการบีบอัด gzip คุณต้องเจาะลึกการตั้งค่าการกำหนดค่า XML ของ IIS 6.0 (เพื่อที่คุณจะได้ไม่ใจอ่อน) โดยบังเอิญ เครดิตไปที่ Scott Forsyth จาก OrcsWeb ที่ช่วยฉันแจ้งปัญหานี้กับเซิร์ฟเวอร์ www.asp.net ที่โฮสต์บน OrcsWeb
บทความนี้จะไม่อธิบายขั้นตอนต่างๆ โปรดอ่านบทความของ Brad Wilson ที่ IIS6 Compression นอกจากนี้ยังมีบทความฐานความรู้เกี่ยวกับการเปิดใช้งานการบีบอัดสำหรับ ASPX ที่เปิดใช้งานการบีบอัด ASPX ใน IIS อย่างไรก็ตาม คุณควรทราบว่า เนื่องจากรายละเอียดการใช้งานบางอย่าง การบีบอัดแบบไดนามิกและการแคชเคอร์เนลจึงไม่สามารถอยู่พร้อมกันใน IIS 6.0
เคล็ดลับ 10 — สถานะมุมมองการควบคุมเซิร์ฟเวอร์
View state เป็นชื่อที่น่าสนใจสำหรับ ASP.NET ที่เก็บข้อมูลสถานะบางส่วนไว้ในฟิลด์เอาต์พุตที่ซ่อนอยู่ของเพจที่สร้างขึ้น เมื่อเพจถูกโพสต์กลับไปยังเซิร์ฟเวอร์ เซิร์ฟเวอร์สามารถแยกวิเคราะห์ ตรวจสอบ และใช้ข้อมูลสถานะมุมมองนี้กลับไปยังโครงสร้างการควบคุมของเพจ สถานะการดูเป็นคุณลักษณะที่มีประสิทธิภาพมากเนื่องจากช่วยให้สามารถคงสถานะไว้กับไคลเอ็นต์ได้ และไม่ต้องใช้คุกกี้หรือหน่วยความจำเซิร์ฟเวอร์ในการบันทึกสถานะนี้ ตัวควบคุมเซิร์ฟเวอร์ ASP.NET จำนวนมากใช้สถานะมุมมองเพื่อคงการตั้งค่าที่สร้างขึ้นระหว่างการโต้ตอบกับองค์ประกอบของเพจ เช่น การบันทึกเพจปัจจุบันที่จะแสดงเมื่อมีการแบ่งหน้าข้อมูล
อย่างไรก็ตาม การใช้ view state ก็มีข้อเสียอยู่บ้างเช่นกัน ขั้นแรก เพิ่มการโหลดโดยรวมบนเพจทุกครั้งที่มีการแสดงหรือร้องขอ ค่าใช้จ่ายเพิ่มเติมยังเกิดขึ้นเมื่อซีเรียลไลซ์หรือดีซีเรียลไลซ์ข้อมูลสถานะมุมมองที่โพสต์กลับไปยังเซิร์ฟเวอร์ ในที่สุด สถานะการดูจะเพิ่มการจัดสรรหน่วยความจำบนเซิร์ฟเวอร์
การควบคุมเซิร์ฟเวอร์หลายตัวมีแนวโน้มที่จะใช้สถานะการดูมากเกินไปแม้ว่าจะไม่จำเป็นก็ตาม ซึ่งอันที่โด่งดังที่สุดคือ DataGrid ลักษณะการทำงานเริ่มต้นของคุณสมบัติ ViewState เปิดอยู่ แต่คุณสามารถปิดได้ที่ระดับการควบคุมหรือหน้าหากไม่ต้องการ ภายในตัวควบคุม เพียงตั้งค่าคุณสมบัติ EnableViewState เป็นเท็จ หรือตั้งค่าส่วนกลางบนเพจโดยใช้การตั้งค่าต่อไปนี้:
<%@ หน้า EnableViewState="false" %><
หากคุณไม่โพสต์กลับเพจ หรือสร้างการควบคุมบนเพจใหม่ทุกครั้งในทุกคำขอ คุณควรปิดการใช้งานสถานะการดูที่ระดับเพจ
ฉันได้ให้คำแนะนำที่เป็นประโยชน์แก่คุณเมื่อเขียนแอปพลิเคชัน ASP.NET ประสิทธิภาพสูง ดังที่ได้กล่าวไปแล้วในบทความนี้ นี่เป็นคำแนะนำเบื้องต้นและไม่ใช่คำสุดท้ายเกี่ยวกับประสิทธิภาพของ ASP.NET (สำหรับข้อมูลเกี่ยวกับการปรับปรุงประสิทธิภาพของแอปพลิเคชัน ASP.NET โปรดดูการปรับปรุงประสิทธิภาพ ASP.NET) วิธีที่ดีที่สุดในการแก้ปัญหาประสิทธิภาพเฉพาะสามารถพบได้จากประสบการณ์ของคุณเท่านั้น อย่างไรก็ตาม เคล็ดลับเหล่านี้ควรให้คำแนะนำที่ดีแก่คุณในการเดินทางของคุณ ในการพัฒนาซอฟต์แวร์ มีเพียงไม่กี่อย่างเท่านั้นที่ทุกแอปพลิเคชันมีเอกลักษณ์เฉพาะตัว