redis เร็วกว่า MySQL จริงหรือ?

redis เร็วกว่า MySQL จริงหรือ?

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

จำลองสถานการณ์อย่างไร

เบื้องต้น ผมลองจำลอง environment ให้คล้ายกับการทำงานจริงๆขึ้นมา โดยกำหนดให้ผมมี web server 1 เครื่อง และมี database อีก 1 เครื่อง ซึ่งงานที่ใหญ่ๆ เค้าก็มักจะแยกเครื่องกันทำงานครับ เพราะเครื่องเดียวเอาไม่อยู่แน่นอน (เพราะต้องประมวลผลอะไรต่อมิอะไรเยอะมาก) โดยผมจะเทียบกัน แบ่งเป็น สองส่วนเทียบกัน ส่วนแรก คือส่วนที่ให้หน้าเว็บ เชื่อม database MySQL ส่วนที่สอง หน้าเว็บเชื่อม database redis 

ทดสอบอะไรบ้าง

โดยผมจะกำหนดให้ write เข้าไป เป็นจำนวน 5 แสน record โดยแบ่งเป็น รอบละ 10 record จำนวน 50K รอบ และ การอ่าน ทีละ 100 record จำนวน 5K รอบ เพื่อให้ใกล้เคียงกับการใช้งานจริงๆ ที่จะได้เจอ (database ปกติจะมีการอ่านมากกว่าการเขียน) ทั้งนี้ redis กำหนดให้ไม่มี BGSAVE นะครับ คือไม่ save ข้อมูลลง Disk เลย ทำงานบน ram ล้วนๆ

spec เครื่องที่ใช้เป็นอย่างไร

เครื่องที่เป็น web server ในการทดสอบนี้ ผมใช้เครื่องตัวเองที่นั่งทำงานอยู่ คือ PC มี CPU AMD 8350 (8 cores ,4 Ghz) Ram 16GB และเครื่องที่เป็น database ใช้ Virtual Box (เป็นเครื่อง จำลอง) 2 Core CPU, 2GB Ram โดยเครื่องจำลอง รันอยู่บน PC อีกทีหนึ่ง 

โค้ดที่ใช้ทดสอบ

ผมเขียนบน CodeIgniter Framework ทั้งหมด โดยแยก function กันทำงาน แต่อยู่บน environment เดียวกันทั้งหมด พยายามควบคุมตัวแปรทั้งหมด ให้เหมือนกันทั้งหมด เท่าที่จะเป็นไปได้ โดยจะแบ่งโค้ดได้เป็น 4 ชุด

MySQL

เขียน เข้า mysql ทีละ query ทีละชุดข้อมูล
โค้ด เขียนข้อมูลลง mysql

MySQL (multiple insert)

เขียนเข้า mysql โดย query หนึ่งครั้ง มีข้อมูล 10 ชุด
โค้ด เขียนข้อมูลลง mysql ทีละหลาย record

redis

เขียนเข้า redis โดยใช้ set ทีละค่า
โค้ด เขียนข้อมูลลง redis

redis (pipe line)

เขียนเข้า redis โดยใช้ pipe line ให้มี 10 คำสั่ง set ต่อ 1 pipe line
โค้ด เขียนข้อมูลลง redis โดยใช้ pipe line

*pipe line คือการรวบคำสั่งหลายๆคำสั่งต่อเนื่องกัน แล้วส่งให้ redis ทำงานเพียงครั้งเดียว ซึ่งทาง redis บอกว่า จะเพิ่ม ประสิทธิภาพได้มาก

ทั้งนี้ โค้ดทั้งหมด ผมรวมมาให้ในไฟล์เดียวกันแล้วครับ download ไปอ่านได้ แต่อย่าลืมนะครับ ผมทดสอบด้วย CodeIgniter Framework ดังนั้น ต้องเอาโค้ดไปประกอบร่างอีกทีนะครับ

ผลการทดสอบ การเขียนข้อมูล ทั้งหมด


ผลการทดสอบเขียนลง mysql , redis (write)
ครั้งที่ MySQL MySQL (multiple insert) redis redis (pipe line)
ครั้งที่ 1118.933727.02187.682232.9327
ครั้งที่ 2117.567426.983589.0928.2973
ครั้งที่ 3128.084328.282391.266928.9382

สรุปผลการเขียน

พบว่า หากเราใช้ pipe line ของ redis และ multiple insert ของ MySQL ในการเขียนข้อมูล ถือว่า ให้เสมอกัน แต่เดี๋ยวก่อน ถ้าลอง ปรับ table mysql ให้เป็น memory type แล้วพบว่า mysql จะเร็วขึ้นอีก 50% เลยทีเดียว นั่นหมายความว่า เร็วกว่า redis ซะอีก ทั้งที่ redis ทำงานบน ram แล้ว และปิด BGSAVE แล้วซะด้วยนะเนี่ย แต่สำหรับผลการ insert ข้อมูลทีละคำสั่ง ทีละ record พบว่า MySQL ช้ากว่า redis ประมาณ 20% ก็ถือว่าไม่ได้ต่างกันมากมายอย่างที่เค้าเคลมๆกันเอาไว้แฮะ

ทดสอบผลการอ่าน

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

MySQL

อ่าน mysql ทีละ query ทีละ record
อ่านข้อมูลจาก mysql

MySQL (multiple id)

อ่าน mysql โดย query หนึ่งครั้ง มีข้อมูลจาก 10 record
โค้ด อ่านข้อมูลจาก mysql ทีละหลาย record

redis

อ่าน redis โดยใช้ get ทีละค่า
โค้ด อ่านข้อมูลจาก redis

redis (pipe line)

อ่าน redis โดยใช้ pipe line ให้มี 10 คำสั่ง get ต่อ 1 pipe line
โค้ด อ่านข้อมูลจาก redis โดยใช้ pipe line

ผลการทดสอบการอ่านข้อมูล

ผลการทดสอบอ่าน mysql , redis (write)
ครั้งที่ MySQL MySQL (multiple insert) redis redis (pipe line)
ครั้งที่ 1มากกว่า 300 วินาที8.241891.943411.923
ครั้งที่ 2มากกว่า 300 วินาที8.245878.093414.4863

สรุปผลการทดลองการอ่าน

mysql ไม่สามารถทำงานได้ในความเป็นจริง ด้วยปริมาณ query ที่มากขนาดนี้ได้ คือ จากการจำลอง เหมือนกับว่า มีคน 5000 คนเปิดเว็บ โดยเว็บแต่ละหน้า มี 100 query ผลคือ รอกันไป 5 นาทีก็ยังทำงานไม่เสร็จ สุดท้ายก็ time out กันไปเลย (เครื่องทดสอบผมตั้ง time out ไว้ 300 วินาที แต่ server ทั่วไปตั้งไว้ที่ 90-120 วินาทีเท่านั้น) นั่นแปลว่า mysql รองรับ traffic จำนวนมากๆไม่ไหว แต่กลับกับ redis ถึงจะช้า แต่ก็ยังทำงานได้ครบถ้วน ถูกต้อง และมีเรื่องน่าประหลาดใจอีกแล้วกับการ query ครั้งนึงหลาย record ของ MySQL กับสามารถทำงานได้ และใช้เวลาที่น้อยกว่าการทำ pipe line ของ redis ซะอีก คือประมาณ 20% ได้ ซึ่งเป็นผลการทดสอบ ที่ชวน งง มากทีเดียว นี่หมายความว่า mysql รองรับการทำงานแบบ key เยอะๆมากกว่า การ query ทีละครั้งอย่างนั้นหรือ? 

สรุปผลรวม ทั้งการ เขียน การอ่าน

การเขียนข้อมูล ถือว่า ไม่แตกต่างกัน ไม่ว่าจะเป็น redis , MySQL แต่สำหรับการอ่าน ถือว่า redis ยังทำงานอยู่ได้ ภายใต้ภาวะ load สูงๆ เพราะหากเรามาคิดถึงความเป็นจริง ว่า MySQL เวลาการทำงาน บนหน้าเว็บจริง จะมี query จำนวนมาก ประกอบกันเป็น 1 หน้า เพราะว่าต้องดึงข้อมูลออกมาจากหลาย table ดังนั้นหลายคน เลยเขียน advance ด้วยการใช้การ join กัน ของ table ซึ่งจากประสบการณ์พบว่าการ join กันจะเริ่มทำงานช้า เมื่อ table หลายๆ table มีข้อมูลจำนวน record มากๆ เพราะว่ามันจะต้อง scan key เพื่อเอาข้อมูลมาตัดต่อเชื่อมกัน ก่อนจะส่งมาให้เราได้ แต่ผมยังไม่ได้ทดสอบประเด็นเรื่องการ join นะ เพราะว่า ในประเด็นการเชื่อม การ join นี้ไม่มีใน redis เนื่องจาก redis เป็นแบบ key value ดังนั้น แม้ว่ามีการสร้าง key มากๆ ความเร็วก็ไม่น่าจะตกลงไปมากเท่าไร เพราะว่า redis มันเก็บข้อมูลแบบแบนๆ แต่จะมีประเด็นเรื่องการทำงานไปนานๆแล้วเกิด fragment ได้เช่นกัน (ข้อมูลกระจายตัวกัน ทำให้ค้นหาได้ยากขึ้น)

สรุป ใช้อะไรยังไงดี

ถ้าเราเอาทุกสิ่งอย่างมารวมกัน พบว่า MySQL มีการ write + read ที่จำกัดระดับหนึ่ง แต่เราสามารถเชื่อถือข้อมูลที่เก็บอยู่ใน MySQL ได้ ว่ามันถูกต้อง ไม่หาย แต่ redis นั้น ทนต่อการทำงานหนักแม้ว่า ทำงานหนักมาก ก็ยังความเร็วไม่ตกไปมากในระดับที่แย่ แต่ข้อมูลอย่าคาดหวังว่ามันจะอยู่ถาวร ดังนั้น หากเราต้องการใช้ เราต้องเขียนตัวเชื่อมข้อมูลระหว่าง MySQL ให้มาเก็บบน redis (คิดถึงตอน restart ก็ยังต้องอ่านขึ้นมาเก็บใหม่ได้ด้วยนะ) และปรับการอ่านข้อมูลจาก MySQL ไปอ่านที่ redis แทน รวมทั้งปรับรูปแบบการอ่าน เขียน ให้เป็นการ query ครั้งเดียวแต่ทำงานหลายๆ record ซึ่งจะช่วยเพิ่ม performance ขึ้นไปอีกมาก แต่แน่นอนว่าการจะ อ่าน เขียน ครั้งเดียว ได้หลาย record นั้นเราต้องเปลือง ram ในการพักข้อมูลมากๆก่อนส่งคำสั่ง และ CPU ในการประมวลผลเพิ่มขึ้น แต่ก็นั่นล่ะครับ แลกมากับความไหลลื่นของระบบเพราะว่า หากเราไม่ทำอะไร และปล่อยให้ database มีคอขวด ส่งผลให้เว็บล่ม แล้วเราไปเพิ่ม ram เปลี่ยน CPU ก็คงไม่ได้ช่วยให้เว็บทำงานได้เร็วขึ้นอีกสักเท่าไรอย่างแน่นอน ปรับกระบวนการคิด ดึงทรัพยากรมาใช้ให้เต็มที่จะดีกว่า เพราะว่าหลังๆมานี้ CPU ล้ำหน้าไปมาก ประมวลผลคำสั่งจำนวนมหาศาลในเวลาอันสั้นได้ดีขึ้นมาแล้ว (จริงๆ ram server ก็ถูกลงมาพอสมควรแล้ว ถึงจะแพงอยู่มากก็ตาม คือ 8GB ประมาณ 4000 บาท) จึงต้องเอามาใช้ให้เกิดประโยชน์สูงสุดครับ  แต่ถ้ารีด จน CPU 100% ram หมดจนต้องกิน swap HDD มี IO สูงมาก โดยอ่านโค้ดแล้ว รีดมาสุดๆแล้วจริงๆ ก็เปลี่ยนเครื่องเถอะครับ เพราะทุกสิ่งอย่างก็มีข้อจำกัดในตัวมันเช่นกันครับ

แต่... ไม่มีสูตรสำเร็จ ที่ตายตัว ที่ชี้เป็นชี้ตาย ว่าแบบนี้ดีกว่านั้น แบบนั้นดีกว่านี้ เพราะว่า มันขึ้นอยู่กับงานที่ทำด้วย บางงาน เป็นงานที่เน้น write และเก็บ ก็ไม่เหมาะ ที่จะต้องมี redis เพราะไม่รู้จะเอามาช่วยอะไร

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

Create: Modify : 2013-07-25 06:42:02 Read : 3436 URL :