วันอังคารที่ 30 พฤษภาคม พ.ศ. 2560

รันโปรแกรมสคริป php อัตโนมัติ สำหรับบริการเซิร์ฟเวอร์ TCP ฉบับเซียน

ผู้เขียนเคยแนะนำวิธีการ สร้าง PHP ทำหน้าที่เป็น TCP server รองรับจำนวนลูกข่ายมากกว่า 10 เครื่องพร้อมกัน โดยโปรแกรมจะทำงานในโหมดโฟร์กราวด์(foreground) คือหากปิดหน้าต่างหรือปิดเทอร์มินอลโปรแกรมก็หยุดทำงาน จากนั้นผู้เขียนได้พัฒนาให้ทำงานในโหมดแบ็กกราวด์(background)ดีขึ้นมาหากปิดเทอร์มินอลโปรแกรมก็ยังทำงานได้ดีอยู่ จากนั้นก็สร้าง cron ให้ทำงานทุก ๆ 5-10 นาทีเพื่อตรวจสอบดูว่าหากโปรแกรมสคริปหยุดทำงาน ก็ให้สตาร์ทเซอร์วิสใหม่ การรันโปรแกรมสคริป php ที่ทำหน้าที่เป็นเซิร์ฟเวอร์แบบนี้ หากเราหยุดโปรแกรมโดยการฆ่าโฟรเซส(kill process)บางครั้งโปรแกรมก็ไม่สามารถสตาร์ทได้ใหม่ในทันใด
socket_bind() failed: reason: Address already in use
ปํญหาที่พบเจอก็คือข้อผิดพลาด "Address already in use" วิธีแก้ของผู้เขียนก็คือรอเวลาระหว่างการรีสตาร์ทเซอร์วิสให้นานขึ้น แต่การรอเพื่อจะสตาร์ทเซอร์วิสใหม่นานถึง 5-10 นาที ข้อมูลที่ต้องการติดต่อระหว่างนั้นก็จะหายไปหรือปิดเซอร์วิสการให้บริการชั่วคราว นับเป็นปัญหาหนึ่งของการให้บริการ

ผู้เขียนเคยใช้งานโปรแกรมควบคุมเซอร์วิสให้ทำงานอยู่ตลอดเวลา  ไม่ต้องเสียน้ำตากับการรันโปรแกรมสคริป php อัตโนมัติ supervisor แบบมืออาชีพ ซึ่งเซอร์วิสนี้พบว่าทำงานได้อย่างดีเยี่ยมโดยเฉพาะการควบคุมคิวการทำงาน(beanstalk)

ครั้งนี้จะนำมาประยุกต์ให้ใช้ทำงานร่วมกันให้ได้อย่างมีประสิทธิภาพ สำหรับรันโปรแกรมสคริป php อัตโนมัติ สำหรับบริการเซิร์ฟเวอร์ TCP ฉบับเซียน


ขั้นตอนที่ 1 หากยังไม่เคยใช้งานโปรแกรม supervisor แนะนำให้กลับไปอ่านบทความ ไม่ต้องเสียน้ำตากับการรันโปรแกรมสคริป php อัตโนมัติ supervisor แบบมืออาชีพ ก่อน สำหรับขั้นตอนนี้ให้เพิ่มคอนฟิกไฟล์ตามตัวอย่าง

  [program:ywt6035v2]
command=bash -c "ulimit 10000; exec /usr/bin/php /var/www/ywt7035v2/ywt7035v2.php"             ; the program (relative uses PATH, can take args)
process_name=%(program_name)s ; process_name expr (default %(program_name)s)
numprocs=1                    ; number of processes copies to start (def 1)
directory=/tmp                ; directory to cwd to before exec (def no cwd)
umask=022                     ; umask for process (default None)
priority=999                  ; the relative start priority (default 999)
autostart=true                ; start at supervisord start (default: true)
startsecs=1                   ; # of secs prog must stay up to be running (def. 1)
startretries=3                ; max # of serial start failures when starting (default 3)
;autorestart=unexpected        ; when to restart if exited after running (def: unexpected)
autorestart=true        ; when to restart if exited after running (def: unexpected)
exitcodes=0,2                 ; 'expected' exit codes used with autorestart (default 0,2)
stopsignal=QUIT               ; signal used to kill process (default TERM)
stopwaitsecs=10               ; max num secs to wait b4 SIGKILL (default 10)
;stopasgroup=false             ; send stop signal to the UNIX process group (default false)
;killasgroup=false             ; SIGKILL the UNIX process group (def false)
;user=chrism                   ; setuid to this UNIX account to run the program
;redirect_stderr=true          ; redirect proc stderr to stdout (default false)
;stdout_logfile=/a/path        ; stdout log path, NONE for none; default AUTO
;stdout_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
;stdout_logfile_backups=10     ; # of stdout logfile backups (default 10)
;stdout_capture_maxbytes=1MB   ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false   ; emit events on stdout writes (default false)
;stderr_logfile=/a/path        ; stderr log path, NONE for none; default AUTO
stderr_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
stderr_logfile_backups=10     ; # of stderr logfile backups (default 10)
;stderr_capture_maxbytes=1MB   ; number of bytes in 'capturemode' (default 0)
;stderr_events_enabled=false   ; emit events on stderr writes (default false)
;environment=A="1",B="2"       ; process environment additions (def no adds)
;serverurl=AUTO                ; override serverurl computation (childutils)
ปัญหาการรีสตาร์ทเซอร์วิสสำหรับสคริปของ php ได้ถูกแก้ไขโดยใช้แบทไฟล์(bash file) ครอบไว้อีกทีหนึ่งเพื่อป้องกันปัญหาการหยุดการทำงานของสคริป php แต่ยังค้างพอร์ตไว้อีกระยะหนึ่ง ทำให้เซอร์วิสลูกใหม่ไม่สามารถสตาร์ทได้ทันที

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

/etc/init.d/supervisor reload
สำหรับการตรวจสอบเซอร์วิสว่าทำงานหรือไม่ให้ใช้คำสั่ง supervisorctl
#supervisorctl
pheanstalkget                    STARTING
ywt2035v2                        STARTING
ywt3035v2                        STARTING
ywt4035v2                        STARTING
ywt6035v2                        STARTING
ywt7035v2                        STARTING
supervisor> 
หรือคำสั่ง status
supervisor> status
pheanstalkget                    RUNNING   pid 19998, uptime 0:01:37
ywt2035v2                        RUNNING   pid 19467, uptime 0:41:05
ywt3035v2                        RUNNING   pid 19468, uptime 0:41:05
ywt4035v2                        RUNNING   pid 19999, uptime 0:01:22
ywt6035v2                        RUNNING   pid 19985, uptime 0:03:20
ywt7035v2                        RUNNING   pid 19925, uptime 0:03:56
จากคำสั่ง status จะเห็นได้ว่าเซอร์วิส uptime นานที่สุดแค่า 41.05 นาที ส่วนเซอร์วิสอื่น ๆ ก็เพิ่งจะทำงานได้ไม่นาน หากการหยุดทำงานในแต่ละครั้งกินเวลาถึง 5-10 นาทีแบบเดิม ข้อมูลที่สูญหายไปในแต่ละวันย่อมมากเกินกว่าค่าที่จะรับได้

จากการทดลองรันโปรแกรม supervisorctl สำหรับควบคุมโปรแกรมสคริป php พบว่าต้องเพิ่มบรรทัดในส่วนการเรียกใช้งานแอดเดรสใหม่ด้วยตามสคริปที่แนบให้ ให้เพิ่มก่อนถึงบรรทัด socket_bind()
// modified to correct Address already in use
        if (!socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1)){
                echo "socket_set_option() failed: reason: ".socket_strerror(socket_last_error())."\n";
        }
ดังนั้นการรันโปรแกรมสคริป php อัตโนมัติ สำหรับบริการเซิร์ฟเวอร์ TCP ฉบับเซียน จะช่วยแก้ปัญหาเรื่องนี้ได้อย่างชัดเจนและเป็นรูปธรรมที่สุด ข้อสำคัญเนื้อหาบทความดี ๆ อย่างนี้จะเกิดขึ้นไม่ได้เลยหากไม่ได้รับการสนับสนุนจากบริการเวบไซต์ thai-gpstracker.com ผู้นำ รู้ลึก รู้จริง ด้านการให้บริการระบบจีพีเอสติดตามรถยนต์ บริหารงานโดยทีมงานวิศวกร



วันจันทร์ที่ 29 พฤษภาคม พ.ศ. 2560

ใช้งานโปรแกรมจัดการคิวแบบง่าย ประสิทธิภาพสูง beanstalk

หลังจากที่ผู้เขียนได้ผ่านการใช้งานโปรแกรมคิวไฟล์แบบเท็กซ์ไฟล์แบบง่ายไปได้ 3-4 เดือนที่ผ่านมา สร้างคิวไฟล์(queue file)แบบเท็กซ์ไฟล์แบบง่ายโดยใช้โปรแกรม php พบว่าผลการทำงานเป็นไปอย่างไม่ประทับใจ กล่าวคือมีการแย่งกันบันทึกไฟล์พร้อม ๆ กันหลาย ๆ ครั้งส่งผมให้ข้อความที่บันทึกลงในคิวไฟล์ไม่สมบูรณ์ ผิดพลาดค่อนข้างมาก ทำให้ต้องกลับมาทบทวนหาวิธีอื่นดู จนได้พบกับ ใช้งานโปรแกรมจัดการคิวแบบง่าย ประสิทธิภาพสูง beanstalk

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


ขั้นตอนที่ 1 เป็นการติดตั้งโปรแกรมคิว beanstalk

apt-get install beanstalkd

ขั้นตอนที่ 2 เป็นการติดตั้งโปรแกรม pheanstalk สำหรับการติดตั้งผ่าน composer ให้สร้างไฟล์ที่ชื่อว่า composer.json

{
        "require": {
                "pda/pheanstalk": "3.0.2"}
}
จากนั้นทำการติดตั้งโปรแกรม pheanstalk โดยใช้คำสั่งติดตั้งข้างล่าง

#composer install --no-dev

ขั้นตอนที่ 3 เป็นการสร้างไฟล์ สำหรับทดสอบคิวโดยการป้อนข้อมูลลงในคิว 

<?php
require_once("vendor/autoload.php");
use \Pheanstalk\Pheanstalk;

$pheanstalk = new Pheanstalk('127.0.0.1');

// ----------------------------------------
// producer (queues jobs)

$pheanstalk
   ->useTube('testtube')
   ->put("job payload goes here\n");
?>

ขั้นตอนที่ 4 เป็นการสร้างไฟล์เพื่อดึงข้อมูลจากคิวมาใช้งาน

<?php
require_once("vendor/autoload.php");
use \Pheanstalk\Pheanstalk;

$pheanstalk = new Pheanstalk('127.0.0.1');

// ----------------------------------------
// worker (performs jobs)

  $job = $pheanstalk
   ->watch('testtube')
   ->ignore('default')
   ->reserve();
  echo $job->getData();
  $pheanstalk->delete($job);
?>

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

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

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









วันอาทิตย์ที่ 28 พฤษภาคม พ.ศ. 2560

ไม่ต้องเสียน้ำตากับการรันโปรแกรมสคริป php อัตโนมัติ supervisor แบบมืออาชีพ

หลายครั้งพัฒนาโปรแกรมเรียบร้อยแล้ว นำไปใช้งานจริงกลับทำงานได้เพียงแค่สักครู่เดียว โปรแกรมก็หยุดทำงานลง ไม่สามารถทำให้ทำงานแบบต่อเนื่องตลอดเวลาได้ แนวทางสมัยก่อน ๆ ที่ผู้เขียนนิยมใช้ก็คือทำโปรแกรมให้รันแบบเบื้องหลัง(daemon) และใช้ cron ตั้งเวลาสำหรับตรวจสอบโพรเซสว่าทำงานอยู่หรือไม่ ทุก ๆ 5 - 10 นาทีเป็นต้น

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

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


 ขั้นตอนที่ 1 สำหรับโปรแกรมที่ใช้งานก็คือโปรแกรม supervisor การติดตั้งบนเครื่องลีนุกส์เพียงแค่พิมพ์คำสั่งตามที่ผู้เขียนแนบให้แค่นั้น

#apt-get install supervisor

ขั้นตอนที่ 2 กำหนดค่าคอนฟิกให้กับโปรแกรม ตามตัวอย่างผู้เขียนต้องการรันสคริป php แบบอัตโนมัติ แบบตรวจสอบเซอร์วิสให้ด้วยหากหยุดทำงานก็เริ่มต้นสตาร์ทให้ใหม่ด้วย ตามตัวอย่างให้สร้างไฟล์ชื่อ pheanstalk.conf ไว้ในโฟลเดอร์ /etc/supervisor/conf.d/ ข้อสำคัญที่สุดห้ามรันโปรแกรมแบบ daemon หรือแบบเบื้องหลัง

[program:pheanstalkget.php]
command=/usr/bin/php /var/www/tpit/gprmc/pheanstalk/pheanstalkget.php              ; the program (relative uses PATH, can take args)
process_name=%(program_name)s ; process_name expr (default %(program_name)s)
numprocs=1                    ; number of processes copies to start (def 1)
;directory=/tmp                ; directory to cwd to before exec (def no cwd)
umask=022                     ; umask for process (default None)
priority=999                  ; the relative start priority (default 999)
autostart=true                ; start at supervisord start (default: true)
autorestart=true        ; whether/when to restart (default: unexpected)
startsecs=1                   ; number of secs prog must stay running (def. 1)
startretries=3                ; max # of serial start failures (default 3)
exitcodes=0,2                 ; 'expected' exit codes for process (default 0,2)

ขั้นตอนที่ 3 เป็นการเริ่มใช้งานโปรแกรม supervisor และการควบคุมโปรแกรมสคริป php โดยใช้โปรแกรม supervisorctl

#/etc/init.d/supervisor start
# supervisorctl
pheanstalkget.php                   RUNNING   pid 30700, uptime 0:16:55
supervisor>


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






สร้างคิวไฟล์(queue file)แบบเท็กซ์ไฟล์แบบง่ายโดยใช้โปรแกรม php

หลายครั้งที่การสั่งให้ทำงานแบบเรียลไทม์หรือทันทีทันใดไม่สามารถดำเนินการได้โดยเฉพาะการข้อมูลผ่านระบบเครือข่ายอินเทอร์เน็ตบางครั้งสำเร็จ บางครั้งไม่สำเร็จ สำหรับงานลักษณะนี้ ผู้เขียนจะขอแนะนำให้ใช้คิวไฟล์(queue file)แบบง่ายโดยใช้คลาสของโปรแกรมที่ใช้งานง่ายที่สุดก็คือ php นั่นเอง

สำหรับการใช้งานคิวไฟล์เองก็ไม่ยุ่งยาก เช่นหากต้องการเพิ่มข้อมูลเข้าไปในคิวไฟล์ก็ใช้คำสั่ง enqueue() หากต้องการดึงข้อมูลออกจากคิวไฟล์ก็แค่ใช้คำสั่ง dequeue() และหากต้องการให้คิวไฟล์สามารถจัดเก็บข้อมูลในเท็กซ์ไฟล์ก็ใช้คำสั่ง save() นับว่าการใช้งานสามารถนำไปประยุกต์ใช้งานได้อย่างมากมาย


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

ขั้นตอนการสร้างคิวไฟล์แบบเท็กซ์ไฟล์แบบง่ายโดยใช้โปรแกรม php

ขั้นตอนที่ 1 ในการสร้างการป้อนข้อมูลเข้าคิวไฟล์ ผู้เขียนแนะนำให้ใช้โค๊ดอย่างง่าย ๆ ที่แปะไว้ให้ข้างล่างนี้ โดย include เป็นการเรียกใช้งานคลาสคิวไฟล์ คำสั่ง new เป็นการสร้างออปเจคขึ้นมาใหม่ เมทธอด enqueue เป็นการป้อนข้อมูลเข้าคิวไฟล์ จากนั้นทำการ save ลงในเท็กซ์ไฟล์

<?php
include "queue/TitleManager.php";
$qt = new TitleManager();
$qt->enqueue($msgs);
$qt->save();
?>

ขั้นตอนที่ 2 เป็นการสร้างโค๊ดสำหรับดึงข้อมูลออกจากคิวไฟล์ include เป็นการเรียกใช้งานคลาสคิวไฟล์ คำสั่ง new เป็นการสร้างออปเจคขึ้นใหม่ ส่วนเมทธอด dequeue เป็นการอ่านค่าจากคิวไฟล์ในตำแหน่งที่พอยเตอร์อยู่ และเมทธอด save เป็นการบันทึกข้อมูลลงเท็กซ์ไฟล์

<?php
include "queue/TitleManager.php";
qt = new TitleManager();
$msg = $qt->dequeue();
$qt->save();
?>   

ขั้นตอนที่ 3 เป็นการสร้างไฟล์สำหรับคลาสคิวไฟล์ ให้ตั้งชื่อว่า TitleManager.php

<?php

// Title Manager class (essentially a queue) that uses a simple text file for storage
class TitleManager {
        private $filename = "/tmp/gpsmessages.txt";
        private $queueLimit = 10000;
        private $titles;

        // Upon creation, load up our titles from the file
        public function __construct() {
                $this->titles = array();
                $this->loadTitles();
        }


        private function loadTitles() {
                if (file_exists($this->filename)) {
                        $this->titles = file($this->filename, FILE_SKIP_EMPTY_LINES);
                }
        }

        // Add a title to the queue and if we are at our limit, drop one off the end.
        public function enqueue($strTitle) {
                if (!empty($strTitle)) {
                        array_unshift($this->titles, $strTitle . "\n");

                        if (count($this->titles) > $this->queueLimit) {
                                $this->dequeue();
                        }
                }
        }

        // Remove a title item from the end of our list
        public function dequeue() {
                if (count($this->titles) > 0) {
                        return trim(array_pop($this->titles));
                }
                return "";
        }

        // Save the contents of our array back to the file.
        public function save() {
                if (file_put_contents($this->filename, $this->titles)) {
                        return true;
                }
                return false;
        }


        // Check if an item is already in our list.
        // Note: We could have also used in_array here instead of a loop.
        public function isTitlePresent($strTitle = "") {
                if (!empty($strTitle)) {
                        foreach ($this->titles as $title) {
                                $trimmedTitle = trim($title);
                                $strTitle = trim($strTitle);
                                if (strtolower($strTitle) == strtolower($trimmedTitle)) { return true; }
                        }

                        return false;
                }
                return -1;
        }


        // Mainly a debug function to print our values to screen.
        public function printValues() {
                foreach ($this->titles as $value) {
                        echo "$value<br/>";
                }
        }
}
?>


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

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




วันอังคารที่ 18 เมษายน พ.ศ. 2560

คัดลอกพาร์ติชั่นอิมเมจ Ubuntu server ใหม่โดยใช้ lvm

บทความเมื่อครั้งก่อน วิธีการสำรองพาร์ติชั่นแบบ logical volumn management(lvm) โดยใช้ snapshot มาในวันนี้ ผู้เขียนจะพาไปแนะวิธีการคัดลอกพาร์ติชั่นอิมเมจ โดยระบบปฏิบัติการที่ใช้คือเซิร์ฟเวอร์ Ubuntu นั่นเอง การทำงานที่อาศัยการทดลองและปฏิบัติตามขั้นตอนอย่างระมัดระวัง ย่อมสร้างความปลอดภัยให้ข้อมูลรวมถึงความน่าเชื่อถือของการให้บริการ(service availability)

ขั้นตอนที่ 1 ตรวจสอบพาร์ติชั่นเดิมกันก่อนว่ามีข้อมูลใดอยู่บ้าง และต้องการคัดลอกอิมเมจจากพาร์ติชั่นไหน จากตัวอย่างเราต้องการคัดลอกพาร์ติชั่น vm2_01 ขนาดข้อมูล 30 GBytes นั่นเอง อยู่ในกลุ่มโวลลุ่ม innova-vg โดยใช้คำสั่ง lvs

# lvs
  LV            VG        Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
                              
  root          innova-vg -wi-ao----  19.08g                                    
  swap_1        innova-vg -wi-ao----  35.95g                                    
  vm2_01        innova-vg -wi-ao----  30.00g                                    
 

ขั้นตอนที่ 2 เป็นการสร้าง snapshot สำหรับพาร์ติชั่นที่ต้องการคัดลอก คำสั่งนี้สามารถทำได้โดยขั้นตอนดังต่อไปนี้ lvcreate นั่นเอง -L หมายถึง ขนาดของอิมเมจใหม่ -s หมายถึงสร้าง snapshot -n หมายถึงชื่อของอิมเมจใหม่ ตามด้วยพาร์ติชั่นที่ต้องการคัดลอก

#lvcreate -L30G -s -n vm2_01_snapshot innova-vg/vm2_01

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


#dd if=/dev/innova-vg/vm2_01_snapshot of=/mnt/usb/vm2_04_ubuntu

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



#lvcreate -n vm2_04_ubuntu -L30G innova-vg
#dd if=/mnt/usb/vm2_04_ubuntu of=/dev/innova-vg/vm2_04_ubuntu
หรือหากต้องการดูว่าคำสั่ง dd ทำงานได้กี่เปอร์เซนต์ก็ให้ใช้คำสั่งนี้แทน
#dd if=/mnt/usb/vm2_04_ubuntu | pv -s 2G | dd of=/dev/innova-vg/vm2_04_ubuntu bs=4096
ขั้นตอนที่ 5 เป็นขั้นตอนสุดท้าย ให้ลบ snapshot ที่ได้สร้างไว้ในขั้นตอนที่ 2 ออก

#lvremove /dev/innova-vg/vm2_01_snapshot

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

วันพฤหัสบดีที่ 23 มีนาคม พ.ศ. 2560

สร้าง PHP ทำหน้าที่เป็น TCP server รองรับจำนวนลูกข่ายมากกว่า 10 เครื่องพร้อมกัน

บทความนี้ผู้เขียนใช้เวลาทดสอบมายาวนานกว่า 3 เดือนและสามารถใช้งานได้จริงรองรับจำนวนลูกข่ายเข้ามาแอคเซสในเวลาเดียวกันมากกว่า 10 เครื่องพร้อมกัน  การเขียนโปรแกรมแบบซ็อกเกต(socket)เพื่อรองรับจำนวนลูกข่ายเข้ามาใช้งานพร้อม ๆ กันสามารถทำได้อยู่หลายวิธีด้วยกัน แต่ที่พบมากมีอยู่ 3 แบบคือ forking หรือการสร้างโพรเซสลูก, threading หรือการทำงานพร้อม ๆกันยังไม่มีใน php และ select methods เป็นการรอเพื่ออ่านค่าเฉพาะที่มีการส่งมาจากลูกข่าย

สำหรับเนื้อหานี้จะใช้วิธีการที่เรียกว่า select methods โดยฟังก์ชั่น select จะทำงานเฉพาะเมื่อมีกิจกรรมเกิดขึ้นหรือมีการส่งข้อมูลจากฝั่งเครื่องลูกข่ายมายังเซิร์ฟเวอร์นั่นเอง โค๊ดเบื้องต้นผู้เขียนพัฒนาจากอินเทอร์เน็ต เน้นว่าเป็นสคริปง่าย ๆ สะดวกต่อการทำความเข้าใจ ไม่ต้องการไลบราลี่หรือสร้างเป็นคลาสให้ยุ่งยาก

<?php
        error_reporting(E_ALL);
        set_time_limit(0);
        ob_implicit_flush();
        $address = "0.0.0.0";
        $port = "4444";
        $client_socks = array();
        if (($server = socket_create(AF_INET, SOCK_STREAM,0))===false){
                echo "socket_create() failed: reason: ".socket_strerror(socket_last_error())."\n";
                die('something went wrong while creating');
        };
        if (socket_bind($server,$address,$port)===false){
                echo "socket_bind() failed: reason: ".socket_strerror(socket_last_error())."\n";
                die('something went wrong while binding');
        };
        if (socket_listen($server)===false){
                echo "socket_listen() failed: reason: ".socket_strerror(socket_last_error())."\n";
                die('something went wrong while listening');
        };
        while(true){
                //prepare readable sockets
                $read_socks = $client_socks;
                $read_socks[] = $server;
                //start reading and use a large timeout
                if(!socket_select ( $read_socks, $write, $except, 300000 )){
                        die('something went wrong while selecting');
                }
                //new client
                if(in_array($server, $read_socks)){
                        $new_client = socket_accept($server);
                        if ($new_client) {
                                //print remote client information, ip and port number
                                //echo 'Connection accepted from ' . socket_getsockname($new_client, true) . "n";
                                $client_socks[] = $new_client;
                                echo "Now there are total ". count($client_socks) . " clients.n";
                        }
                        //delete the server socket from the read sockets
                        unset($read_socks[ array_search($server, $read_socks) ]);
                }
                //message from existing client
                foreach($read_socks as $sock) {
                        $data = socket_read($sock, 128);
                        if(!$data){
                                unset($client_socks[ array_search($sock, $client_socks) ]);
                                socket_close($sock);
                                echo "A client disconnected. Now there are total ". count($client_socks) . " clients.n";
                                continue;
                        }
                        //send the message back to client
                        socket_write($sock, $data);
                }
        }


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

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

วันอาทิตย์ที่ 15 มกราคม พ.ศ. 2560

การสำรองข้อมูลพาร์ติชั่นแบบ lvm โดยใช้ snapshot

 

วิธีการสำรองพาร์ติชั่นแบบ logical volumn management(lvm) โดยใช้ snapshot 

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

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

ขั้นตอนที่ 1 ตรวจสอบด้วยคำสั่ง lvs เพื่อตรวจสอบดูว่ามีพาร์ติชั่นไหนบ้างในระบบ จากตัวอย่างจะแสดงพาร์ติชั่นทั้งหมดประกอบไปด้วย vm2_02 อยู่ มีขนาดความจุ 80GB มีชื่อของ VG คือ innova-vg


# lvs
  LV            VG        Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  vm2_02                innova-vg owi-aos---  80.00g                                   

ขั้นตอนที่ 2 เป็นการสร้างพาร์ติชั่นแบบ snapshot ขนาด 80gb เพื่อทำการคัดลอกเกสต์โอเอสอิมเมจที่กำลังทำงานอยู่


#lvcreate -L80G -s -n vm2_02_snapshot innova-vg/vm2_02

ขั้นตอนที่ 3 ใช้คำสั่ง lvs ตรวจสอบพาร์ติชั่นที่ทำการสร้างขึ้นมาใหม่ จะพบว่ามีพาร์ติชั่น vm2_02_snapshot ขนาด 80gb ที่ถูกสร้างในขั้นตอนที่ 2 นั่นเอง


# lvs
  LV            VG        Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  vm2_02                innova-vg owi-aos---  80.00g                                
  vm2_02_snapshot innova-vg swi-a-s---  80.00g      vm2_02 1.16                                          

ขั้นตอนที่ 4 เป็นการสำรองข้อมูลไปยัง USB drive หรือ external harddisk โดยใช้คำสั่ง dd หลังจากสำรองของมูลเสร็จเรียบร้อยแล้วให้ดำเนินการตามขั้นตอนถัดไป


#dd if=/dev/innova-vg/vm2_02_snapshot of=/mnt/usb/idcbackup/vm2_02

 หรือต้องการดูความก้าวหน้าของการทำงานของคำสั่ง dd

#dd if=/dev/innova-vg/vm2_02_snapshot | pv -s 80G | dd of=/mnt/usb/idcbackup/vm2_02 bs=4096

 

ขั้นตอนที่ 5 เป็นการลบ snapshot ที่ได้สร้างขึ้นมาออก เป็นขั้นตอนสุดท้ายของการดำเนินการ


#lvremove /dev/innova-vg/vm2_02_snapshot

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