[TYPO3-core] Taming the Performance in 6.2
Thomas Maroschik
tmaroschik at dfau.de
Wed Nov 6 14:51:59 CET 2013
Hi,
Am 05.11.13 16:02, schrieb Ernesto Baschny:
> Package Management
>
> Since beta1 together with the Package Management we introduced a new
> Caching Backend for loading PHP classes and it's class aliases. The new
> concepts minimizes the amount of memory required by not keeping one huge
> array in memory, but it seems that has still some performance drawbacks
> due to heavy use of "require_once". Since this affects all hits (even in
> frontend with all cached), tackling this area will most probably bring
> us the biggest benefit.
With the introduced package management several concepts have been
introduced/reworked along that had to be reflected in the class loader.
If you ask yourself where do all that require files result from read on:
"Arbitrary length vendor and package namespace"
So now you can use YourCompany\YourSolution\YourWhatever as base
namespace. But there can also be another package present that uses
YourCompany\YourSolution as base namespace. This is why you cannot
derive the package namespace deterministically from the class name.
Composer and Flow solves that by sorting the base namespaces (called
prefixes in composer) by length and checking for a match. See [1] for
code. This means for the worst case, in a system with 60 packages the
class name to load is been checked up to 59 unmatching prefixes. A
typical frontend requests loads about 200 classes. This means at worst
200 * 60 = 12000 strpos calls to resolve the package path of the class
name. This is still done now but a match is saved in the caching
framework resulting in a "proxy require" file.
"Keeping nothing more in memory"
With the introduction of namespaces the class alias mechanism has been
established. Due to the renaming of all class names into more meaningful
ones a map of about 1350 old to new class names had to be kept in
memory, because if the old name entered the class loader first the class
loader has to know that this class name is an old one. The inverse map
had to be kept too, because if the new name entered the class loader
first the aliases for the old ones have to be established. This results
in loading two array with 1350 entries upon bootstrap. Further the
ext_autoload.php files of extensions have been merged and loaded too,
which results in another potentially large array. The upfront loading
took constant long time upon every request. The process changed in the
new implementation so that a cache entry for each ext_autoload entry and
class alias is set up resulting in a "proxy require". After the first
request there is no need to load the 3 arrays anymore and logic to
retrieve the class file from the original and aliased class name is
greatly simplified.
"Resolving concurrent write issues"
The old class loader kept a map of class names to class file paths in
memory. Upon request shutdown when any changes to that map happened. it
has been simply serialized to a cache entry. If two request run in
parallel and load different classes new to their class name to class
file map the longer running request overwrites the cache entry which can
result in constant writes on the class name to class file map cache
file. The "proxy require" file approach mitigates that by creating an
atomic cache entry for every class name to class file mapping.
All this happens at the expense of IO which impact greatly depends on
your opcode cache (you really should use one) and the speed of your
filesystem (if you don't use opcode cache). Basically I'm using the
filesystem as key value store where the filename is the key and the
value the class file path and the aliases.
From the feedback in the community I gathered some more insight into
their configurations and their filesystems. The performance can be
increased by a more performant key value store. My current approach I'm
working on includes getting rid of the proxy requires, the special class
loader cache backend, replacing that one by a more efficient file based
key value store based on a append only btree implementation and beeing
able to use also other existing cache backends as alternative.
Kind regards,
Thomas (Tom) Maroschik
[1]
https://github.com/composer/composer/blob/master/src/Composer/Autoload/ClassLoader.php#L222
--
Thomas Maroschik
TYPO3 CMS Active Contributor
TYPO3 .... inspiring people to share!
Get involved: typo3.org
More information about the TYPO3-team-core
mailing list