A bit of a dev story, followed by a bit more of an ops story.
Here's what happened when we decided it was about time to get around to upgrading our PHP 5.3 app to something a bit more current.
View Slide
Glen Mailer
A short audience survey
Set the Scene (as of September 2013)
The Codebase
First commit April 2010 60k commits sinceAccording to git
9300 PHP files 690k lines of codeAccording to cloc
10 releases a week 35 active committers 10 concurrent streams 1 deployable
The Platform
8 Test Environments 1 Staging Environment 2 Live Environments
74 Live PHP boxes
1300 req/s peak 500k uniques/week
Why Upgrade?
Using basically the samePHP version as the firstcommitwith security patches
PHP 5.3 is dead
Bug fixes Performance
New Features!short array syntaxtraits$this in closuresyieldfinally
Bug #64827 GC causes segfaults
The Plan
Upgrade a dev boxSupport 5.3 and 5.5Pass all testsUpgrade 1 Test envUpgrade CIUpgrade Test & StagingIncrementally Upgrade Live
Vagrant Chef Unit Tests Acceptance Tests
Hack hack hack...
3 days later
What changed?
APC becomes OPcache and APCu
Check for new function, fall back to old oneif (function_exists('opcache_reset')) {opcache_reset();} else {apc_clear_cache();}
“The PHP api will retaincompatibility with APC, aswill common configurationoptions, providing a dropin replacement.”APCu
Not a drop in replacement
APCu 4.0.1 APCu 4.0.2 master is closer still
No more mysql_
It will not be missed
preg_replace /e becomes preg_replace_callback
(string) array() Now raises a warningStill returns “Array”
"Type-checked" functionfunction inc($int) {if (!is_int($int)) {throw new InvalidArgumentException('Expected int, got: ' . $int);}return $int + 1;}
Unit test for type-checked function/*** @dataprovider provideIncInvalid*/function testIncRejectsInvalid($a) {try {inc($a);$this->fail('Expected exception');} catch (InvalidArgumentException $ex) {}}function provideIncInvalid() {return array(null, true, "string", array());}
Simplest fixthrow new InvalidArgumentException('Expected int, got: ' .json_encode($int));
$a = "string”; $a['index']; Now raises a warning
// protected $a; ++$this->a Now raises a warning
Progress
Upgrade a dev box Support 5.3 and 5.5 Pass all tests Upgrade 1 Test env Upgrade CI Upgrade Test & Staging Incrementally Upgrade Live
PHPNW 2013
The Rollout
APCu Failures APCu #49: Segfaults APCu #19: deadlock
Forwards or Backwards
Segfaults - 100 point Moving Average7.2/s6.0/s4.8/s3.6/s2.4/s1.2/sOct Nov Dec Jan
Shared Memory? I'm out.
Can we leverage OPCache?
The Barwell Cache
function barwell_store($key, $value) {$path = BARWELL_BASE . '/' . md5($key);file_put_contents($path,'var_export($value, 1));opcache_invalidate($path);}function barwell_fetch($key) {return include(BARWELL_BASE .'/' . md5($key));}
function barwell_store_obj($key, $value) {$path = BARWELL_BASE . '/' . md5($key);file_put_contents($path,'serialize($value) . '")');opcache_invalidate($path);}
Are you mad?
Probably.
Take a moment. Stop. Think.
What is the problemwe're trying to solve?
Fast k/v access for hot paths
How fast do we reallyneed to be?
Move almost everythingover to memcached
Autoload Map Environment Config Weird Zend Reflection
function simple_store($key, $value) {file_put_contents(path($key), serialize($value));}function simple_fetch($key) {return unserialize(file_get_contents(path($key)));}
The Aftermath
Performance
Average Response Time in ms
Average Memory Use in MB
Average Response Time in ms on one API endpoint withminimal external calling
New Features
17 Traits + 4 in tests
2 uses of finally
37 uses of yield
New array syntax?
A few snowflake boxesare still on 5.3
Have bumped minorversion a couple oftimes since
Began upgrading to 5.6 this week
Takeaways
Use configurationmanagement tools
Frequently upgradethings in smallincrements
Shared memory isinherently complicated
Monitor absolutelyeverything
When you think you'redoing something crazy You might be right
Understand why you'redoing something
Fin.
@glenathan https://joind.in/11801