pátek 22. března 2013

PHP - rozdělení kódu do více souborů vs. jeden velký soubor (agregace kódu)

Zajímalo mě, zda je v PHP výhodné mít soubory rozdělené do více malých souborů (jde hlavně o třídy) nebo jestli se vyplatí udělat agregaci nejčastěji používaných tříd do "balíčků", čímž myslím jeden velký soubor PHP.

Hlavní rozdíl je samozřejmě v paměti, pokud PHP načítá třídy přes autoload jen aktuálně potřebné třídy, obsazená pomět bude vždy menší, než když načteme všechny třídy najednou. Ale předpokládejme, že pamět nás netrápí anebo, že naše aplikace načítá beztak skoro všechno. Jak s si tím tedy PHP poradí ? Hmm.

Testovací prostředí
  • centos, php-fpm 5.4.13, apache prefork, APC  3.1.14
Co testuji
vzorek 1: 50 php tříd o velikosti 10KB, tedy 50 souborů celkem 500KB
vzorek 2: 1 php soubor, spojení všech tříd přes "cat", tedy 1 soubor o velikosti 500KB,

Závěr z měření:

  • bez APC parsování tříd zabere více času - 80x více ??  ale jo klidně :) 
  • bez APC PHP scripty zaberou znatelně více paměti (v mém testu je úspora s APC přes 500%!)
    opcode je sice uložen ve sdílené paměti, ale tato paměť se zabere 1x, nikoliv při každém zpracování php scriptu (requestu)
  • nemá cenu se za každou cenu snažit sjednocovat scripty do jednoho, úspora je minimální, sice to vypadá procentuelně jako hodně velké zrychlení (100% )
  • autoload nabídne mnohem větší flexibilitu,  nepožere tolik paměti, opět za předpokladu, že naše aplikace nepotřebuje všechny třídy/includes
  • agregaci do jednoho souboru bych volil v případě, kdy víme, že aplikace bude potřebovat pro každý request více jak 50% komponent anebo když máme pomalý disk a chceme ušetřit IO (stat souboru) při includování, nebo je pomalý autoloader (to je jiná věc)
  • zajímavý postup může být agregování  globálně sdílených komponent do jednoho souboru, může jít často řekněme o 20-30 souborů (tříd či konfigurační soubory), tohle řešení je ale třeba potom ošetřit v situaci, kdy se komponenty mění, v SVN by to šlo přes nějaký hook. Celková úspora bude ale beztak  v jednotkách ms, což za případné problémy s aktualizací nemusí stát.


A výsledek měření ...

vzorek 1 (50 kids):

1. run (ještě není v APC cache)
took 115.624ms
memory_get_usage:      4 194 304

každý další run, průměrné časy  - APC již pracuje
(v APC opcode zabere všech 50 souborů celkem 3 301 600 bytes)

took 2.5239ms
memory_get_usage:      786 432

vzorek 2 (1 big daddy):

1. run (ještě není v APC cache)
took 87.9078ms
memory_get_usage:      4 194 304

každý  další run s APC - průměrné časy 
(v APC opcode zabere 3 170 576 bytes)

took 1.2119ms
memory_get_usage:      786 432

čtvrtek 28. února 2013

SSD v serverech - MySQL


V dnešní době již není nasazení SSD do produkčních serverů považováno za nějaký extrém. Pokud se člověk z principu nebojí nových technologií, v řadě případů může jít o velký posun k lepšímu ve výkonu celého serveru a následně systému, na něm provozovanému.

Pozitiva a přínos

  1. znatelný nárůst IOPS, obrovská výhoda pro databáze, které se nevejdou do RAM resp. innodb buffer pool nepojme všechna hot data, konec dob kdy se při 200tps už systém začíná potit, s SSD jsou hranice tps v řádech tisíců, 5000 a více
  2. seek time řádově 10x až 100x rychlejší
  3. velká výhoda SSD je v random zápisu (a mysql server zapisuje opravdu hodně, a to jak random = updaty tabulek, tak i sekvenčně = binlogy, innodb transakční logy, doubblewrite...)
  4. rychlejší sekvenční načítání dat do RAM při startu serveru, platí za předpokladu, že SSD disk má rychlejší čtení než SAS disky v raidu, tedy obecně všechny SSD se čtením 200MB/s ++
  5. velmi malá spotřeba el. enegie SSD disku, příkon bývá něco kolem 4-5W (týká se pouze SATA, PCIE karty požírají více jak 20W, tedy dost nad hranici SAS 15K disků...) 
  6. SSD bývají cenově velmi výhodné oproti  RAID polím, spolehlivý SSD je levnější v poměru cena/výkon než enterprise disk 15K (cheetah, savvio...). V praxi  je téměř vždy nutné použít kombinaci SAS (s kvalitním řadičem) + SSD, takže úsporu za RAID řadič nemůžeme uvažovat

Negativa

  1. obrovský problém je RAID řadič, starší značkové servery mají takové řadiče, které SSD nepodporují oficiálně vůbec, neoficiálně možná ano ale SSD bude značně degradované ve svém výkonu, silně je doporučeno mít FBWC
  2. nový RAID řadič může být celkem drahý cca 10 000 CZK
  3. klasické SATA SSD běží rychleji bez RAIDu než s ním
  4. kapacita je v řádech 100G, 400G kvalitní SSD už je celkem drahá záležitost
  5. problém může být nepřítomnost kondenzátoru (má ho například Intel 320) kvůli výpadku napájení, pokud je však server postaven za UPC, neměl by to být problém, tedy pokud nevypadne napájení celého bloku serverovny, což se nám už také stalo...
  6. pokud disk nemá kondenzátor, hrozí při zapnuté write cache, že pří výpadku el. se nezapíší data z cache do permanentní paměti, tedy dojde ke ztrátě dat
  7. s vypnutou write cache jsou SSD značně pomalé
  8. pokud disk nemá kondenzátor, lze to ještě řešit přes raid řadič s FBWC (Flash based write cache), ale pro MySQL bych v každém případě doporučil SSD s kondenzátorem (Intel SSD 320, Intel SSD DC S3700, většina PCIE SSD karet...)
  9. levnější SSD není vhodné pro dlouhodobé sekvenční zápisy kvůli omezení počtu přepisu, u řady Intel S3700 podle parametrů, již tohle nehrozí, u Intel 200G S3700 byste museli denně zapsat 2T dat, což je 83GB/hod, jde to, ale je to dost extrém. Nicméně na sekvenční logy bych stále použil SAS/SATA, SSD je pro ně škoda.

Řešení v praxi, instalace SSD do MySQL serveru

  1. v DB serveru nám teď běží Intel SSD 910 400G
  2. ale aktuálně vůbec bych se nebál použít 2x  Intel SSD DC S3700 - 200GB v raid 0, za poloviční cenu
  3. disk naformátován na ext4
  4. mount parition options: noatime, nobarrier, 
  5. ioscheduler: deadline
  6. použit Percona server 5.5.x, hlavně kvůli optimalizačním direktivám, které standardní Mysql nemá
config my.cnf, uvádím pouze speciální optimalizace pro SSD

[mysqld]

  • datadir = /path/at-ssd-disk #SSD
    • innodb_data_home_dir = /path/at-ssd-disk #SSD
      • innodb_doublewrite_file  = /path/to/file/at-sas-disk  #SAS
        • tmpdir  = /path/at-ssd-disk #SSD
          • log-bin = /path/at-sas-disk #SAS
          • innodb_io_capacity  = 20000
          • innodb_flush_method       = O_DIRECT
          • innodb_write_io_threads = 16
          • innodb_read_io_threads = 16
          • innodb_log_file_size = 4G
          • innodb_log_files_in_group = 2
          • innodb_file_per_table = 1
          • innodb_log_block_size = 4096
          • innodb_file_format = Barracuda
          • innodb_read_ahead = none
          • innodb_adaptive_flushing_method = keep_average
          • innodb_flush_neighbor_pages = 0

          [mysqld_safe]

          • numa_interleave = on
          • flush_caches = on