LevelUp! Studio » performance https://blog.levelup.in.th Experience the new world. Fri, 26 May 2017 10:06:07 +0000 th hourly 1 http://wordpress.org/?v=3.8.1 Unity Profiler https://blog.levelup.in.th/2015/08/31/unity-profiler/ https://blog.levelup.in.th/2015/08/31/unity-profiler/#comments Mon, 31 Aug 2015 15:55:18 +0000 http://blog.levelup.in.th/?p=4677 เคยหรือไม่ ทำเกมแล้วกระตุก เคยหรือไม่ ทำเกมแล้ว memory เกินจนภาพกระพริบ หรือกลายเป็นสีดำ เคยหรือไม่ว่าไม่รู้ว่าอะไรกิน Memory มากที่สุด! วันนี้เราขอนำเสนอ Profiler พระเอกของเรา!!

เนื่องจาก Unity 5 เป็นต้นไปสามารถใช้งาน Feature ต่างๆ ได้ฟรีแบบเต็มที่ แน่นอนว่ารวมไปถึง Profiler นี้ เรามาลองดูกันดีกว่า

profiler4

ภาพที่ 1

profiler1

ภาพที่ 2

 

  1. ขั้นแรกเราต้องเลือก Build Setting เป็น Development Build และ Auto Connect Profiler ก่อน Build APK หรือ Build เป็น XCode ตามรูปที่ 1
  2. กด CTRL + 7 หรือ Command + 7 เพื่อเปิดหน้าต่าง Profiler
  3. กดที่ Active Profiler ตามรูปที่ 2 เพื่อเลือกว่าเราต้องการจะดูข้อมูลการทดสอบที่ใด ถ้าดูที่ Editor เลยก็เลือก Editor ถ้าดูที่ Android ก็ต้องต่อ Wifi เดียวกันระหว่าง PC และ android เครื่องนั้นแล้วจะมีชื่อมือถือเครื่องนั้นมาให้เลือกตามรูปที่ 2 และสุดท้ายถ้าเป็น ios ก็ต้องเสียบ USB ครับ
  4. เมื่อเลือก Device ที่ต้องการแล้ว หากถูกต้องจะปรากฏกราฟวิ่งตลอดเวลา โดยมีหลากหลายอย่างให้เลือกดู ที่ดูบ่อยๆ ก็คงหนีไม่่พ้น CPU และ Memory ลองคลิกที่ Memory กันก่อน

profiler2

รูปที่ 3

profiler3

รูปที่ 4

  1. จากรูปที่ 3 จะเริ่มที่ simple ซึ่งเป็นภาพรวมของ memory ที่ใช้ ซึ่งเราสามารถคลิกเปลี่ยนเป็น Detailed แล้วจะมีคำว่า “Take Sample: xxx” อยู่ข้างๆ ตามรูปที่ 4 ให้กดและรอสัก 2-3 นาที (หากเปิด Profiler ก่อนเปิดโปรแกรมบนมือถืออาจเร็วกว่านั้น)
  2. เมื่อมีข้อมูลปรากฏ เราจะสามารถรู้ได้ทันทีว่า ณ เวลาที่เรากด Take Sample  อะไรที่กิน Memory มากที่สุด ซึ่งสิ่งที่กินมากที่สุดมักจะหนีไม่พ้น Texture 2D รองลงมาก็คือ Mesh หากเป็นเกม 3D และสุดท้ายคือ ManagedHeap หรือก็คือ Mono Memory ซึ่งจะเพิ่มอย่างเดียวไม่มีลด ก็ต้องคอยระวัง เคลียร์ค่า Texture 2D หรือ Mesh ไม่ให้ค้างใน Memory ตลอดเวลา ซึ่งหนึ่งในวิธีที่ง่ายที่สุดก็คือการ Load Scene ใหม่นั่นเอง
  3. หากต้องการดู CPU ก็คอยสังเกตว่ามีอะไรที่กราฟพุ่งสูงผิดปกติไหม สูงจนได้ fps ต่ำเกินไป และมี Draw Calls มากเกินไปหรือไม่

ขอให้โชคดีกับการทำเกมครับ :)

 

]]>
https://blog.levelup.in.th/2015/08/31/unity-profiler/feed/ 0
HandlerSocket NoSQL ในรูปแบบของ MySQL https://blog.levelup.in.th/2012/09/30/how-to-install-handlersocketinstall-handlersocket-%e0%b8%a2%e0%b8%b1%e0%b8%87%e0%b9%84%e0%b8%87/ https://blog.levelup.in.th/2012/09/30/how-to-install-handlersocketinstall-handlersocket-%e0%b8%a2%e0%b8%b1%e0%b8%87%e0%b9%84%e0%b8%87/#comments Sun, 30 Sep 2012 05:34:45 +0000 http://blog.levelup.in.th/?p=2057 ก่อนอื่นต้องเท้าความก่อนว่า HandlerSocket คืออะไร HandlerSocket คือ Plugin MySQL ของ InnoDB Engine (เท่านั้น) ที่จะช่วยให้เราสามารถใช้ NoSQL ในรูปแบบของ MySQL ทำให้ได้ speed เพิ่มขึ้นมากหลายเท่าโดยที่โครงสร้างข้อมูลยังอยู่ในรูปแบบของตารางอยู่ (ผู้เขียน HandlerSocket claim ว่าเร็วกว่า Memcache ถ้าปริมาณข้อมูลใส่ใน memory ได้พอเลยนะเออ!) ซึ่งหลักการของ HandlerSocket คือตัดขั้นตอนที่ไม่จำเป็นออกจาก MySQL ทั้งหมด โดยเฉพาะอย่างยิ่ง SQL Parse ซึ่งเป็นขั้นตอนที่กินเวลามากที่สุด แต่ก่อนอื่น เรามาทำความเข้าใจกันสักนิดก่อนจะใช้งาน HandlerSocket

  • ต้องแก้ Code ใหม่เนื่องจากไม่สามารถใช้ SQL query ได้อีกต่อไป ต้องใช้ function ที่ตัวเชื่อมกับ HandlerSocket มีให้เท่านั้น
  • Join ไม่ได้เพราะเป็นการใช้งานแบบ NoSQL เต็มรูปแบบ ใช้ได้เฉพาะ Query ง่ายๆ ของ SELECT,INSERT, UPDATE, DELETE ที่อ้างอิงกับ primary key
  • Replication ไม่ได้ถ้าใช้เป็นรูปแบบการ write (แก้ปัญหาได้ด้วยการใช้แค่ read อย่างเดียว write ยังใช้เป็น SQL เหมือนเดิม)
  • ไม่มีระบบ Autenticatation ไม่มี Security ใดๆ (ต้องเข้าใจก่อนว่า NoSQL เจ้าอื่นๆ เช่น Redis, Memcache ก็เป็นแบบนี้เช่นกัน) แต่สามารถใช้ Firewall block port ที่จะใช้งานจากภายนอกแทนได้
  • ควรปิดระบบ query cache เวลาใช้งานไม่งั้นค่าที่อ่านมาได้อาจผิดพลาด (แต่เนื่องจากมันเร็วส์อยู่แล้ว ปิด query cache ก็ไมได้กระทบกับระบบอะไรมากหรอก)
  • ถ้า insert รัวๆ Auto Increment จะนับข้ามบ้างเป็นบางครั้ง ถ้าไม่ serious ว่าเลขต้องเรียงต่อกันก็ไม่เป็นไรครับ
  • ใช้ได้กับ InnoDB Storage Engine เท่านั้น!

มาดูที่ข้อดีกันบ้าง

  • เร็วส์ (750,000 query/sec แต่อันนี้เป็นคำโม้จากคนสร้างนะครับ ใช้จริงอาจไม่ถึง แต่เร็วกว่า memcache ถ้า memory พอดีกับข้อมูลครับ)
  • INSERT, UPDATE ตัว HandlerSocket จะจับมัดเป็นก้อนเดียวกันโยนไปทีเดียวเลยเหมือนใช้ Transaction ในตัว (เฉพาะ performance นะครับ ไม่ได้ใช้ transaction ได้เต็มรูปแบบ) จริงๆ ก็คือ เร็วส์แหละครับ
  • ข้อมูลยังคงออกมาเป็นรูปแบบของตาราง MySQL ที่เราคุ้นเคย เรายังใช้ SQL มาดึงข้อมูลภายหลังได้ หากเกิดเปลี่ยนใจไม่อยากใช้ HandlerSocket แล้ว
  • เร็วส์ เร็วส์ เร็วส์ (ไม่มีข้อดีอย่างอื่นแล้ว)

ถ้าพิจารณาข้อจำกัดต่างๆ แล้ว ทุกอย่างผ่านหมด ก็มาดูที่วิธีติดตั้งได้เลย

1. install percona server ก่อนเลยครับ ถ้าไม่ใช้ Percona Server ก็ต้อง compile plugin ใช้เองซึ่งวุ่นวายกว่ามากครับ วิธี Install ตามนี้เลย

- apt-get
- yum

2. แก้ไขไฟล์ my.cnf เพิ่มบรรทัดเหล่านี้เข้าไป


loose_handlersocket_port = 9998
# the port number to bind to for read requests
loose_handlersocket_port_wr = 9999
# the port number to bind to for write requests
loose_handlersocket_threads = 16
# the number of worker threads for read requests
loose_handlersocket_threads_wr = 1
# the number of worker threads for write requests
open_files_limit = 65535
# to allow handlersocket to accept many concurrent
# connections, make open_files_limit as large as
# possible.

9998 คือ port สำหรับ read อย่างเดียว ส่วน 9999 คือ port สำหรับ write นะครับ (แก้เลขเป็น port อื่นได้)

3. login เข้า MySQL เป็น root แล้วพิมพ์คำสั่งไปว่า

install plugin handlersocket soname 'handlersocket.so';

4. สั่ง SHOW PROCESS LIST ถ้า Install สำเร็จจะปรากฏ Worker ใน process list ดังนี้


mysql> SHOW PROCESSLIST;
+----+-------------+-----------------+---------------+---------+------+-------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------------+-----------------+---------------+---------+------+-------------------------------------------+------------------+
| 1 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL |
| 2 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL |
...
| 16 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL |
| 17 | system user | connecting host | handlersocket | Connect | NULL | handlersocket: mode=wr, 0 conns, 0 active | NULL |

5. เสร็จสิ้น หลังจากนี้ก็ต้องหา library ที่สามารถติดต่อกับ HandlerSocket มาใช้ละครับ เช่น php ใช้ php-handlersocket nodejs ใช้ node-handlersocket

]]>
https://blog.levelup.in.th/2012/09/30/how-to-install-handlersocketinstall-handlersocket-%e0%b8%a2%e0%b8%b1%e0%b8%87%e0%b9%84%e0%b8%87/feed/ 2
วิธี config และใช้ nginx + php-fpm + fast-cgi เบื้องต้นให้ใช้งานกับ Codeigniter https://blog.levelup.in.th/2011/12/31/basic-configuring-nginx-php-fpm-fast-cgi-for-codeigniter%e0%b8%a7%e0%b8%b4%e0%b8%98%e0%b8%b5-config-%e0%b9%81%e0%b8%a5%e0%b8%b0%e0%b9%83%e0%b8%8a%e0%b9%89-nginx-php-fpm-fast-cgi-%e0%b9%80/ https://blog.levelup.in.th/2011/12/31/basic-configuring-nginx-php-fpm-fast-cgi-for-codeigniter%e0%b8%a7%e0%b8%b4%e0%b8%98%e0%b8%b5-config-%e0%b9%81%e0%b8%a5%e0%b8%b0%e0%b9%83%e0%b8%8a%e0%b9%89-nginx-php-fpm-fast-cgi-%e0%b9%80/#comments Sat, 31 Dec 2011 15:46:23 +0000 http://blog.levelup.in.th/?p=1324 เนื่องด้วยทั่วๆ ไปแล้ว web server มาตรฐานทั่วๆ ไปที่ใช้งานกันคือ Apache แต่ว่า Apache นั้นบริโภค Memory อย่างไม่ไยดี และถ้าเว็บเรามีการใช้งาน static file จำพวกรูปภาพหรือ css, js มากๆ ก็จะกิน Memory หนักขึ้นไปอีก หลักการของ nginx จึงเปรียบเสมือนการเป็นป้ายบอกทางว่าถ้าเป็น static file ให้เรียกไฟล์นั้นๆ ขึ้นมาตรงๆ เลยไม่ต้องผ่าน apache หรือตัวกลางอื่นๆ แต่ถ้าเป็น Dynamic file เช่น PHP ก็ให้ส่งไปยัง Fast-cgi แทน ซึ่ง Fast-cgi จะทำหน้าที่อ่าน PHP เพียงอย่างเดียว ไม่ต้องเผื่อรองรับ static file จึงกิน Memory น้อยกว่านั่นเอง สุดท้ายจึงทำให้สามารถรองรับการใช้งานเว็บไซต์ที่มี traffic หนักๆ ได้อย่างสบายๆ กว่า apache มากหลายเท่าตัว

อันที่จริงแล้ว Apache ก็ไม่ได้มีแต่ข้อเสียขนาดนั้น ข้อดีของ Apache คือเหมือนเป็น All-in-one machine ติดตั้งตัวเดียว ทำงานได้ทุกอย่าง ถ้ามีคนใช้งานไม่มาก เราจะแทบไม่ต้องไปยุ่งกับการปรับ config เลยด้วยซ้ำไป เพียงแต่ว่าเมื่อเราต้องการให้รองรับการใช้งานหนักๆ ได้ เราจึงจำเป็นต้องใช้ “ผู้เชี่ยวชาญเฉพาะด้าน” ซึ่งในที่นี้คือ fast-cgi นั่นเอง และจะมี php-fpm คอยควบคุมสั่งการอีกทอดหนึ่งซึ่งแน่นอนว่าการ config เพื่อใช้งานจึงยุ่งยากกว่า แต่ก็แลกมากับประสิทธิภาพที่น่าพอใจ

ตัวอย่าง file config ของ nginx จาก server เกมของผม (ก่อนอื่นออกตัวก่อนครับว่าผมเองก็พึ่งหัดใช้ nginx เหมือนกัน อาจยังไม่ใช่ config ที่ดีที่สุดในตอนนี้ แต่เป็นเพียง config เบื้องต้นให้ใช้งานได้ครับ) ซึ่งอยู่ที่ /opt/local/etc/nginx/nginx.conf (เครื่องอื่นอาจเก็บอยู่ที่อื่นนะครับ ลองหาดู)

user www www;
worker_processes 1;

events {
# After increasing this value You probably should increase limit
# of file descriptors (for example in start_precmd in startup script)
worker_connections 1024;
}

http {
include /opt/local/etc/nginx/mime.types;
default_type application/octet-stream;

#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';

#access_log /var/log/nginx/access.log main;

sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;

#gzip on;

server {
listen 80;
server_name kdq-web;

#charset koi8-r;

#access_log /var/log/nginx/host.access.log main;

location / {
root /home/jill/web/public;
index index.php index.html index.htm;
# file doesn't exist, let CI handle it
if (!-f $request_filename) {
rewrite ^(.*)/maingame/(.*)$ /maingame/index.php?/$2 last;
}
}

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root share/examples/nginx/html;
}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root /home/jill/web/public;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/jill/web/public$fastcgi_script_name;
include /opt/local/etc/nginx/fastcgi_params;
}
}

server {
listen 443;
server_name kdq-web;

ssl on;
ssl_certificate /opt/local/etc/openssl/levelup/self.crt;
ssl_certificate_key /opt/local/etc/openssl/levelup/self.key;

ssl_session_timeout 5m;

ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;

location / {
root /home/jill/web/public;
index index.php index.html index.htm;
# file doesn't exist, let CI handle it
if (!-f $request_filename) {
rewrite ^(.*)/maingame/(.*)$ /maingame/index.php?/$2 last;
}
}

location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/jill/web/public$fastcgi_script_name;
fastcgi_param HTTPS on;
include /opt/local/etc/nginx/fastcgi_params;
}
}
}

จุดที่น่าสนใจคือตรงนี้ครับ ขออธิบายเป็นจุดๆ นะครับ

1. listen ใช้บอกว่าจะให้ดัก port อะไร ถ้าเว็บทั่วไป (http) ก็ 80 ถ้า secure (https) ก็ 443 ครับ

location / {
root /home/jill/web/public;
index index.php index.html index.htm;
# file doesn't exist, let CI handle it
if (!-f $request_filename) {
rewrite ^(.*)/maingame/(.*)$ /maingame/index.php?/$2 last;
}
}

2. ตรงนี้คือ directory root ตั้งต้นของเว็บผมอยู่ที่ /home/jill/web/public และมีการใช้งานระบบ URI Routing ของ Codeigniter ดังนั้น ผมต้องเซ็ต if ไว้ด้วยว่าถ้าหาไฟล์ไม่เจอให้ rewrite ใหม่ไปยัง maingame/index.php แทน (นับจาก root ที่ตั้งเมื่อกี้) ซึ่งเป็นไฟล์เริ่มต้อนของ Codeigniter และย้าย parameter ที่อยู่ต่อท้าย /maingame/ ไปอยู่ด้านหลัง index.php?/ แทน (ต้องมี ? ไม่อย่างนั้น nginx ก็จะยังหา file ไปเจออยู่อย่างนั้น และ rewrite ใหม่เรื่อยๆ จนเจอ infinite loop) ซึ่งตรงนี้ใช้ syntax แบบ regular expression ครับ

location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/jill/web/public$fastcgi_script_name;
fastcgi_param HTTPS on;
include /opt/local/etc/nginx/fastcgi_params;
}

3. ตรงนี้คือ config สำหรับส่งค่าไปยัง fast-cgi ครับ (port มาตรฐานคือ 9000 อาจแก้ได้ตามต้องการ) ที่น่าสนใจคือ fastcgi_param ใช้ส่งค่าเข้า $_SERVER ครับ ตามชื่อที่ต้องการเลย ถ้าเป็น https ผมบังคับส่ง $_SERVER['HTTPS'] ด้วยเพราะ Apache เคยมีตัวแปรนี้ที่ผมใช้งานอยู่ แต่ใน nginx ต้องกำหนดเพิ่มเองครับ และสุดท้ายคือ include parameter สำคัญอื่นๆ เข้ามาจากไฟล์ fastcgi_params ครับ ในไฟล์ก็มีเนื้อหาด้านล่าง (copy ไปใช้ได้เลย ถ้าเครื่องของคุณยังไม่มี)

fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;

fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;

fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;

fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;

4. จะมี ssl on ให้เปิดใช้ https และ ssl_certificate, ssl_certificate_key เอาไว้กำหนด path ไปยัง cer และ key ตามลำดับครับ

เป็นอันเสร็จสิ้นสำหรับ nginx ส่วน php-fpm ซึ่งเอาไว้ใช้สร้าง process ของ fast-cgi ขึ้นโดยอัตโนมัติและสามารถปรับเพิ่ม-ลดได้ตามปริมาณคนเข้าจริงๆ ของ server (ดีกว่า spawn-fcgi มากครับ ทั้งเรื่องความเสถียร และการ config ให้ใช้งานได้ ซึ่งตัว spawn-fcgi จะไม่สามารถเพิ่ม-ลดจำนวน process ที่ใช้งานตามปริมาณคนเข้าจริงได้) ถ้าไม่มี php-fpm แล้วละก็ หาก process fast-cgi(ที่เราสร้างเองจากการรันใน shell) ตายลงไปละก็ ก็จะไม่มี process มาคอยรับงานจาก nginx ไปประมวลผล php จริงๆ ทำให้ server พังนั่นเองครับ php-fpm นั้นจะติดมากับ php5.3 อยู่แล้ว (หรือถ้าไม่มีก็สามารถ install ตามทีหลังได้ง่าย) หากเป็น php5.2 ก็ยังใช้ php-fpm ได้อยู่เพียงแต่ว่าต้อง build, compile จาก source รวมกับ source php ตัวหลักเอาเองครับ ใครอยากอ่านรายละเอียดข้อดี php-fpm เพิ่มตามอ่านได้ที่ php-fpm.org

config ของ php-fpm จะอยู่ที่ /opt/local/etc/php-fpm.conf (เฉพาะของเครื่องผมอีกเช่นกัน เครื่องคุณอาจอยู่ที่อื่น) config ที่น่าสนใจมีดังนี้

  1. listen = 127.0.0.1:9000 อันนี้คือใส่ให้เหมือน nginx นั่นแหละครับ
  2. pm – ให้เลือกว่าเป็น static หรือ dynamic ซึ่ง static คือตายตัว dynamic คือปรับตาม idle process ที่มี (ควรเลือก dynamic ครับ)
  3. pm.max_children – ให้แตก child ได้สูงสุดไม่เกินกี่ตัวในเวลาเดียวกัน
  4. pm.start_servers – เริ่มต้นมามี child กี่ตัว
  5. pm.min_spare_servers – จำนวน child ที่อยู่ใน idle state ขั้นต่ำ
  6. pm.max_spare_servers – จำนวน child ที่อยู่ใน idle state ไม่เกินกี่ตัว (ถ้าเกินจะ auto kill ทิ้ง)
  7. pm.max_requests – ใช้จำกัดไม่ให้ process นึงกิน memory เกินเท่าไหร่ ใช้กรณีเกิดปัญหา memory leak จากตัว php แต่ยังหาสาเหตุไม่เจอ ให้ auto kill ถ้า request เยอะเกินไปก่อน

สุดท้ายคือ code ที่ต้องแก้ไขใน config.php ของ codeigniter เพื่อให้สามารถอ่าน URI ที่ส่งต่อมาจาก nginx ได้ครับ ดังนี้

$config['uri_protocol'] = "REQUEST_URI";
$index_page = $config['index_page'];
if (!empty($index_page) && strpos($_SERVER['QUERY_STRING'], $index_page) === FALSE)
$script_filename = str_replace($index_page, '', $_SERVER['SCRIPT_NAME']);
else
$script_filename = $_SERVER['SCRIPT_NAME'];
$request_uri = $_SERVER['QUERY_STRING'];
if ($request_uri[strlen($request_uri)-1] != '/')
$request_uri .= '/';

$request_uri = str_replace($script_filename, '', $request_uri);
list($_SERVER['REQUEST_URI']) = explode("&",$request_uri,2);

เรียบร้อยครับสำหรับการ config nginx + php-fpm สำหรับ Codeigniter วันนี้เท่านี้ละครับ :)

]]>
https://blog.levelup.in.th/2011/12/31/basic-configuring-nginx-php-fpm-fast-cgi-for-codeigniter%e0%b8%a7%e0%b8%b4%e0%b8%98%e0%b8%b5-config-%e0%b9%81%e0%b8%a5%e0%b8%b0%e0%b9%83%e0%b8%8a%e0%b9%89-nginx-php-fpm-fast-cgi-%e0%b9%80/feed/ 2
ทดสอบประสิทธิภาพเครื่องด้วย apachebench + newrelic https://blog.levelup.in.th/2011/07/31/test-web-performance-with-apachebench-newrelic%e0%b8%97%e0%b8%94%e0%b8%aa%e0%b8%ad%e0%b8%9a%e0%b8%9b%e0%b8%a3%e0%b8%b0%e0%b8%aa%e0%b8%b4%e0%b8%97%e0%b8%98%e0%b8%b4%e0%b8%a0%e0%b8%b2%e0%b8%9e/ https://blog.levelup.in.th/2011/07/31/test-web-performance-with-apachebench-newrelic%e0%b8%97%e0%b8%94%e0%b8%aa%e0%b8%ad%e0%b8%9a%e0%b8%9b%e0%b8%a3%e0%b8%b0%e0%b8%aa%e0%b8%b4%e0%b8%97%e0%b8%98%e0%b8%b4%e0%b8%a0%e0%b8%b2%e0%b8%9e/#comments Sun, 31 Jul 2011 14:41:14 +0000 http://blog.levelup.in.th/?p=1159 ช่วงนี้กำลังทดสอบประสิทธิภาพ server เลยต้องใช้งาน apachebench (ขอเรียกสั้นๆ ว่า ab) เป็น tools ในการทดสอบประสิทธิภาพ server อย่างหนึ่ง หลังจากลงโปรแกรมแล้ว เราสามารถทดสอบการใช้งานได้ดังนี้

ลองพิมพ์คำสั่งด้านล่างกัน โดย -n คือจำนวน request ทั้งหมดที่จะยิง และ -c คือจำนวน concurrent connection ที่จะใช้ (คือจำลองว่ามีผู้ใช้เข้าใช้งานพร้อมกันกี่คนนั่นเอง) โดยเวลาพิมพ์ชื่อเว็บอย่าลืมพิมพ์ / ต่อท้ายด้วยไม่งั้นจะยิงไม่ได้ ผลจะเป็นดังนี้

ab -n 100 -c 10 http://www.sanook.com/

This is ApacheBench, Version 2.3 <$Revision: 655654 $>

Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/

Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking www.sanook.com (be patient)…..done

Server Software:        Apache

Server Hostname:        www.sanook.com

Server Port:            80

Document Path:          /

Document Length:        154040 bytes

Concurrency Level:      10

Time taken for tests:   2.523 seconds

Complete requests:      100

Failed requests:        0

Write errors:           0

Total transferred:      15435200 bytes

HTML transferred:       15404000 bytes

Requests per second:    39.64 [#/sec] (mean)

Time per request:       252.255 [ms] (mean)

Time per request:       25.225 [ms] (mean, across all concurrent requests)

Transfer rate:          5975.49 [Kbytes/sec] received

Connection Times (ms)

min  mean[+/-sd] median   max

Connect:        2    3   1.5      2      16

Processing:    43  222 180.5    154     885

Waiting:        2   11  40.4      3     210

Total:         45  225 181.0    156     891

Percentage of the requests served within a certain time (ms)

50%    156

66%    275

75%    294

80%    313

90%    494

95%    542

98%    707

99%    891

100%    891 (longest request)

จากผลลัพท์นี้จะเห็นว่าได้ sanook.com รับได้ 39.64 Request/sec และใช้เวลาตอบสนองคือ min 45, mean 225, max 891 millisec ซึ่งเราสามารถทดลองเพิ่มค่า -n และ -c เพื่อเพิ่มขนาดจำนวน load ที่จะยิงได้ตามใจ โดยผมลองยิง server ตัวเอง (ควรจะยิงจากเครื่องอื่นที่ไม่ใช่ webserver เพราะ ab นั้นกินพลัง cpu ด้วยเช่นกัน จะทำให้ค่าที่วัดคลาดเคลื่อนได้ถ้ารันในเครื่องเดียวกับ webserver) ด้วยค่า -n 1000 – c 100 (มีคนเข้าพร้อมกัน 100 คน ทดสอบเมื่อคนเข้าเยอะมากๆ นั่นเอง) และเว็บผมได้ติด Newrelic ดู performance อยู่กรณีมีคนเข้าเยอะผลจะเป็นอย่างไร ได้ผลเป็น 40.20 Request/sec ใช้เวลาตอบสนอง min 215, mean 2313, max 3877 (ยิงด้วยเครื่องที่อยู่ในวง network เดียวกัน) และได้ผลจาก newrelic ออกมาดังรูป

จากรูปก็จะเห็นว่าเมื่อมี Request เพิ่มมากขึ้นแล้ว จะทำให้ php ช้าขึ้นมากอย่างเห็นได้ชัด(กราฟที่แสดงส่วนของ php นี้รวมเวลาทั้ง webserver และ php ไว้ด้วยกัน) ส่วน Database ของผมแม้จะมี Request มากขึ้น แต่ก็ไม่ส่งผลให้ช้าลงมากนัก จึงเป็นอันสรุปได้ง่ายๆ เลยว่า Bottleneck ของ application ตัวนี้เวลาคนเข้าเยอะๆ อยู่ที่ php/webserver นั่นเอง โดยสามารถตัดประเด็นเรื่อง Database ออกไปได้เลย มา optimize ที่ตัว code php และการ set ค่าต่างๆ ของตัว server เองต่อไป ซึ่งตัวผมเองได้ใช้เอามาเปรียบเทียบการเปลี่ยน webserver จาก apache เป็น nginx ก็เห็นผลได้ค่อนข้างชัดเจนเช่นกัน จะเห็นได้ว่า ab มีประโยชน์มากจริงๆ ครับ :)

]]>
https://blog.levelup.in.th/2011/07/31/test-web-performance-with-apachebench-newrelic%e0%b8%97%e0%b8%94%e0%b8%aa%e0%b8%ad%e0%b8%9a%e0%b8%9b%e0%b8%a3%e0%b8%b0%e0%b8%aa%e0%b8%b4%e0%b8%97%e0%b8%98%e0%b8%b4%e0%b8%a0%e0%b8%b2%e0%b8%9e/feed/ 0
5 เทคนิคการปรับปรุงเว็บไซต์ให้ทำงานได้รวดเร็วขึ้น https://blog.levelup.in.th/2011/05/31/5-technique-for-improving-website-performance5-%e0%b9%80%e0%b8%97%e0%b8%84%e0%b8%99%e0%b8%b4%e0%b8%84%e0%b8%81%e0%b8%b2%e0%b8%a3%e0%b8%9b%e0%b8%a3%e0%b8%b1%e0%b8%9a%e0%b8%9b%e0%b8%a3%e0%b8%b8%e0%b8%87/ https://blog.levelup.in.th/2011/05/31/5-technique-for-improving-website-performance5-%e0%b9%80%e0%b8%97%e0%b8%84%e0%b8%99%e0%b8%b4%e0%b8%84%e0%b8%81%e0%b8%b2%e0%b8%a3%e0%b8%9b%e0%b8%a3%e0%b8%b1%e0%b8%9a%e0%b8%9b%e0%b8%a3%e0%b8%b8%e0%b8%87/#comments Tue, 31 May 2011 14:48:09 +0000 http://blog.levelup.in.th/?p=1076 บทความนี้ค่อนข้างจะเป็นบทความภาคต่อจาก ทำไมเว็บไซต์ของคุณช้า หรือล่มบ่อย? โดยเป็นรูปแบบ Software Architecture (สถาปัตยกรรมของซอฟต์แวร์) ที่ต้องใช้ในการรันเว็บ application แต่ก่อนจะไปถึงขั้นนั้นคงต้องถามตัวเองให้ดีก่อนว่าเว็บไซต์ของคุณเป็นเว็บไซต์ที่ใช้งานหนักทางด้านไหน? คนนิยมทำอะไรบนเว็บไซต์ของคุณเพื่อที่จะได้ปรับปรุงเปลี่ยนแปลงรูปแบบการวางระบบของเราได้เหมาะสม ได้แก่

  • เว็บไซต์ของคุณมีรูปแบบ operation ใดมากกว่ากันระหว่าง Read กับ Write? เป็นเว็บที่เน้น Read อย่างเดียวหรือเป็นส่วนมากหรือไม่
  • หากเว็บไซต์ของคุณจำเป็นต้องใช้งาน read มากๆ ลองคิดดูให้ดีว่าข้อมูลที่แสดงให้ User เห็นจำเป็นต้องเป็นข้อมูลที่ Real Time แค่ไหน ข้อมูล update ช้าลงแค่ 5-10 นาทีจะเป็นอะไรหรือไม่ เช่น สถิติการใช้งานต่างๆ ที่มักต้องใช้ข้อมูลจากหลายๆ ส่วนมาประมวลผลรวมกันมากๆ อาจคำนวณแค่เพียงทุกๆ 5-10 นาที แต่ทุกครั้งที่คนคลิกเพื่อดูข้อมูลเราเพียงแสดงข้อมูลที่ผ่านการคำนวณเก็บไว้อยู่แล้วมาแสดงเท่านั้น (Cache)
  • หากเว็บไซต์ของคุณจำเป็นต้องใช้งาน write มากๆ ลองคิดดูให้ดีว่าข้อมูลของคุณจำเป็นต้อง Durability สูงหรือไม่ (ข้อมูลเมื่อเปลี่ยนแปลงแล้วต้องคงอยู่ตลอดไปหรือไม่) เช่นระบบ chat ที่ใช้เพียงคนคุยกันแค่ไม่กี่ครั้งก็ล้างข้อมูลทิ้งหมดแล้ว ข้อมูลเก่าๆ ไม่มีการใช้งานอีก แบบนี้อาจพิจารณาการเก็บข้อมูลทั้งหมดใน Memory แทน
  • หาก write เยอะ ข้อมูลที่คุณต้องเปลี่ยนในการเซพข้อมูลลงหนึ่งครั้ง สามารถเปลี่ยนแนวคิดจากการ write ทุกครั้งที่เปลี่ยนแปลงทันทีมา write เฉพาะตอนที่ web server สิ้นสุดการทำงานครั้งสุดท้ายเพียงแค่ครั้งเดียวได้หรือไม่
  • และอื่นๆ อีกมาก

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

1. ใส่ index ในฐานข้อมูลเพื่อการ query ที่รวดเร็ว

โดยปกติแล้วการทำ query ถ้ามีการกำหนด WHERE หรือ ORDER BY และมีการเรียกใช้งานบ่อยๆ แล้วเราควรจะเพิ่ม INDEX เข้าไปด้วยเพื่อให้กระบวนการค้นหาข้อมูลสามารถกระทำได้เร็วขึ้น โดยหากใส่ INDEX ถูกที่แล้วจะสามารถเร่งความเร็วได้ทั้งกระบวนการ SELECT, UPDATE, DELETE เลยทีเดียว เนื่องจากทั้งสามกระบวนการนี้จำเป็นต้องค้นหาข้อมูลให้พบก่อนจึงจะทำงานต่อไปของตัวมันเองได้

ข้อควรระวัง: ถ้าใส่ index มากเกินไป จะกระทบ performance ด้านการ write ได้ ดังนั้นให้ใส่เฉพาะที่จำเป็นเท่านั้น (แต่ทั้งนี้และทั้งนั้น performance ที่กระทบถ้า index ไม่เยอะเวอร์เกินไปจริงๆ จะไม่ค่อยรู้สึกมาก เพราะจะไปติด bottleneck ที่อื่นก่อนซะมากกว่า)

2. ใช้การเก็บข้อมูลลง Memory เช่น Memcache

เว็บไซต์ประเภท Read เยอะๆ ส่วนใหญ่แล้ววิธีการแก้ปัญหาก็คือการเก็บ Cache ลง Memory เอาไว้ก่อนนั่นเอง เพราะการ access Memory (RAM) จะสามารถเข้าถึงข้อมูลได้เร็วกว่าข้อมูลบน disk (Database) อยู่หลายเท่า เพียงแต่ว่าโชคร้ายที่ RAM ของเรานั้นมีจำกัดเสียเหลือเกิน ทำให้ข้อมูลทั้งหมดยังคงจำเป็นต้องเก็บลง Database อยู่ และเก็บเพียงข้อมูลส่วนที่เรียกใช้บ่อยๆ ภายใน RAM แต่จุดสำคัญคือต้องไม่ลืม update ค่าที่เก็บใน Cache เมื่อมีการเปลี่ยนแปลงข้อมูลเกิดขึ้น เพื่อให้ข้อมูลไม่ผิดไปจากที่ต้องการ โดยเมื่อเกิดเหตุจำเป็นต้อง reboot server ข้อมูลใน cache แม้จะหายไปตาม memory แต่ก็สามารถเรียกกลับคืนมาจาก database ได้โดยง่าย เพราะข้อมูลตัวจริงไม่ได้มีการแก้ไข

ข้อควรระวัง : พื้นที่การเก็บ Cache มีจำกัดเนื่องจาก Memory มีจำกัด เราไม่สามารถ Cache ข้อมูลทุกอย่างจาก database ลง Memory ได้

3. เก็บในรูปไฟล์ HTML โดยตรง

อีกวิธีหนึ่งสำหรับเว็บไซต์ประเภท Read เยอะๆ คือการเก็บในรูปไฟล์ html ไปเลยตรงๆ อันนี้ไม่ได้หมายความว่าให้ทำเว็บโดยห้ามใช้พวก server side script แต่คือส่วนของการประมวลผลข้อมูล และการส่งข้อมูลไปเก็บไว้ใน server จากผู้ใช้นั้นยังคงต้องใช้ server side script อยู่ เพียงแต่เฉพาะส่วนของการแสดงผลเท่านั้นที่เซพเป็น text file ประเภท html โดยตรงเพราะ server ไม่ต้องประมวลผล script ใดๆ ฝั่ง server เลย ทำให้สามารถให้บริการแก่ผู้คนจำนวนมากได้ โดยเมื่อมีการแก้ไขข้อมูลใดๆ ในหน้านั้นๆ จึงค่อยไปสร้างไฟล์ html วิธีนี้จะลด Load ทั้งการ access database และการใช้ CPU ในการประมวลผลแต่ละหน้าลงได้มาก เช่นการแสดงผลกระทู้เว็บบอร์ดที่กระทู้ใดไม่ค่อยมีการแก้ไขก็จะแทบไม่กิน CPU server เลยทีเดียว

ข้อควรระวัง : ใช้พื้นที่ harddisk เป็นจำนวนมากในการเก็บข้อมูล โดยเฉพาะอย่างยิ่งเว็บไซต์ที่มีหน้าข้อมูลอยู่หลายหมื่น หลายแสนหน้าจะยิ่งใช้พื้นที่เยอะมากตาม และหากข้อมูลในแต่ละหน้ามีการเปลี่ยนแปลงบ่อย จะต้องเกิดการสร้างไฟล์ html ขึ้นบ่อยตาม และในท้ายที่สุดก็จะช้ากว่าการเรียกใช้ server side script ธรรมดา

4. ทำ transaction ตอน query ประเภท write

เรื่องนี้หลายคนอาจจะคาดไม่ถึง พวก Database ที่มีคุณสมบัติสามารถทำ Transaction ได้ (ถ้าใน MySQL ก็คือ Engine ประเภท InnoDB ถ้าใช้ MyISAM จะไม่มีคุณสมบัติตัวนี้) นอกจากประโยชน์ของการทำ Transaction จะเป็นความปลอดภัยของข้อมูลที่แก้ไขจะได้ถูกต้อง 100% แล้ว การทำ transaction ยังหมายถึงการจับมัดก้อน query ประเภท write ให้ไปแก้ไขที่ database พร้อมๆ กันในครั้งเดียวอีกด้วย ซึ่งส่งผลให้เร่งความเร็วการ write ขึ้นได้หากเว็บไซต์ของคุณมีการ write ข้อมูลบ่อยๆ และ write หลายอย่างหรือในหลายครั้งในเวลาใกล้ๆ กัน ทดสอบได้ง่ายๆ ด้วยการสั่ง START TRANSACTION ครอบส่วนของ for ที่วนลูป insert ลง database สัก 100 ครั้ง แล้วจับเวลาที่ใช้ไปก็จะเห็นผลชัดเจนครับ

ข้อควรระวัง: START TRANSACTION แล้วอย่าลืม COMMIT ด้วย ไม่เช่นนั้น database ของคุณจะทำงานไม่เสร็จและอาจทำให้เกิดปัญหากับ database ได้ และหากมีการ write เพียงไม่กี่ครั้งต่อ 1 request อาจใช้วิธีนี้แล้วไม่ค่อยเห็นผลชัดเจนนัก

5. ใช้รูปแบบสถาปัตยกรรมซอฟต์แวร์ที่หลากหลายให้เหมาะสมกับงานที่ทำในแต่ละส่วนเฉพาะทาง

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

  • ใช้ Redis  (Redis ทำงานคล้ายกับ Memcache แต่จะดีกว่าเนื่องจากรับประกันว่า reboot เครื่องแล้วข้อมูลที่เคยอยู่ใน RAM จะไม่หายไป) ล้วนๆ เป็นฐานข้อมูลในการจัดเก็บข้อมูล Chat Log เพราะข้อมูลเก่าๆ จะถูกทำลายทิ้งเรื่อยๆ โดยอัตโนมัติอยู่แล้ว จึงไม่จำเป็นต้อง write ลง disk ให้เสียเวลา
  • ใช้ MySQL เก็บข้อมูลหลักของตัวเว็บเนื่องจากสามารถ Query ข้อมูลได้ซับซ้อน ใช้ MongoDB ในการเก็บ Log เนื่องจาก write เร็วและใช้ Redis ในการเก็บ cache ทั้ง Read และ Write
  • อื่นๆ

ตอนนี้ผมยังไม่ค่อยรู้รูปแบบสถาปัตยกรรมมากนัก จึงยกตัวอย่างได้น้อย เอาไว้มีข้อมูลแล้วจะเขียนให้ละเอียดๆ อีกทีครับ

]]>
https://blog.levelup.in.th/2011/05/31/5-technique-for-improving-website-performance5-%e0%b9%80%e0%b8%97%e0%b8%84%e0%b8%99%e0%b8%b4%e0%b8%84%e0%b8%81%e0%b8%b2%e0%b8%a3%e0%b8%9b%e0%b8%a3%e0%b8%b1%e0%b8%9a%e0%b8%9b%e0%b8%a3%e0%b8%b8%e0%b8%87/feed/ 0