ในสภาพแวดล้อมของวิศวกร SRE/DevOps จะไม่แปลกใจเลยที่วันหนึ่งลูกค้า (หรือระบบตรวจสอบ) ปรากฏขึ้นและรายงานว่า "ทุกอย่างหายไป": ไซต์ไม่ทำงาน การชำระเงินไม่ผ่าน ชีวิตกำลังเสื่อมถอย ... ไม่ว่าคุณต้องการช่วยในสถานการณ์เช่นนี้มากแค่ไหน การทำเช่นนี้อาจเป็นเรื่องยากมากหากไม่มีเครื่องมือที่ง่ายและเข้าใจได้ บ่อยครั้งที่ปัญหาซ่อนอยู่ในโค้ดของแอปพลิเคชัน คุณเพียงแค่ต้องแปลเป็นภาษาท้องถิ่น
และด้วยความโศกเศร้าและความสุข...
มันเกิดขึ้นจนเราหลงรัก New Relic มานานและลึกซึ้ง มันเป็นและยังคงเป็นเครื่องมือที่ยอดเยี่ยมสำหรับการตรวจสอบประสิทธิภาพของแอปพลิเคชัน และยังช่วยให้คุณกำหนดสถาปัตยกรรมไมโครเซอร์วิส (โดยใช้เอเจนต์) และอื่นๆ อีกมากมาย และทุกอย่างคงจะดีมากถ้าไม่ใช่เพราะการเปลี่ยนแปลงนโยบายการกำหนดราคาของบริการ: ค่า
สถานการณ์ปกติ: ไม่จำเป็นต้องใช้ของที่ระลึกใหม่ "ถาวร" แต่จะจดจำได้เฉพาะช่วงเวลาที่เกิดปัญหาเท่านั้น แต่คุณยังต้องจ่ายเป็นประจำ (140 USD ต่อเซิร์ฟเวอร์ต่อเดือน) และในโครงสร้างพื้นฐานคลาวด์ที่ปรับขนาดอัตโนมัติ จำนวนเงินรวมกันค่อนข้างมาก แม้ว่าจะมีตัวเลือก Pay-As-You-Go แต่การเปิดใช้งาน New Relic จะทำให้คุณต้องรีสตาร์ทแอปพลิเคชัน ซึ่งอาจนำไปสู่การสูญเสียสถานการณ์ปัญหาที่เริ่มต้นทั้งหมดได้ ไม่นานมานี้ New Relic ได้เปิดตัวแผนภาษีใหม่ -
ด้วยเหตุนี้ เราจึงเริ่มคิดที่จะมองหาทางเลือกที่ถูกกว่า และเราเลือกบริการสองอย่าง: Datadog และ Atatus ทำไมพวกเขา?
เกี่ยวกับคู่แข่ง
ให้ฉันพูดทันทีว่ามีวิธีแก้ไขปัญหาอื่น ๆ ในตลาด เรายังพิจารณาตัวเลือกโอเพ่นซอร์สด้วย แต่ไม่ใช่ว่าลูกค้าทุกรายจะมีความจุฟรีในการโฮสต์โซลูชันที่โฮสต์เอง... - นอกจากนี้ พวกเขายังต้องการการบำรุงรักษาเพิ่มเติมอีกด้วย คู่ที่เราเลือกกลายเป็นคู่ที่ใกล้เคียงที่สุด ความต้องการของเรา:
- การสนับสนุนในตัวและการพัฒนาสำหรับแอปพลิเคชัน PHP (สแต็กของลูกค้าของเรามีความหลากหลายมาก แต่นี่เป็นผู้นำที่ชัดเจนในบริบทของการค้นหาทางเลือกอื่นแทน New Relic)
- ต้นทุนที่เหมาะสม (น้อยกว่า 100 USD ต่อเดือนต่อโฮสต์)
- เครื่องมือวัดอัตโนมัติ
- บูรณาการกับ Kubernetes
- ความคล้ายคลึงกับอินเทอร์เฟซ New Relic นั้นเป็นข้อดีที่เห็นได้ชัดเจน (เพราะวิศวกรของเราคุ้นเคยกับมัน)
ดังนั้นในขั้นตอนการคัดเลือกเบื้องต้น เราได้ขจัดโซลูชันยอดนิยมอื่นๆ ออกไปหลายประการ โดยเฉพาะอย่างยิ่ง:
- Tideways, AppDynamics และ Dynatrace - สำหรับต้นทุน;
- Stackify ถูกบล็อกในสหพันธรัฐรัสเซียและแสดงข้อมูลน้อยเกินไป
ส่วนที่เหลือของบทความมีโครงสร้างในลักษณะที่จะนำเสนอวิธีแก้ปัญหาที่เป็นปัญหาก่อน หลังจากนั้นฉันจะพูดถึงปฏิสัมพันธ์ทั่วไปของเรากับ New Relic และประสบการณ์/ความประทับใจจากการดำเนินการที่คล้ายกันในบริการอื่น ๆ
การนำเสนอของผู้แข่งขันที่ได้รับการคัดเลือก
เกี่ยวกับ
อย่างไรก็ตาม New Relic Agent ทำงานบนโปรโตคอลที่เป็นกรรมสิทธิ์และไม่รองรับ OpenTracing เครื่องมือขั้นสูงจำเป็นต้องมีการแก้ไขสำหรับ New Relic โดยเฉพาะ ท้ายที่สุด การสนับสนุน Kubernetes ยังอยู่ในช่วงทดลอง
เริ่มพัฒนาในปี 2010
เมื่อใช้ Datadog เราพบว่าบางครั้งสร้างแผนที่ไมโครเซอร์วิสไม่ถูกต้อง และมีข้อบกพร่องทางเทคนิคบางประการ ตัวอย่างเช่น ระบุประเภทบริการอย่างไม่ถูกต้อง (เข้าใจผิดว่า Django เป็นบริการแคช) และทำให้เกิดข้อผิดพลาด 500 รายการในแอปพลิเคชัน PHP โดยใช้ไลบรารี Predis ยอดนิยม
ข้อเสียเปรียบที่สำคัญคือรองรับเฉพาะ Node.js และ PHP เท่านั้น ในทางกลับกัน มีการใช้งานที่ดีกว่า Datadog อย่างเห็นได้ชัด ต่างจากอย่างหลัง Atatus ไม่ต้องการแอปพลิเคชันเพื่อทำการแก้ไขหรือเพิ่มป้ายกำกับเพิ่มเติมให้กับโค้ด
เราทำงานร่วมกับ New Relic อย่างไร
ตอนนี้เรามาดูกันว่าโดยทั่วไปแล้วเราใช้ New Relic อย่างไร สมมติว่าเรามีปัญหาที่ต้องการวิธีแก้ไข:
มองเห็นได้ง่ายบนกราฟ สาด - มาวิเคราะห์กัน ใน New Relic ธุรกรรมบนเว็บจะถูกเลือกทันทีสำหรับเว็บแอปพลิเคชัน ส่วนประกอบทั้งหมดจะถูกระบุไว้ในกราฟประสิทธิภาพ มีแผงอัตราข้อผิดพลาด อัตราคำขอ... สิ่งที่สำคัญที่สุดคือโดยตรงจากแผงเหล่านี้ คุณสามารถย้ายไปมาระหว่างแผงต่างๆ ได้ ส่วนของแอปพลิเคชัน (เช่น การคลิก MySQL จะนำไปสู่ส่วนฐานข้อมูล)
เนื่องจากในตัวอย่างที่อยู่ระหว่างการพิจารณา เราพบว่ามีกิจกรรมเพิ่มขึ้นอย่างรวดเร็ว PHPคลิกที่แผนภูมินี้และไปที่โดยอัตโนมัติ การทำธุรกรรม:
รายการธุรกรรมซึ่งเป็นตัวควบคุมจากโมเดล MVC ได้ถูกจัดเรียงตามแล้ว ใช้เวลานานที่สุดซึ่งสะดวกมาก: เราจะเห็นได้ทันทีว่าแอปพลิเคชันทำอะไร นี่คือตัวอย่างคำค้นหาแบบยาวที่ New Relic รวบรวมโดยอัตโนมัติ ด้วยการสลับการเรียงลำดับ ทำให้ง่ายต่อการค้นหา:
- ตัวควบคุมแอปพลิเคชันที่มีการโหลดมากที่สุด
- ตัวควบคุมที่ร้องขอบ่อยที่สุด
- ตัวควบคุมที่ช้าที่สุด
นอกจากนี้ คุณยังสามารถขยายแต่ละธุรกรรมและดูว่าแอปพลิเคชันกำลังทำอะไรอยู่ ณ เวลาที่เรียกใช้โค้ด:
ในที่สุด แอปพลิเคชันจะเก็บตัวอย่างการติดตามคำขอที่ยาว (คำขอที่ใช้เวลานานกว่า 2 วินาที) นี่คือแผงสำหรับธุรกรรมระยะยาว:
จะเห็นได้ว่าสองวิธีใช้เวลานาน และในเวลาเดียวกันเมื่อมีการดำเนินการคำขอ URI และโดเมนก็จะแสดงเช่นกัน บ่อยครั้งสิ่งนี้จะช่วยค้นหาคำขอในบันทึก กำลังจะ รายละเอียดการติดตามคุณสามารถดูได้ว่ามีการเรียกใช้เมธอดเหล่านี้จากที่ใด:
และใน แบบสอบถามฐานข้อมูล — ประเมินการสืบค้นไปยังฐานข้อมูลที่ดำเนินการในขณะที่แอปพลิเคชันกำลังทำงาน:
ด้วยความรู้นี้ เราสามารถประเมินได้ว่าเหตุใดแอปพลิเคชันจึงทำงานช้าลง และทำงานร่วมกับนักพัฒนาเพื่อกำหนดกลยุทธ์ในการแก้ปัญหา ในความเป็นจริง New Relic ไม่ได้ให้ภาพที่ชัดเจนเสมอไป แต่จะช่วยให้เลือกเวกเตอร์ของการสืบสวนได้:
- ยาว
PDO::Construct
นำเราไปสู่การทำงานที่แปลกประหลาดของ pgpoll; - ความไม่มั่นคงเมื่อเวลาผ่านไป
Memcache::Get
แนะนำว่าเครื่องเสมือนได้รับการกำหนดค่าไม่ถูกต้อง - เวลาที่เพิ่มขึ้นอย่างน่าสงสัยสำหรับการประมวลผลเทมเพลตนำไปสู่การวนซ้ำที่ซ้อนกันเพื่อตรวจสอบการมีอยู่ของอวตาร 500 ตัวในที่จัดเก็บอ็อบเจ็กต์
- ฯลฯ …
นอกจากนี้ยังเกิดขึ้นว่าแทนที่จะเรียกใช้โค้ดบางสิ่งที่เกี่ยวข้องกับการจัดเก็บข้อมูลภายนอกจะเติบโตบนหน้าจอหลัก - และไม่สำคัญว่ามันจะเป็นอะไร: Redis หรือ PostgreSQL - ทั้งหมดนี้ถูกซ่อนอยู่ในแท็บ ฐานข้อมูล.
คุณสามารถเลือกฐานเฉพาะสำหรับการวิจัยและเรียงลำดับคำค้นหาได้ คล้ายกับวิธีการทำในธุรกรรม และเมื่อไปที่แท็บคำขอ คุณจะสามารถดูได้ว่าคำขอนี้เกิดขึ้นกี่ครั้งในตัวควบคุมแอปพลิเคชันแต่ละตัว และยังประมาณว่ามีการเรียกใช้บ่อยเพียงใด มันสบายมาก:
แท็บนี้มีข้อมูลที่คล้ายกัน บริการภายนอกซึ่งซ่อนคำขอไปยังบริการ HTTP ภายนอก เช่น การเข้าถึงที่เก็บข้อมูลอ็อบเจ็กต์ การส่งเหตุการณ์ไปยังยาม หรือสิ่งที่คล้ายกัน เนื้อหาของแท็บนั้นคล้ายกับฐานข้อมูลโดยสิ้นเชิง:
คู่แข่ง: โอกาสและความประทับใจ
ตอนนี้สิ่งที่น่าสนใจที่สุดคือการเปรียบเทียบความสามารถของ New Relic กับสิ่งที่คู่แข่งเสนอ น่าเสียดายที่เราไม่สามารถทดสอบเครื่องมือทั้งสามอย่างในเวอร์ชันเดียวของแอปพลิเคชันหนึ่งที่ทำงานอยู่ในเวอร์ชันที่ใช้งานจริงได้ อย่างไรก็ตาม เราพยายามเปรียบเทียบสถานการณ์/การกำหนดค่าที่เหมือนกันที่สุดเท่าที่จะเป็นไปได้
1. ดาต้าด็อก
Datadog ทักทายเราด้วยแผงที่มีบริการมากมาย:
มันพยายามแยกแอปพลิเคชันออกเป็นส่วนประกอบ/ไมโครเซอร์วิส ดังนั้นในตัวอย่างแอปพลิเคชัน Django เราจะเห็นการเชื่อมต่อกับ PostgreSQL 2 รายการ (defaultdb
и postgres
) เช่นเดียวกับคื่นฉ่าย, Redis การทำงานกับ Datadog ต้องการให้คุณมีความรู้เพียงเล็กน้อยเกี่ยวกับหลักการ MVC: คุณต้องเข้าใจว่าคำขอของผู้ใช้โดยทั่วไปมาจากไหน ซึ่งมักจะช่วยได้ แผนที่บริการ:
อย่างไรก็ตามมีบางอย่างที่คล้ายกันใน New Relic:
... และในความคิดของฉัน แผนที่ของพวกเขาถูกทำให้เรียบง่ายและชัดเจนยิ่งขึ้น: มันไม่แสดงส่วนประกอบของแอปพลิเคชันเดียว (ซึ่งจะทำให้มีรายละเอียดมากเกินไป เช่น ในกรณีของ Datadog) แต่จะแสดงเฉพาะบริการหรือไมโครเซอร์วิสเฉพาะเท่านั้น
กลับไปที่ Datadog: จากแผนที่บริการเราจะเห็นว่าคำขอของผู้ใช้มาที่ Django ไปที่บริการ Django แล้วดูว่าเราคาดหวังอะไร:
ขออภัย ไม่มีกราฟที่นี่โดยค่าเริ่มต้น เวลาทำธุรกรรมทางเว็บคล้ายกับที่เราเห็นบนแผง New Relic หลัก อย่างไรก็ตาม สามารถกำหนดค่าแทนกำหนดการได้ % ของเวลาที่ใช้. ก็เพียงพอที่จะเปลี่ยนไปใช้ เวลาเฉลี่ยต่อคำขอตามประเภท... และตอนนี้กราฟที่คุ้นเคยกำลังมองมาที่เรา!
เหตุใด Datadog จึงเลือกแผนภูมิอื่นจึงเป็นเรื่องลึกลับสำหรับเรา สิ่งที่น่าหงุดหงิดอีกประการหนึ่งคือระบบไม่จดจำตัวเลือกของผู้ใช้ (ไม่เหมือนกับคู่แข่งทั้งสองราย) ดังนั้นทางออกเดียวคือสร้างแผงแบบกำหนดเอง
แต่ฉันพอใจกับความสามารถของ Datadog ในการเปลี่ยนจากกราฟเหล่านี้ไปเป็นหน่วยเมตริกของเซิร์ฟเวอร์ที่เกี่ยวข้อง อ่านบันทึกและประเมินโหลดในตัวจัดการเว็บเซิร์ฟเวอร์ (Gunicorn) ทุกอย่างเกือบจะเหมือนกับใน New Relic... และมากกว่านั้นอีกเล็กน้อย (บันทึก)!
ด้านล่างกราฟเป็นธุรกรรมที่คล้ายกับ New Relic โดยสิ้นเชิง:
ใน Datadog ธุรกรรมจะถูกเรียก ทรัพยากร. คุณสามารถจัดเรียงคอนโทรลเลอร์ตามจำนวนคำขอ ตามเวลาตอบกลับโดยเฉลี่ย และตามเวลาสูงสุดที่ใช้ในช่วงเวลาที่เลือก
คุณสามารถขยายทรัพยากรและดูทุกสิ่งที่เราสังเกตเห็นแล้วใน New Relic:
มีสถิติเกี่ยวกับทรัพยากร รายการการโทรภายในโดยทั่วไป และตัวอย่างคำขอที่สามารถจัดเรียงตามรหัสตอบกลับ... อย่างไรก็ตาม วิศวกรของเราชอบการจัดเรียงนี้มาก
ทรัพยากรตัวอย่างใดๆ ใน Datadog สามารถเปิดและศึกษาได้:
พารามิเตอร์คำขอ แผนภูมิสรุปเวลาที่ใช้ในแต่ละส่วนประกอบ และแผนภูมิน้ำตกที่แสดงลำดับการโทรจะถูกนำเสนอ คุณยังสามารถสลับไปยังมุมมองแบบต้นไม้ของแผนภูมิน้ำตกได้:
และสิ่งที่น่าสนใจที่สุดคือการดูโหลดของโฮสต์ที่คำขอถูกดำเนินการและดูบันทึกคำขอ
บูรณาการที่ยอดเยี่ยม!
คุณอาจสงสัยว่าแท็บอยู่ที่ไหน ฐานข้อมูล и บริการภายนอกเช่นเดียวกับใน New Relic ไม่มีที่นี่: เนื่องจาก Datadog แยกแอปพลิเคชันออกเป็นส่วนประกอบต่างๆ PostgreSQL จึงจะได้รับการพิจารณา บริการแยกต่างหากและแทนที่จะเป็นบริการภายนอก ก็คุ้มค่าที่จะมองหา aws.storage
(จะคล้ายกันกับบริการภายนอกอื่นๆ ทั้งหมดที่แอปพลิเคชันสามารถเข้าถึงได้)
นี่คือตัวอย่างด้วย postgres
:
โดยพื้นฐานแล้วมีทุกสิ่งที่เราต้องการ:
คุณสามารถดูได้ว่าคำขอมาจาก "บริการ" ใด
ไม่ผิดที่จะเตือนคุณว่า Datadog ผสานรวมกับ NGINX Ingress ได้อย่างสมบูรณ์แบบ และช่วยให้คุณสามารถติดตามตั้งแต่ต้นทางถึงปลายทางตั้งแต่วินาทีที่คำขอมาถึงคลัสเตอร์ และยังช่วยให้คุณได้รับตัววัดสถิติ รวบรวมบันทึกและตัววัดโฮสต์อีกด้วย .
ข้อดีอย่างมากของ Datadog ก็คือราคาของมัน กำลังเป็นรูปเป็นร่าง จากการตรวจสอบโครงสร้างพื้นฐาน, APM, Log Management และการทดสอบ Synthetics เช่น คุณสามารถเลือกแผนของคุณได้อย่างยืดหยุ่น
2.อัตตาทัส
ทีมงาน Atatus อ้างว่าบริการของพวกเขา "เหมือนกับ New Relic แต่ดีกว่า" เรามาดูกันว่าจะเป็นเช่นนั้นจริงหรือไม่
แผงหลักมีลักษณะคล้ายกัน แต่ไม่สามารถระบุ Redis และ memcached ที่ใช้ในแอปพลิเคชันได้
APM เลือกธุรกรรมทั้งหมดตามค่าเริ่มต้น แม้ว่าโดยปกติแล้วจะต้องใช้เฉพาะธุรกรรมบนเว็บเท่านั้น เช่นเดียวกับ Datadog ไม่มีวิธีนำทางไปยังบริการที่ต้องการจากแผงหลัก นอกจากนี้ ธุรกรรมจะแสดงรายการหลังจากเกิดข้อผิดพลาด ซึ่งดูเหมือนจะไม่สมเหตุสมผลสำหรับ APM
ในธุรกรรมของ Atatus ทุกอย่างจะคล้ายกับ New Relic มากที่สุดเท่าที่จะเป็นไปได้ ข้อเสียคือไดนามิกของคอนโทรลเลอร์แต่ละตัวไม่สามารถมองเห็นได้ในทันที คุณต้องค้นหามันในตารางคอนโทรลเลอร์โดยเรียงลำดับตาม ใช้เวลาส่วนใหญ่:
รายการคอนโทรลเลอร์ตามปกติมีอยู่ในแท็บ อ่านเพิ่มเติม...:
ในบางแง่ ตารางนี้ชวนให้นึกถึง Datadog และฉันชอบมากกว่าตารางที่คล้ายกันใน New Relic
คุณสามารถขยายแต่ละธุรกรรมและดูว่าแอปพลิเคชันกำลังทำอะไรอยู่:
แผงยังชวนให้นึกถึง Datadog มากกว่า: มีคำขอจำนวนหนึ่ง, รูปภาพทั่วไปของการโทร แผงด้านบนแสดงแท็บข้อผิดพลาด ความล้มเหลวของ HTTP และตัวอย่างการสืบค้นที่ช้า การติดตามเซสชัน:
หากคุณไปที่ธุรกรรม คุณสามารถดูตัวอย่างการติดตาม คุณสามารถรับรายการคำขอไปยังฐานข้อมูล และดูที่ส่วนหัวของคำขอ ทุกอย่างคล้ายกับ New Relic:
โดยทั่วไปแล้ว Atatus พอใจกับการติดตามโดยละเอียด - โดยไม่ต้องติดสาย New Relic ทั่วไปไว้ในบล็อกเตือนความจำ:
อย่างไรก็ตาม มันขาดตัวกรองที่ (เช่น New Relic) จะตัดคำขอที่เร็วเป็นพิเศษ (<5ms) ในทางกลับกัน ฉันชอบการแสดงการตอบกลับการทำธุรกรรมขั้นสุดท้าย (สำเร็จหรือผิดพลาด)
Панель ฐานข้อมูล จะช่วยคุณศึกษาคำขอไปยังฐานข้อมูลภายนอกที่แอปพลิเคชันสร้างขึ้น ฉันขอเตือนคุณว่า Atatus พบเฉพาะ PostgreSQL และ MySQL แม้ว่า Redis และ memcached จะมีส่วนร่วมในโปรเจ็กต์นี้ก็ตาม
คำขอจะถูกจัดเรียงตามเกณฑ์ปกติ เช่น ความถี่ในการตอบกลับ เวลาตอบกลับโดยเฉลี่ย และอื่นๆ ฉันอยากจะพูดถึงแท็บที่มีการสืบค้นที่ช้าที่สุด - มันสะดวกมาก นอกจากนี้ ข้อมูลในแท็บนี้สำหรับ PostgreSQL ยังตรงกับข้อมูลจากส่วนขยายอีกด้วย
แท็บ คำขอภายนอก เหมือนกับฐานข้อมูลโดยสิ้นเชิง
ผลการวิจัย
เครื่องมือที่นำเสนอทั้งสองทำงานได้ดีในบทบาทของ APM รายการใดรายการหนึ่งสามารถเสนอขั้นต่ำที่ต้องการได้ ความประทับใจของเราสรุปได้สั้นๆ ดังนี้
ดาต้าด็อก
จุดเด่น:
- ตารางภาษีที่สะดวก (APM มีค่าใช้จ่าย 31 USD ต่อโฮสต์)
- ทำงานได้ดีกับ Python
- ความเป็นไปได้ของการรวมเข้ากับ OpenTracing
- บูรณาการกับ Kubernetes
- บูรณาการกับ NGINX Ingress
จุดด้อย:
- APM เดียวที่ทำให้แอปพลิเคชันไม่พร้อมใช้งานเนื่องจากข้อผิดพลาดของโมดูล (predis)
- เครื่องมืออัตโนมัติ PHP ที่อ่อนแอ;
- คำจำกัดความของบริการและวัตถุประสงค์ที่แปลกบางส่วน
อตาตัส
จุดเด่น:
- เครื่องมือวัด PHP แบบลึก
- ส่วนต่อประสานผู้ใช้คล้ายกับ New Relic
จุดด้อย:
- ไม่ทำงานบนระบบปฏิบัติการรุ่นเก่า (Ubuntu 12.05, CentOS 5)
- เครื่องดนตรีอัตโนมัติที่อ่อนแอ
- รองรับเพียงสองภาษา (Node.js และ PHP)
- อินเทอร์เฟซช้า
เมื่อพิจารณาถึงราคาของ Atatus ที่ 69 USD ต่อเดือนต่อเซิร์ฟเวอร์ เราอยากจะใช้ Datadog ซึ่งผสานรวมเข้ากับความต้องการของเราได้ดี (แอปพลิเคชันเว็บใน K8) และมีคุณสมบัติที่มีประโยชน์มากมาย
PS
อ่านเพิ่มเติมในบล็อกของเรา:
- «
เครื่องมือสำหรับนักพัฒนาแอปพลิเคชันที่ทำงานบน Kubernetes "; - «
ปลั๊กอิน kubectl-debug สำหรับการดีบักในพ็อด Kubernetes "; - «
ไมโครเซอร์วิส: ขนาดมีความสำคัญ แม้ว่าคุณจะมี Kubernetes ก็ตาม '
ที่มา: will.com