โจทย์คืองานอีเลิร์นนิ่งกระทรวงศึกษามีเซิร์ฟเวอร์ห้าตัวให้ใช้รองรับนักเรียนจากทั้งประเทศ จะกระจายโหลดไปยังเซิร์ฟเวอร์แต่ละตัวแต่ไม่มีโหลดบาลานด์ให้ Moodle สามารถกำหนดไดเรคทอรี่ไว้เก็บข้อมูลได้ก็จะใช้ตัวหนึ่งเป็นตัวเก็บข้อมูลสกอร์มข้อมูลจะได้ตรงกัน และใช้ตัวอื่นๆรัน php หาทางเลือกดูมี 3 วิธีคือ
- ให้แต่ละตัวรับไปแต่ละภาค ปัญหาคือเกือบทั้งหมดวิ่งผ่านไอเอสพีไม่กี่ที่ และแยกแทบไม่ได้ว่ามากจากภาคไหน
- ใช้ function random สุ่ม server ดูปรากฎว่าการกระจายค่อนข้างกระจุกอยู่ที่ server ตัวหลังๆ เกือบทุกครั้ง
- ทำให้ระบบจำได้ว่าจ่ายงานครั้งสุดท้ายไปที่ตัวไหนแล้วขยับไปตัวต่อไปเรื่อยๆ เหมือนเราแจกไพ่ การจะทำให้ php จำค่าล่าสุดได้นั้นมีการรักษาตัวแปรไว้ได้ 4 วิธี
- เขียนเป็นไฟล์ อันนี้จะมีปัญหาการเข้าถึงพร้อมกันของแต่ละเทรด(Threads)
- Cookie ใช้ไม่ได้เพราะเก็บไว้ที่เครื่องผู้ใช้คนอื่นเข้ามาก็จะอ่านค่าไม่ได้
- Session ข้อมูลจะเก็บบนเครื่องเซิร์ฟเวอร์แต่ก็เป็นการเก็บข้อมูลของแต่ละคนเหมือน cookie
- เก็บในฐานข้อมูล ใช้ร่วมกันได้ แต่เราต้องการแต่ให้ทำงานได้เร็วที่สุด
DROP TABLE IF EXISTS `lastserv`; CREATE TABLE `lastserv` ( `used` int(11) default NULL ) ENGINE=MEMORY DEFAULT CHARSET=utf8 COMMENT='จำ server ที่ใช้ล่าสุด'; INSERT INTO `lastserv` VALUES (1);
จะเห็นคำสั่งแปลกๆ ENGINE=MEMORY คือ MySQL จะมีระบบบริหารดาต้าเบสอยู่หลายตัวให้เลือกใช้ให้เหมาะกับงานต่างๆอ่านเพิ่มเติมได้จาก MySQL Storage Engine Architecture ในบรรดาเอ็นจิ้นของ MySQL จะมีเอ็นจิ้น Memory ซึ่งจะเก็บข้อมูลใน ram ทำให้อัตราการเข้าถึงข้อมูลเร็วที่สุดโดยเราสามาถเลือกได้ตอนสร้างตารางให้ระบุ engine ลงไปด้วย
ในส่วนโค้ท php ไม่มีอะไรเป็นพิเศษเพียงมีการออพติไมซ์เพิ่มเล็กน้อยคือ<?php $dsn = mysql_connect('localhost', 'database user', 'databae password'); mysql_select_db('database name' ,$dsn); /* การระบุ datasource จะทำงานได้เร็วขึ้น */ $sql="SELECT used FROM lastserv;"; $row = mysql_fetch_assoc(mysql_unbuffered_query($sql ,$dsn)); /* คิวรี่แบบใช้ข้อมูลเพียงครั้งเดียวทิ้งลดการใช้ memory */ if($row['used'] == 4){ $next = 1; }else{ $next = $row['used'] + 1; } $sql="UPDATE lastserv SET used= $next LIMIT 1;"; mysql_unbuffered_query($sql ,$dsn); switch($row['used']){ case '1' : { header('Location: http://192.168.1.1'); }break; case '2' : { header('Location: http://192.168.1.2'); }break; case '3' : { header('Location: http://192.168.1.3'); }break; case '4' : { header('Location: http://192.168.1.4'); }break; }