I’m actually really excited about Hack and HHVM

When you get to be my age you start thinking about the future.  You start wondering if some of the choices you made when you were younger.  You wonder if those choices are going to come back and haunt you.  If you don’t have such thoughts you are either an idiot, or a young person without enough experience to make you think such things.

One of the things that I have been wondering about is whether my decision to focus on PHP several years ago was the right one.  Technology is always changing and eventually the guys writing Ruby, too, will start having children and then will start looking down upon people who use disposable diapers instead of more environmentally friendly cloth instead.  In other words, times change and one of the keys to navigating change is to know what to change, why to change and when, if ever, change is necessary.  Change for the sake of change is stupid.

There are several changes that are occurring in technology.  But one thing that has not changed has been the venom that PHP has been on the receiving end.  Much of the venom is, in fact, deserved, though the quantity by which the venom is spewed is not.  If you are the source of 75% of the traffic on the Internet then you might be doing something right.  But that 75% is today.  What about tomorrow?

And so my question has been “will there be enough innovation in PHP to keep it a force to be reckoned with several years down the road?”  I ask this because there are market and technology changes occurring that PHP is not well suited to navigate.

But before you think that I am totally down on PHP that is not quite true.  PHP was a revolutionary force when the web first came out.  It, and not any other programming language, democratized the web in a way that was not otherwise possible at the time.  But with the web won PHP kind of sat on its laurels for a bit.  Because of this several different languages have gained a foothold.  While PHP won the initial battle for the web (and did it convincingly) it did not protect its flank through continued innovation.  Innovation occurred to some extent, but PHP did not really mature.  In fact, I would argue that Ruby did what market forces are supposed to do to competitors ; forced them to step up them game.

And PHP did.  Within the span of just a few years framework after framework shot up.  The running joke was Q: “How many frameworks are there today?” A “That depends.  Is it Wednesday or Thursday?”  Ruby threatened and PHP responded.  Symfony, Zend, Laravel, Cake and a host others that I am not listing matured the PHP community very quickly.  What was once a hack language grew into a much more mature ecosystem.

But again, PHP seems to have stagnated a little.  There have been several people who have noted dis-function in PHP internals.  I’m not involved that close with that and so I have no definite statement I am willing to make.  However I have been concerned and what I am perceiving to be a slowdown of innovation since PHP 5.3 came out.

But the hack language may be on the verse of another jump forward via the Hack language and the HipHop VM.  While I, as a metalhead, object to the naming of the aforementioned VM with the release of version 3 we may be seeing something that could possible extend PHP’s life by 10-15 years and introduce another round of innovation for PHP.

With version 3 the excitement is almost palpable.  Davey Shafik and Padraic Brady have written blog posts recently that are the source of my optimism.  Resource utilization is a significant concern of mine at Magento (where I work now).  Magento does some really great things but does them at a fairly significant cost of CPU time.  If you’ve played with Customer Segments in EE you know what I’m talking about.  or, for that matter, rendering the layout.  When I was working at Zend I was constantly asked “what switch do I need to make PHP faster?” and an opcode cache can only do so much.  With Hack and HHVM that, quite literal, is a possibility.  In the spirit of full disclosure, I have not had a chance to play with it in depth and I hope to be able to soon, but the potential is there.

And that potential is something to be excited about.  Facebook has demonstrated significant resolve in building the HHVM.  It, like PHP to begin with, was built to solve a real problem; the problem of moving an old language into new times.

And maybe, just maybe, solving that problem will help keep PHP in the position it is in.  Maybe an old dog can be taught new tricks.

 

Now if only someone could provide my wishes of core low level event APIs and easy messaging integration.

assertTrue( ): Amazon: The Everything Company

If you’re thinking about putting your company’s Web presence on Amazon’s computers (using EC2), you might want to ask yourself a few questions. Does Amazon already compete with your business in any way? How long before Amazon does compete with you? Do you want to put your online business in the hands of a potential competitor? Do you want Amazon to know more about your business than it already does? No one’s suggesting Amazon is actually going to spy on your business’s bits and bytes (which are already encrypted anyway, right?), but they can learn a lot simply by knowing your capacity needs, your business’s Web traffic patterns, your scale-out and failover strategies. Just by metering your Web usage, they know too much.

via assertTrue( ): Amazon: The Everything Company.

Magento memory utilization for backend work

I was talking with a colleague about my previous blog post on memory utilization in Magento and he noted that I had not taken into account backend tasks.  Which he was right about.  So I decided to take a second look at the memory usage from the point of view of the admin UI.

But before we do that, let the caveats begin!  Firstly, this was with the sample Magento dataset.  Second, there were no additional modules (beyond Aoe_Scheduler and Alanstormdotcom_Systemsearch).  Third, just because these numbers show low usage does NOT mean you should drop memory_limit down to 32MB.

Read the previous post to see the methodology.

dataflow-export

 

Dataflow Export

reindex

 

Reindexing All Indexes

save-bundle-product

 

Saving a Bundled Product

save-simple

Saving a Simple Product

 

Using events in Magento 2

With the minimal research I have done on Magento 2 recently the only thing I am apprehensive about is the invocation chain.  Its purpose is to open the doors wide open to where you can hook your application in.  I suppose that’s not a bad goal, though I do think that there is wisdom in creative restraint.  Additionally, I don’t like code generation, which is what it uses.  I never have and probably never will.

But why am I saying that at the beginning of a blog post on using events in Magento 2?  That’s because the premise of the invocation chain is that events are going to be less important than they were before.  That’s not to say that they won’t be important, only that they will be less important.  In Magento 1 if you wanted to integrate with the system you needed events (or you could modify core files… which would give you a taste of the back of me hand).  In Magento 2 you might need events.

One of the things that has not changed between Magentos is is the notion of an area.  You still have adminhtml and frontend.  However, instead of having their own node in an XML document they have their own XML files.  Or, more correctly, their more XML file directories.  Event observers are declared in an events.xml file but where those observers are active will depend on the location of an events.xml file.  They will always be under <module>/etc.  If it is in that directory then the event will be watched globally.  If it is under etc/frontend, then it will be observed only when the frontend area is active and the same for adminhtml.  I really like this split.

In terms of declaring an observer a lot has changed, and it’s for the better.  One of the things that was problematic with Magento 1 is that observers needed to be defined under a unique XML node and if there was an accidental collision one of those observers the last merged node would be the one that would win out.  It didn’t happen often, but it was a potential side effect due to the nature of the system.  Now instead of silently overwriting the value you will get an error such as “Duplicate key-sequence [‘controller_action_predispatch’] in unique identity-constraint ‘uniqueEventName'” if your observer has a duplicate name.

Configuring an observer is stupid easy.  No more memorization of “OK, I’m going to put this under /config/global/observers… no, wait.  /config/global/events/observers … no…”.  It is this:

<?xml version="1.0" encoding="UTF-8"?>
 <config>
   <event name="controller_action_predispatch">
   <observer
     name="eschrade_helloworld_echo"
     instance="Eschrade\HelloWorld\Model\Observer"
     method="echoHello" />
   </event>
 </config>

The code for our observer is very similar to how it looked in Magento 1.

1
2
3
4
5
6
7
8
9
namespace Eschrade\HelloWorld\Model;
 
class Observer
{
  public function echoHello(\Magento\Event\Observer $observer)
  {
    echo 'Hello World';
  }
}

This code echos “Hello World” when the “controller_action_predispatch” event is triggered.  Pretty simple.

But this is a poor example.  Why?  Because I’m echoing the content.  There is a dependency I need to properly handle output.  So, as with dependency injection I simply define what I need in the constructor (I have not blogged about this functionality in detail yet, but you don’t need to know the underlying implementation and you can trust that this works as displayed here).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace Eschrade\HelloWorld\Model;
 
class Observer
{
  protected $_response;
 
  public function __construct(
    \Magento\App\Response\Http $response
  ) {
    $this->_response = $response;
  }
 
  public function echoHello(\Magento\Event\Observer $observer)
  {
    $this->_response->appendBody('Hello World');
  }
}

There.  That is how you get things done.  And did you notice that you didn’t need to know anything about dependency injection?  It all kind of work itself out.  It’s even stupider easier to observe events in Magento 2.

But how about triggering them?  It’s a little harder, but not by much.  Did you see earlier where we needed to define a dependency for the response object if we wanted to use it later on?  We simply need to do the same thing for the class \Magento\Event\Manager.  There is no more Mage::app()->dispatchEvent(… and this is a good thing.  It makes for much better testing.  So if you want to trigger an event you simple define the event manager as a dependency.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace Eschrade\HelloWorld\Model;
 
class Observer
{
  protected $_response;
  protected $_eventManager;
 
  public function __construct(
    \Magento\App\Response\Http $response,
    \Magento\Event\Manager $manager
  ) {
    $this->_response = $response;
    $this->_eventManager = $manager;
  }
 
  public function echoHello(\Magento\Event\Observer $observer)
  {
    $this->_response->appendBody('Hello World');
    $this->_eventManager->dispatch('eschrade_echo_helloworld');
  }
 
  public function catchEvent(\Magento\Event\Observer $observer)
  {
    $this->_response->appendBody('Observed event');
  }
}

In our constructor we defined the event manager as a dependency and in the echoHello() method we call the dispatch() method on it.  But simply dispatching the event will not call the catchEvent() method.  In order to do that we need to modify the events.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<config>
 <event name="controller_action_predispatch">
   <observer name="eschrade_helloworld_echo"
     instance="Eschrade\HelloWorld\Model\Observer"
     method="echoHello" />
 </event>
 <event name="eschrade_echo_helloworld">
   <observer name="eschrade_helloworld_echo"
     instance="Eschrade\HelloWorld\Model\Observer"
     method="catchEvent"
     shared="false" />
 </event>
</config>

In this updated configuration file we added the second event which defined the observer configuration.  It’s pretty much exactly the same as the previous definition except that we are observing the event that our observer dispatches (though I would not recommend doing too many nested events).  But I added an additional attribute called “shared” which I set to “false”.  When the event manager dispatches an event it retrieves the observer object from the dependency injection container.  But whether it asks the DI container for a shared object (the default) or a new object depends on the value of the “shared” attribute.  If it is set to false it calls the create() method on the DI container.  For all other scenarios it calls get() which checks the shared instance property for an existing object of the type prior to returning it.

So there you have it.  Basic events in Magento 2.

Performance of Apache 2.4 with the event MPM compared to Nginx

I wrote a little while ago about how, for running PHP, Nginx was not faster than Apache.  At first I figured that it would be and then it turned out not to be, though only by a bit.

But since Apache also has an event-based MPM I wanted to see if the opposite results were true; that if Apache were using its event MPM it would be about the same as Nginx.  I had heard that Apache 2.2’s event MPM wasn’t great (it was experimental) but that 2.4 was better, possibly even faster, than Nginx.

So I had a few spare moments this Friday and figured I would try it out.   I basically ran ab at concurrency levels of 1, 10, 25, 50, 100 and 1000.  Like before the results surprised me.

event-mpm-nginx

 

The first run with Nginx was impressive.  It peaked at 14,000 requests per second.  Given my wimpy VM that  I ran it on, those numbers are pretty good.  What surprised me was that Apache was only half that.  I will say for the record that I do not know how to tune the event MPM.  But I don’t really have to tune Nginx to get 14k requests per second so I was expecting a little better from Apache.  So I pulled out all of the LoadModule statements I could but still have a functional implementation of Apache.  While the numbers were 25% better or so they were still well shy of what Nginx was capable of.  Then I added the prefork MPM to provide a baseline.  Again, I was surprised.  The event MPM was faster than the prefork MPM for static content, but not by much.

So it seems that if you are serving static content Nginx is still your best bet.  If you are serving static content from a CDN or have a load balancer in front of Apache which is running PHP then the prefork MPM is the way to go.  While the event MPM will help with concurrency it will not help you speed up PHP and so is not really needed.

(Basic) Configuring the Magento 2 Dependency Injection Container

My previous blog post on the DIC (Dependency Injection Container) in Magento 2 covered just some basics of using the Magento 2 DIC.  The purpose of that post was to, perhaps, make you less apprehensive about using DI combined with the DIC in Magento 2.  However, in this post I want to go a little deeper into the DIC, implemented via the Magento\ObjectManager\ObjectManager class, and talk about how to configure it.

Configuration for the DIC is done in each module’s etc/di.xml file or etc/<area>/di.xml.  Because you can split DIC configuration based on the area this tells you that the /config/<area> naming stuff is over; which I applaud.  The configuration file has the standard /config base node, but then can have child nodes that are named “type”, “preference” or “virtualType”.  We will focus on “type” and “preference” here.

Type

The first configuration type we will look at is the “type” element.  This is used to give the DIC instructions on configuring the object that has been requested.  There are several instructions that can be given be we are going to focus, for the time being, on the “param” setting.  We will start by creating a new module called Eschrade\HelloWorld.

In that module we are going to create a class called Eschrade\HelloWorld\Model\Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace Eschrade\HelloWorld\Model;
 
class Test
{
  protected $message;
 
  public function __construct($message)
  {
    $this->message = $message;
  }
 
  public function getMessage()
  {
    return $this->message;
  }
}

In order for us to get an instance of that class we need to call the DIC’s create() method.  In the previous blog post we called get().  We will get to that.

So how do we fulfill the requirement for the $message constructor argument?  The second parameter in the DIC’s create() method is that of arguments.  In other words, via the create() method you can inject your own data into the class.

1
2
3
4
5
6
7
8
9
10
11
12
use Magento\App\ObjectManagerFactory;
require_once 'app/bootstrap.php';
 
$locatorFactory = new ObjectManagerFactory();
$om = $locatorFactory->create(__DIR__, $_SERVER);
$test = $om->create(
  'Eschrade\HelloWorld\Model\Test',
  array(
    'message' => 'Hello World'
  )
);
echo $test->getMessage();

When we run this code we get

Hello World

Exactly what we placed in the argument.

But what if there are options you want to pass into the constructor that the classes with the dependency wouldn’t know about.  Some examples could be configuration strings, cache prefixes, template values and so on.  Requiring a class with a dependency to know how to fulfill one of the dependencies of its dependency would be a pain to manage.  To manage such things we now need to look at an example di.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<config>
  <type name="Eschrade\HelloWorld\Model\Test">
    <param name="message">
      <value>Hello World</value>
    </param>
  </type>
</config>

One of the things you might have gotten used to in Magento 1 was arbitrarily throwing XML in wherever you want it.  That is not the case with Magento 2, particularly when it comes to the DIC.  In this case <type> is a node that has a certain definition (it can be found in lib/Magento/ObjectManager/etc/config.xsd).  This node has certain attributes and child nodes that it can have.  One attribute is “name” which tells the DIC the class name that this configuration element is referring to.  This is the fully qualified class name.

As a child node, one of the options is <param> (another is <instance> which we will not look at here).  It also requires a parameter called name which must match the name of the constructor argument, in this case “message”.  <value> is also a required node name and it contains the value of the string that will be passed in to the constructor.

We will now change our code a little to call get() instead of create() on the DIC.

1
2
3
4
5
$locatorFactory = new ObjectManagerFactory();
$om = $locatorFactory->create(__DIR__, $_SERVER);
 
$test = $om->get('Eschrade\HelloWorld\Model\Test');
echo $test->getMessage();

When we run this code we get

Hello World

Congratulations, you have now created a DIC configuration file.

Preference

A big part of using a DIC is the dependence on an interface to define the requirements of a given class.  This allows you to work on various implementation components in parallel while defining what it is this class will require.  Then, as part of unit testing, the interface can be mocked and provide sample data without depending on a concrete implementation of the interface.

So let’s change our Test model class to require an interface for its constructor.  We will call it Message and it will look like this.

1
2
3
4
5
6
namespace Eschrade\HelloWorld\Model;
 
interface Message
{
  public function getMessage();
}

Our Test model will now look like this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace Eschrade\HelloWorld\Model;
 
class Test
{
  protected $message;
 
  public function __construct(Message $message)
  {
    $this->message = $message;
  }
 
  public function getMessage()
  {
    return $this->message->getMessage();
  }
}

If we were to run this code right now we would get an error stating that the DIC could not instantiate an instance of Message because it is an interface.  So we need to do two things.  We need to define a concrete instance of that class and then tell the DIC to use it instead of the interface.

1
2
3
4
5
6
7
8
9
namespace Eschrade\HelloWorld\Model;
 
class HelloWorld implements Message
{
  public function getMessage()
  {
    return 'Hello World';
  }
}

And now our di.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<config>
  <preference
    for="Eschrade\HelloWorld\Model\Message"
    type="Eschrade\HelloWorld\Model\HelloWorld" 
  />
</config>

When we run the code

1
2
$test = $om->get('Eschrade\HelloWorld\Model\Test');
echo $test->getMessage();

We get

Hello World

Instance Parameters

As nice as that was it is not really feasible to have such global definitions all of the time.  And so this time we will use the <type> element to declare HelloWorld as being the proper implementation of Message.  Because all of the code has been written all we need to do is change di.xml.

<?xml version="1.0" encoding="UTF-8"?>
<config>
  <type name="Eschrade\HelloWorld\Model\Test">
    <param name="message">
     <instance type="Eschrade\HelloWorld\Model\HelloWorld" />
    </param>
  </type>
</config>

When we run our test code we get the following output.

Hello World

(Starting) Using Dependency Injection in Magento 2

One of the biggest switches you will experience when moving from Magento 1 to Magento 2 is inversion of control.  This is a very different concept to get used to but once you have it you will be a very happy person.  Maybe.  At least I was.  Understanding how to use dependency injection and understanding how dependency injection works are two completely different things of which the former is probably more important if you are new to it.

I wrote an introduction to Dependency Injection for Zend Framework a while back and was able to work out some of the kinks in my understanding of how a DI container worked with 4 blog posts.  It took a while for me to get it but much of what I learned for Zend Framework does directly apply for Magento 2.

Dependency Injection is handled in Magento 2 via the class Magento\App\ObjectManager.  And if you look at that from within the context of Magento 2 you are probably pooping your pants.  200+ class instances, configuration options, dogs and cats living together.

But is it really that difficult?  Let’s start with a little sample script.

1
2
3
4
5
6
7
8
use Magento\App\ObjectManager;
require_once 'app/bootstrap.php';
 
class Test {}
 
$om = new ObjectManager();
$test = $om->get('Test');
echo get_class($test);

We define a class called Test and create an instance of the ObjectManager.  We then ask the object manager for an instance of the class test and echo it out.  When we do we get

Test

OK.  How did it know about the class Test?  It didn’t.  You did.  You knew you needed an instance of Test and you simply asked the DI container for one.  It did a little magic on the backend on gave you exactly what you asked for.

So why would you do this instead of  just calling “new”?

Ahh, that is where the fun comes in.  What if your class Test had a dependency on another class called Test2 which has a method “helloWorld” that it requires?  So we will

  1. Create a class called Test2
  2. Add a method to that class called helloWorld()
  3. Declare our dependency in the constructor of the class Test
  4. Define a method Test::getOutput() which calls Test2::helloWorld()
  5. profit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
use Magento\App\ObjectManager;
require_once 'app/bootstrap.php';
 
class Test2
{
  public function helloWorld()
    {
      return 'hello world';
   }
}
 
class Test {
 
  protected $test2;
 
  public function __construct(Test2 $test2)
  {
    $this->test2 = $test2;
  }
 
  public function getOutput()
  {
    return $this->test2->helloWorld();
  }
}
 
$om = new ObjectManager();
$test = $om->get('Test');
echo $test->getOutput();

When we call this code we get the following output

hello world

“Wait”, you might be thinking.  “Dependency Injection is supposed to be hard!”

Well, it can be, particularly when you need to start configuring the object instances.  However, from a basic perspective what you see here is what Dependency Injection is all about.

We will continue to dive into deeper Dependency Injection in Magento 2 as time goes on, but this is a good place to start with.  If you are not familiar with DI you will probably have a bunch of questions.  We will get to those as time goes on.

[UPDATE]

I was (correctly) notified on Twitter that I needed to be careful not to mix Dependency Injection and a Dependency Injection Container.  Yes, I mixed the concepts; but for good reason.  If you were to look at my code examples and remove the reference to ObjectManager; meaning that you directly injected the dependency you would be using Dependency Injection.  e.g. new Test(new Test2)).  Technically, that is Dependency Injection.  A Dependency Injection Container is when you ask a central object for an instance of a class at IT satisfies the dependencies.

In Magento 2, however, while the two are technical separate concepts they will, in 99.999% (five 9’s) of the scenarios, be married.  That said, if you are going to be building unit tests for your models, and you should, then understanding the distinction is important.  You might use the DIC to contain mocks or you might directly inject the mocks yourself.  I don’t know which way is best at the moment.

Creating a module in Magento 2

This is the first of what I expect will be several blog posts on Magento 2 as  I learn the system.  I believe that one of the best ways to learn something is to write out what it is you are learning.  This forces you to think through the concepts and determine how to explain them to others.  In doing so you are forced to use terms that are familiar to describe this new thing.  This helps to solidify the concepts in your own mind, making it easier to remember.

But still, there are three caveats.  1) Magento 2 is not out yet (as I write this) so things may change.  2) As I write this I am learning it and so there might be inaccuracies. 3) The information gleaned here has not been passed through the core team and so it is my interpretation of what I see.

One of the most visible changes from Magento 1 is the lack of code pools.  No longer is there a core, community and local set of directories.  I liked that there was this separation between different types of code, but it didn’t functionally add anything.  So this is a change that I am ambivalent about.

The next change is that rather than storing all of your module discovery XML files in app/etc/modules they are now stored in the module’s etc directory.  The benefit of this is that the modules are now more self contained than they used to be.  This is a change that I am quite happy about.  And while there is no longer any scope code there still is loading precedence.  The order precedence is base (Magento), custom (Others) and base (You).  This is determined by the location of the module.xml file.  If it is in app/code/Magento… it is Magento.  If module.xml is under any other directory in app/code then it is put into the “custom” scope.  If module.xml exists in a directory under app/etc, such as app/etc/me/module.xml, it is put into the “base” scope.  The names of the scope are irrelevant, but what is important is the order; mage, custom, base.

The parsing of the module.xml files is done by a class called Magento\Config\Dom.  This class does not use SimpleXML like before, but rather uses DOMDocument.  An interesting thing about this change is that it is possible to reference configuration nodes by ID.

However, there is a problem.  In my IDE at least (Zend Studio), DOMDocument is not viewable in the debug variable view whereas SimpleXML was.  I expect that this might make debugging configuration merge errors a little more difficult because I can’t see what the resulting node looks like.  That said, the merged XML document is converted to an array so after the configuration merge is completed you will see what the config looks like.  Additionally, the module nodes are validated against an XSD located in lib/Magento/Module/etc/module.xsd.  Modules are then stored based on dependency and injected into the cache.

This is all done by a class called Magento\App\ObjectManager\ConfigLoader which is injected into a class called Magento\ObjectManager\ObjectManager which is a replacement for Mage::getModel().  That’s not quite true but, like I said about making references to what is known, it is true enough.

Unlike Magento 1 the module list is not stored in the global configuration.  It is stored in the ObjectManager in an object of type Magento\Module\ModuleList.  This means that you will not be querying the configuration for the module list you will need to define the module list as a dependency in your class.

What this also means is that having a config.xml does not “activate” a module, like in Magento 1.  This also hints that you do not need to do that damn /config/models/<name>/class stuff.  There is a LOT of stuff you can do via dependency that will replicate some of that but I will cover that in a later blog post on DI in Magento 2.  Once you get into area-based DI I think you’ll also be getting into some cool stuff.

So let’s create a module that simply echos “Hello World” in the content.

We will start with a module.xml file in app/code/Eschrade/HelloWorld/etc/.

<?xml version="1.0"?>
<config>
  <module name="Eschrade_HelloWorld" version="0.0.1" active="true" />
</config>

There are a few things different.  For one, the options are specified via XML attributes instead of XML nodes.  Secondly, the version is now required.

In an effort to stick to one topic we will output our “Hello World” via the “controller_action_predispatch” event so we don’t have to yet start talking about Invocation Chains, though we will need to talk about DI for a little bit.

To register an event we need to go to our app/code/Eschrade/HelloWorld/etc directory and create a new file called event.xml with the following content.

<?xml version="1.0" encoding="UTF-8"?>
<config>
  <event name="controller_action_predispatch">
    <observer
      name="eschrade_helloworld_echo"
      instance="Eschrade\HelloWorld\Model\Observer"
      method="echoHello" />
  </event>
</config>

Gotta say I really like this new format compared to the old one.  The name is specified via an attribute and the node has a child called observer with attributes name, which is used to give a unique name to the observer, instance, which is the class name of your observer, and the method, which is the method that needs to be called.

The observer is nice and simple.  Put it in app/code/Eschrade/HelloWorld/Model/Observer.php.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace Eschrade\HelloWorld\Model;
 
class Observer
{
  protected $_response;
 
  public function __construct(
    \Magento\App\Response\Http $response
  ) {
    $this->_response = $response;
  }
 
  public function echoHello(\Magento\Event\Observer $observer)
  {
    $this->_response->appendBody('Hello World');
  }
}

In order for us to echo it properly we need to append it to the response object.  Prior to this we would need to call Mage::app()->getResponse->appendBody().  In this case we simple declared, through the constructor, that we needed the response object and placed it in a protected property of the class.  Then when the observer method is called we simply reference the property and get the following output.

Hello World<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8"/>

The underlying implementation to get this working is somewhat complex but I am quite pleased at how easy it was to get this up and running.

How much memory does Magento use?

So, I was teaching the Magento Performance for System Administrators class the other day.  I’ve delivered the class several times but this is the first time that somebody asked me “How much memory does Magento actually use?”  Now, I know what you’re supposed to set it at, but I’ve never measured actual usage.  So I gave some bullcrap answer about how it really depends on a bunch of things and that I really shouldn’t give a precise answer.  But the individual persisted and I was forced to put my tail between my legs and admit that I didn’t know.

So I promised that I would take a look and here are my results.  I’m sure someone will get their panties in a wad about how it doesn’t do this, that, and the other thing. The purpose of these tests were to give a baseline and that’s it. I expect that an actual catalog implementation will have consumption values higher than what is seen here.

The way I measured the memory usage was that I added some code to Mage_Core_Model_App::dispatchEvent() and took memory measurements each time an event was triggered.  I called both memory_get_usage() and memory_get_usage(true).  I also injected a marker at controller_action_predispatch, core_block_abstract_prepare_layout_before,  core_block_abstract_to_html_before, resource_get_tablename, and controller_front_send_response_after.  The reason for that is so that I could get visual cues as to which part of the execution (controller, layout prepare, layout render) was responsible for each.

The Y axis is memory used in MB.  I divided the memory_get_usage() values /1024/1024 to get the the MB used.  Additionally, because the events were used as the sampling point the X axis represents the event count, not elapsed time as your brain might think.

The data that I used was the Magento sample data.  While it is unrealistic to have such a small catalog in Magento it is the only consistent data that is really available.

memory-home-page

The first mark is the start of the request.  The second is controller_action_predispatch.  The second is core_block_abstract_prepare_layout_before.  The third is core_block_abstract_to_html_before.

memory-category-no-images

At this point I had realized that I had not copied the sample media over.  So I re-ran the request with the media.

memory-category-images

There were only 5 products in this category so I wanted to run a page that had pagination.

memory-category-28-9

memory-category-28-30

Obviously there were some images being re-sized here. But actual usage, while higher, was not overly significant.

Then, of course, there is the question of product pages

memory-simple-product-page

memory-configurable-product

There was no real difference between any of the other product types.

Adding to cart was relatively benign.

memory-add-to-cart

As was displaying the cart ( a 302 Found done after adding to cart).

memory-display-cart

While it is a little difficult to read, here is a chart that shows several of these charts in comparison.

memory-all-items

A couple of takeaways from this

  1. Image processing sucks up memory and could allocate more than memory_limit
  2. Layout generation generally uses the most memory.
  3. From a memory perspective, the product type does not seem to do much to memory consumption
  4. From a memory perspective, the number of items in a category does not seem to have much impact in memory consumption
  5. If memory is an issue, layout XML optimizations might be a valid place to look to reduce usage

However, it bears mentioning

  1. This test did not test very large collections
  2. This test did not test very complicated layouts
  3. This test did not test catalog or shopping cart rules
  4. This test did not test performance
  5. And a bunch of other things.

What is Apdex?

Ever since I started using New Relic I’ve been seeing a number for Apdex.  Given that whenever I see a floating point number I presume that the calculation will be too complex for me to understand I just presumed that it was some kind of mystical number voodoo.

Turns out that it is not.  It’s actually really simple.  First of all, New Relic didn’t come up with it at all.  There is an apdex.org website created by a consortium of different companies.  New Relic just did what any good tech company does and used it to their advantage.

In Excel spreadsheet formulas calculating the Apdex is done by taking an arbitrary number that represents your SLA goal, or some number below.  That is your baseline.  If the page response time is below that number a user is considered “Satisfied”.  If the response time is over that number the user is considered “Tolerating”.  If the response time is over that number by a factor of four they are considered “Frustrated”.  In other words if your baseline is 500ms any user below that is satisified, above, tolerating, above baseline * 4, frustrated.

The purpose of this is to get rid of raw response time measurements as the goal.  It, to some degree, gets rid of the 95% rule.

To calculate an Apdex score create an Excel spreadsheet and have the first column be your Satisfied count, the second your Tolerating, the third your Frustrated and apply this formula to it: =(A2 + (B2 / 2))/SUM(A2:C2).  That is the Apdex score.  It is the number of satisfied users plus the number of tolerating users divided by two divided by the sum of all three.

Here.  Let me show you what that looks like.

Satisfied Tolerating Frustrated Apdex
95 12 3 0.918182
76 10 20 0.764151
60 20 50 0.538462
20 50 50 0.375
0 0 100 0

The score is on a scale of 1 (all users satisfied) to zero (all users frustrated).

What is the time scale?  Whatever you choose.  Your Apdex score is calculated based off of whatever time frame you have specified.  Personally, I think a rolling Apdex is a good idea.  But I didn’t really get a proper view of the number until I took these numbers and put them into a multi-axis chart.  The bars are the total count for requests in each of the different categorizations and the line is the Apdex score.

apdex

 

Seeing that corresponding with the raw values helped me to understand what I was looking at for all these months.

Web Analytics