Elasticsearch กับการใช้งานใน KBTG ตอนที่ 2

Nutmos
KBTG Life
Published in
3 min readApr 20, 2020

จากตอนแรกที่ได้อธิบายถึงเหตุผลส่วนงาน Infrastructure ของ KBTG ต้องใช้ Elasticsearch ไปแล้ว ตอนที่ 2 นี้ขออธิบายการคอนฟิกค่าต่างๆ รวมถึงการจูนประสิทธิภาพของ Elasticsearch ในระดับคลัสเตอร์ให้ได้ตามที่เราต้องการ

ในช่วงแรกที่เราเริ่มทดสอบ Elasticsearch กับระบบเพียงแค่ไม่กี่ระบบนั้นได้ผลตอบรับที่ดีมาก แต่เมื่อระบบที่จะเข้ามามอนิเตอร์ผ่าน Elasticsearch มีจำนวนมากขึ้น ปริมาณข้อมูลที่เราต้องรับผิดชอบก็เยอะขึ้นด้วยเช่นกัน

ดังนั้นค่าเริ่มต้นที่ Elasticsearch กำหนดมาแต่แรกจึงไม่ตอบสนองตามที่เราต้องการ เราเริ่มที่จะปรับค่าต่างๆ บทความนี้จึงว่าด้วยคำแนะนำเรื่องการจัดการต่างๆ ในระดับคลัสเตอร์ เพื่อให้ Elasticsearch ตอบสนองการใช้งานของเรา เป็นตัวอย่างสำหรับคนที่กำลังใช้ Elasticsearch เพื่อเป็นไอเดียในการปรับแต่งให้เหมาะสมกับงานของตัวเองต่อไปครับ

ตั้งเป็นคลัสเตอร์

ข้อนี้ถือเป็นข้อพื้นฐานที่สุดของ Elasticsearch เมื่อ Traffic เริ่มโต โดยคำแนะนำของ Elastic ระบุไว้ชัดเจนว่าปกติแล้วคลัสเตอร์ Elasticsearch จะคุยกันภายในแบบโหนดต่อโหนด (คือทุกโหนดในคลัสเตอร์จะรู้จักกันผ่านระบบ Discovery) ซึ่ง Activity ทุกอย่าง โหนดแต่ละโหนดจะรู้ว่าตัวเองว่าต้องไปติดต่อที่โหนดไหน

ดังนั้นเพื่อให้ Elasticsearch ทำงานกันภายในคลัสเตอร์ได้ดีที่สุด ทั้งคลัสเตอร์ควรอยู่ในเน็ตเวิร์ควงเดียวกัน พยายามหลีกเลี่ยงการใช้ Firewall รวมถึงอุปกรณ์อื่นๆ ที่มีผลต่อ Traffic หรือสร้าง Latency อย่างไม่จำเป็น (คืออย่ามีเลยดีกว่า)

สำหรับกรณีการข้ามไซต์ ก็คืออย่าตั้ง Elasticsearch เป็นคลัสเตอร์ข้ามไซต์ ให้ใช้ความสามารถ Remote Cluster เพื่อเชื่อมต่อระหว่าง Elasticsearch หลายๆ คลัสเตอร์จะเหมาะสมกว่า

เพื่อรีดประโยชน์จากการตั้งคลัสเตอร์ให้ได้มากที่สุด การตั้งคลัสเตอร์ควรจะทำเป็น HA ซึ่งการจะตั้งคลัสเตอร์เป็น HA ได้ จะต้องมี Master-eligible (โหนดที่เป็น Master ได้) ขั้นต่ำ 3 โหนด เพราะในคลัสเตอร์จะมีโหนดที่ทำหน้าที่ Master เพียงโหนดเดียว (ในขณะที่หน้าที่อื่นอย่าง Ingest หรือ Data สามารถทำพร้อม ๆ กันได้หลายโหนด) เพื่อให้แต่ละโหนดร่วมกันโหวต Master ป้องกันสถานการณ์ Split-brain และสแตนด์บายหาก Master ที่มีอยู่เพียงตัวเดียวไม่สามารถทำงานได้ ก็จะมีโหนดอื่นขึ้นมาทำหน้าที่แทนทันที

เกร็ด: Split-brain คือการออกแบบเพื่อป้องกันการตั้งคลัสเตอร์จากเหตุการณ์เน็ตเวิร์คมีปัญหา จนทำให้โหนด Master-eligible ไม่สามารถติดต่อกันได้ คือการกำหนดโหนดขั้นต่ำของ Master-eligible ที่สามารถตั้งเป็นคลัสเตอร์ได้ มิฉะนั้นจะทำให้เกิดคลัสเตอร์แยกกันซึ่งไม่สามารถรวมกลับเป็นคลัสเตอร์เดียวได้อีก

โดยส่วนมากแล้วจำนวนโหนดขั้นต่ำจะถูกกำหนดไว้เท่ากับ (N/2)+1 หรืออธิบายง่ายๆ คือต้องมีจำนวนโหนดเกินครึ่งหนึ่งจึงจะสามารถตั้งเป็นคลัสเตอร์ได้

ตัว Elasticsearch ถูกออกแบบมาให้ตั้งเป็นคลัสเตอร์ที่มีกี่โหนดก็ได้ ดังนั้นหากมีงานบางประเภทจำนวนมากๆ เช่น ถ้าข้อมูลที่ต้องเก็บบน Elasticsearch มีปริมาณมากขึ้น เราสามารถสร้างโหนดประเภท Data เพื่อ Join เข้าคลัสเตอร์ให้ทำหน้าที่เก็บข้อมูลอย่างเดียวได้ หรือหากมีข้อมูลที่ต้องประมวลผลเพิ่มขึ้น ก็สามารถสร้าง Ingest ขึ้นมาเพื่อ Join เข้าคลัสเตอร์และทำหน้าที่ประมวลผลข้อมูลอย่างเดียวก็ได้เช่นกัน และโหนดเหล่านี้หากไม่ต้องการใช้งานก็สามารถถอดออกจากคลัสเตอร์ได้ทันที

เมื่อคลัสเตอร์รองรับโหนดเยอะๆ ได้ เราตั้งคลัสเตอร์ที่มีโหนดเยอะๆ ตั้งแต่แรกไม่ดีกว่าเหรอ

เมื่อมีข้อดีก็ต้องมีข้อเสียครับ อย่าลืมว่าในคลัสเตอร์ของ Elasticsearch จะมีโหนดที่ทำหน้าที่ Master ได้เพียงโหนดเดียวเท่านั้น ซึ่งหน้าที่ของ Master มีหลายอย่าง เช่น

  • เก็บและอัพเดตสถานะของคลัสเตอร์
  • ติดตามสถานะของโหนดทุกโหนด
  • ตัดสินใจวางและโยกย้าย Shard ระหว่างโหนด

เกร็ด: หน่วยย่อยที่สุดของ Elasticsearch คือ Shard โดยภายใน Shard ไม่สามารถแยกกันเก็บได้ในระหว่างโหนด แต่สามารถสร้างสำเนาไว้อีกโหนดได้ และการทำคิวรีของ Elasticsearch จะทำโดยแยกตาม Shard

ภาพจาก Elastic

ดังนั้น Master จะเข้าไปเก็บสถานะจากทุกๆ โหนด หากโหนดไหนตอบช้า โหนดนั้นก็อาจหลุดจากคลัสเตอร์ หรือถ้า Master ทำงานไม่ทัน โหนดอื่นอาจจะตัดตัวเองออกจากคลัสเตอร์ ส่งผลต่อประสิทธิภาพการทำงานโดยรวมของคลัสเตอร์

จะเห็นได้ว่า การเพิ่มโหนดเข้าไปเยอะๆ ก็ไม่ใช่เรื่องที่ดี ก่อนเพิ่มโหนดจึงต้องพิจารณาว่าโหนดที่ทำงานอยู่ปัจจุบันขาดเหลืออะไรบ้าง และปรับจูนให้เต็มที่ก่อนที่จะเพิ่มโหนดเข้าไปในคลัสเตอร์

เรื่องของ Master ถือเป็นพื้นฐานของการดีไซน์คลัสเตอร์ เพราะอย่างที่กล่าวไว้ข้างต้นว่า Elasticsearch มีโหนดได้หลายประเภท (อ่านรายละเอียดเกี่ยวกับโหนดแต่ละประเภทได้จากเว็บไซต์ Elastic) ซึ่งหมายความว่ารายละเอียดในการดีไซน์คลัสเตอร์ยังมีอีกมาก ไว้ติดตามในตอนถัดๆ ไปนะครับ

ภาพจาก Elastic

เปิดใช้งานระบบ Monitoring

Elasticsearch มีระบบมอนิเตอร์ภายในคลัสเตอร์มาให้ใช้งานสักระยะหนึ่งแล้ว และเปิดให้ใช้งานฟรี ดังนั้นเพื่อให้เรามองเห็นสภาพการทำงานภายใน Elasticsearch จึงแนะนำให้เปิดระบบนี้ไว้ใช้งานด้วย

แม้ว่าระบบมอนิเตอร์จะเปิดใช้งานง่าย แต่เพื่อประสิทธิภาพในการมอนิเตอร์สูงสุด จึงแนะนำให้คอนฟิกระบบมอนิเตอร์เพิ่มเติม ซึ่งจุดสำคัญคือความถี่ในการมอนิเตอร์ ค่าเริ่มต้นอยู่ที่ 10 วินาที ผมปรับเป็น 1 นาทีเพื่อไม่ต้องเก็บค่ามอนิเตอร์ถี่จนเกินไป (ค่านี้ขึ้นกับว่าต้องการถี่แค่ไหน) และปรับ Timeout ให้นานขึ้น เนื่องจากเมื่อ Elasticsearch โตขึ้น การเก็บสถานะของตัวคลัสเตอร์ก็จะช้าลง ถ้า Timeout สั้นมาก ระบบมอนิเตอร์อาจเก็บสถานะอะไรไม่ได้เลย

ภาพจาก Elastic

จุดสำคัญสุดท้ายของระบบมอนิเตอร์คือตั้งคลัสเตอร์สำหรับเก็บค่ามอนิเตอร์แยก เนื่องจากเราต้องการมอนิเตอร์คลัสเตอร์หลักและนำมาวิเคราะห์ปัญหา แต่ถ้าเราส่งค่ามอนิเตอร์เข้าคลัสเตอร์หลักแล้ว เมื่อคลัสเตอร์หลักเกิดมีปัญหา ค่ามอนิเตอร์ก็จะส่งเข้าคลัสเตอร์ไม่ได้ ทำให้เราไม่เห็นข้อมูลใดๆ และนำไปวิเคราะห์ต่อไม่ได้

ดังนั้นผมจึงแนะนำให้ตั้งคลัสเตอร์แยกสำหรับมอนิเตอร์ออกมาเป็นอิสระจากคลัสเตอร์หลัก (เป็นคลัสเตอร์โหนดเดียวก็พอ) แล้วตั้งค่า HTTP Exporter ให้ชี้ไปยังคลัสเตอร์แยกนี้ครับ ซึ่งเราก็ยังสามารถใช้ Kibana ตัวที่ต่อคลัสเตอร์หลักชี้ไปยังคลัสเตอร์แยกเพื่อดูค่ามอนิเตอร์ของ Elasticsearch ได้

ภาพจาก Elastic

เปิดใช้ระบบ Security

Elasticsearch มีระบบ Security ให้ใช้งานในตัวอยู่แล้ว โดยรุ่นฟรีก็จะมี Basic Authen สามารถสร้าง Account และผูกกับ Role ได้ โดยส่วนของ Role นี้จะต้องกำหนดว่าสามารถใช้งานอะไรได้บ้าง เช่น สร้าง Index, อ่านเขียนข้อมูลใน Index, ลบ Index, เข้าใช้งาน Kibana เป็นต้น

เมื่อเปิดใช้งาน Basic Authen ตัว Elasticsearch จะบังคับเปิดใช้งาน SSL/TLS โดยอัตโนมัติในส่วนพอร์ต 9300 ที่ใช้เพื่อติดต่อระหว่างโหนด Elasticsearch (ส่วน REST API ที่คิวรีผ่านพอร์ต 9200 ไม่ได้บังคับ)

ภาพจาก Elastic

เพื่อความง่าย Elasticsearch จึงเตรียมเครื่องมือสำหรับสร้าง Certificate ให้เรียบร้อยแล้วในชื่อ Elasticsearch-certutil หรือถ้าจะสร้าง Certificate จากเครื่องมืออื่นก็ได้ แต่ควรระวังเรื่องฟิลด์บางอย่างในตัว Certificate ที่หากไม่ใส่อาจทำให้ Elasticsearch ทำงานไม่ได้ อ่านรายละเอียดเพิ่มเติมได้ที่เว็บไซต์ Elastic

เนื่องจากระบบ Security ของ Elasticsearch เป็นฟีเจอร์ปล่อยให้ใช้ฟรี ดังนั้นเพื่อความปลอดภัยในการใช้งานป้องกันข้อมูลสำคัญรั่วไหล จึงแนะนำให้เปิดใช้งานระบบนี้สำหรับผู้ใช้ Elasticsearch ทุกคน

กำหนด Thread Pool และ Queue Size ตามลักษณะการใช้งาน

สุดท้ายคือเรื่อง Thread Pool และ Queue Size สองเรื่องนี้จะสัมพันธ์กัน งานของ Elasticsearch ที่เราใช้เป็นหลักคือการมอนิเตอร์ จึงใช้ Thread Pool ที่ทำงานประเภท Index/Update/Delete เยอะมากๆ โดย Thread Pool ที่ทำงานเหล่านี้ใน Elasticsearch จะใช้ชื่อว่า Write ดังนั้นเราจึงโฟกัสที่ค่านี้เป็นหลัก

ความสำคัญของ Thread Pool และ Queue Size มีดังนี้

  • Thread Pool จะบอกว่ามี Thread ในการทำงานเท่าไร ซึ่งกรณีของ Index/Update/Delete จะมีจำนวนได้มากสุดและเป็นค่า Default เท่ากับ 1+จำนวนคอร์ซีพียูที่ใช้งานได้
  • Queue Size ขนาดคิวสำหรับรองานจนกว่าจะมี Thread คืนมา

โดยปกติแล้ว เมื่อเราสั่งงาน (Request) สักอย่างเข้าไปที่ Elasticsearch หาก Thread Pool ยังมี Thread ว่างเหลืออยู่ Elasticsearch ก็จะให้ Request นั้นทำงานทันที แต่หาก Thread ในการทำงานไม่เหลือว่างแล้ว Elasticsearch ก็จะนำลงคิว และถ้าคิวเต็ม Elasticsearch ก็จะตอบ Error กลับมา

ลูกศรคือ request ที่สั่งเข้ามาหา Elasticsearch ซึ่งถ้ามีเกินจำนวนคิวก็จะตอบ Error กลับไป

กรณีของ Thread Pool จุดสำคัญคือจำนวน Thread ที่จะใช้ต้องมีจำนวนเพียงพอต่องาน ส่วน Queue Size จะมีไว้เพื่อแก้ปัญหากรณีงานเข้ามาจำนวนมากจน Thread ถูกใช้จนหมด ก็จะถูกนำมารอไว้ที่ Queue

ดังนั้นในกรณีที่ระบบ “ช้า” จากปัญหาการประมวลผลไม่ทันเป็นประจำอยู่แล้ว ให้เพิ่ม Thread Pool แต่ถ้าระบบ “ช้า” จากปัญหาประมวลผลไม่ทันเนื่องจากการคาดการณ์ปริมาณข้อมูลไม่ได้เป็นครั้งคราว (พีคเป็นช่วง ๆ) ให้เพิ่ม Queue Size

เนื่องจากจำนวน Thread Pool ในงานสำคัญอย่าง Index/Update/Delete จะมีค่าเท่ากับจำนวนคอร์ซีพียูที่ Java มองเห็น +1 (เช่น ถ้าเป็น 8 คอร์ ก็จะเห็น Thread Pool ทั้งหมด 9) และปัจจุบัน Elasticsearch นิยมนำมารันเป็นคอนเทนเนอร์ ซึ่งถ้าเราไม่ตั้งค่าในส่วนของ Resource ก็อาจส่งผลให้ Java เห็นซีพียูคอร์น้อยกว่าที่เป็นจริงๆ ทำให้ Thread Pool น้อยกว่าที่ควรจะเป็น แม้จะมีทรัพยากรสำหรับการรัน Elasticsearch มากสักเพียงใดก็ตาม

เพื่อหลีกเลี่ยงพฤติกรรมที่ไม่สามารถคาดการณ์ได้ ผมจึงแนะนำให้เซ็ทค่าซีพียูคอร์ให้ Elasticsearch ในกรณีที่รันเป็นคอนเทนเนอร์ด้วย

เหตุผลที่เราโฟกัส Thread Pool ประเภท Write เนื่องจากงานที่เราใช้เป็นหลักจะเป็นงานประเภท Index/Update/Delete แต่จริง ๆ แล้ว Elasticsearch มี Thread Pool ที่ไว้ใช้ทำงานอื่นอีกมาก จึงต้องขึ้นกับการโฟกัสว่าตอนนี้ Elasticsearch ทำงานประเภทไหนช้า และจะต้องปรับค่าตรงไหนบ้าง สามารถอ่านรายละเอียดเพิ่มเติมได้จากเว็บไซต์ Elastic

สรุป

สำหรับบทความนี้ เป็นการอธิบายลงลึกอีกนิดว่าเราจัดการในเบื้องต้นอย่างไรในระดับคลัสเตอร์เพื่อให้ Elasticsearch ได้ประสิทธิภาพตามที่เราต้องการ

แต่เนื่องจากการปรับจูนประสิทธิภาพไม่ใช่งานทำครั้งเดียวจบ และไม่มีสูตรสำเร็จตามที่ทุกคนต้องการ บทความนี้จึงเป็นเพียงแนวทางเบื้องต้นที่ให้เห็นอย่างคร่าวๆ ว่าเราได้ทำอะไรไปบ้าง และนำไปปรับใช้ตามความเหมาะสมของแต่ละคนครับ

--

--