Giter VIP home page Giter VIP logo

wordpress-pecl-memcached-object-cache's Introduction

Build Status

Overview

This project is a WordPress object cache backend that implements all available methods in the Memcached PECL extension. For a detailed account of how this differs from a Memcache PECL backend (note the inclusion/exclusion of the "d"), read the article I wrote on the topic.

Installation

  1. Install the Memcached daemon. Memcached should be available via your favorite package manager in your Linux distribution of choice.

    For Ubuntu and Debian:

apt-get install memcached ``` For CentOS:

```bash

yum install memcached ```

Note that you will likely want to review the Memcached configuration [directives](http://serverfault.com/questions/347621/memcache-basic-configuration). To get the best results from Memcached, you will need to configure it for your system and use case.
  1. Start the Memcached daemon:

service memcached restart ```

  1. Verify that Memcached is installed and running.

    1. From your server, telnet into the Memcached server

telnet localhost 11211 ```

	You should see output like:

	```bash

Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. ```

1. Type `version` into the Telnet prompt. If Memcached is installed and running, you should see something like:

	```bash

VERSION 1.4.14 (Ubuntu) ```

1. Exit Telnet by typing `ctrl` + `]`, hitting `enter`, then typing `quit` and pressing `enter`.
  1. Install the Memcached PECL extension on your server. Note that there are two different PHP interfaces for Memcached; one is named PECL Memcache and the other, PECL Memcached. The "d" at the end of Memcached is extremely important in this case. You should be able to install PECL Memcached from your package manager for your Linux distro.

    For Ubuntu and Debian:

apt-get install php5-memcached ```

For CentOS:

```bash

yum install php-pecl-memcached ```

Note that if you have a more custom installation of PHP, you might need to take some extra steps to link the PECL Memcached extension to PHP. If you are setting this up using your package manager's version of PHP and PECL Memcached, this should not be necessary. For example, many `yum.conf` files will exclude packages that begin with `php`. You may be able to modify the configuration file as necessary to install this package.
  1. Verify that the Memcached daemon is running and accessible via the PECL Memcached extension in PHP. The easiest way to test this is to run a simple PHP script that connects to Memcached and tries to set and retrieve a value.

    1. Enter PHP's interactive shell:

php -a ```

1. Type the following in the interactive shell:

	```bash

php > $m = new Memcached(); php > $m->addServer( '127.0.0.1', 11211 ); php > $m->set( 'foo', 100 ); php > echo $m->get( 'foo' ) . "\n"; ```

1. If that last command returns `100`, everything is working! If you get blank output, something is amiss.

	Note that if your PHP configuration does not support the interactive shell, you can use the code above to create a script to execute in the browser. The interactive shell is easier for the verification step as it does not require a functioning web server.
  1. Now that the server dependencies are resolved, the rest of the configuration is in the WordPress application. Take the object-cache.php file and place it in your wp-content folder. For instance, if the root of your WordPress installation is at /srv/www/wordpress, the location of object-cache.php would be /srv/www/wordpress/wp-content/object-cache.php. Please note that object-cache.php is a WordPress drop-in. It is not a regular plugin or an MU plugin. Drop-ins are located directly in the wp-content folder.

  2. Add the following to your wp-config.php file:

    global $memcached_servers;
    $memcached_servers = array(
        array(
            '127.0.0.1', // Memcached server IP address
            11211        // Memcached server port
        )
    );

    If your Memcached server is located on a different server or port, adjust those values as needed. If you have multiple Memcached instances, add additional servers to the array:

    global $memcached_servers;
    $memcached_servers = array(
        array(
            '1.2.3.4',
            11211
        ),
        array(
            '1.2.3.5',
            11211
        )
    );
  3. To test the WordPress object cache setup, add the following code as an MU plugin:

    <?php
    $key   = 'dummy';
    $value = '100';
    
    $dummy_value = wp_cache_get( $key );
    
    if ( $value !== $dummy_value ) {
    	echo "The dummy value is not in cache. Adding the value now.";
    	wp_cache_set( $key, $value );
    } else {
    	echo "Value is " . $dummy_value . ". The WordPress Memcached Backend is working!";
    }

    After adding the code, reload your WordPress site twice. On the second load, you should see a success message printed at the top of the page. Remove the MU plugin after you've verified the setup.

Authors

  • Zack Tollman
  • 10up

wordpress-pecl-memcached-object-cache's People

Contributors

cmmarslender avatar justinsainton avatar ramoonus avatar tollmanz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wordpress-pecl-memcached-object-cache's Issues

Handle NULL $cas_token value for get and getByKey

The following code fails:

$m->get( 'my-key', null, $cas_token );

It fails because the first conditional in the method sees the third argument as null and therefore does not call the Memcached get method. Instead it pulls from the internal cache. A way around this is to do something like:

$cas_token = ''; $m->get( 'my-key', null, $cas_token );

Using the native Memcached class' get method works with the first example. This class should emulate that.

High Availability Memcached

So I have a high availability setup with a load balancer to two wordpress servers with wordpress-pecl-memcached-object-cache installed.

Obviously when one cache is updated, the other is not. If I specify each individual server IP in global $memcached_servers, does it mean that when one memcached is updated, the other will be concurrently updated?

Cannot use a scalar value as an array options.php

After installing the drop in, I get the error:
Warning: Cannot use a scalar value as an array in /var/www/vhosts/domain.com/httpdocs/wp-includes/option.php on line 68

Any ideas?
WP Version 3.8.1

Remove $server_key arrays in internal cache

After significant thinking, waffling, and misunderstandings about the *ByKey methods, I have decided to remove the notion of server keys within the internal cache.

Memcached's implementation of the ByKey methods are a little confusing and have been the primary reason I've changed my mind about how to tackle this issue. After a lot of testing, I have found the following truths to be self-evident:

  1. When adding a value to cache with a ByKey method, you should be able to retrieve that value with a ByKey method if you use the same server key.

  2. When adding a value to cache with a ByKey method, if you request the key with a ByKey method using a different server key, it may or may not find the result. This is dependent upon whether the different server key used is mapped to the same server or not.

  3. The server key mapping is entirely arbitrary. The only way to tell if two server keys refer to the same server would be to compare them using the getServerByKey method.

  4. I could theoretically add my own server key/server mapping to the class, which would allow me to appropriately store values in the internal cache by key which should lead to the exact same result returned from the internal cache as from memcached.

  5. By not storing values by server key, there is a reduction in overhead to store/access keys from the internal cache. Additionally, I do not see any benefits of doing so.

Given this, I will be removing the notion of server keys from the internal cache (which I unfortunately just reimplemented).

Add support for the binary protocol

There are possibly performance benefits with the binary protocol. Currently, setting this option causes the CAS functions to fail. The option should be set via the config rearrangement in #40.

Allow setting of global options

PECL Memcached exposes a lot of options. This library allows you to set some of them via the wp_cache_set_option() function. While this will work in some cases, it's not a great way to set options for the object cache prior to core using the cache.

I would like to extend $memcached_servers into something like $memcached_config that contains these options. These options would be initiated as soon as the object cache is initiated. This would also make it easier to test these options in Travis CI.

Add stats functionality

The other WordPress object cache backends have stats functionality. It might be worth adding this here, but perhaps using a different method to reduce overhead.

Clone objects before they are returned from cache

When PHP returns an object, it does so by reference, which means that the returned value has the capability to change the "original" value. This tends not to matter, but in the case of object caching it can cause big (and confusing) problems. If an object (i.e. is_object(), not just a generic name for data) is returned from cache, then changed, the change affects the data in the cache. The most common way this manifests itself in WordPress is through filters. Here's an example.

function es_runaway_filter( $theme ) {
    $theme->price = $theme->price * 2;
    return $theme;
}
add_filter( 'get_premium_theme', 'es_runaway_filter' );

function get_premium_theme( $id ) {
    // Let's assume this object is always in cache
    return apply_filters( 'get_premium_theme', wp_cache_get( $id, 'themes' ) );
}

echo get_premium_theme( 123 )->price; // Let's say this prints 100
echo get_premium_theme( 123 )->price; // This prints 200
echo get_premium_theme( 123 )->price; // This prints 400

As you can see, each successive call gets the data that's already been altered by all of the previous calls.

The solution to this is to check if a value is an object (again, is_object() style) before returning it from cache (local and remote). If it is, clone it before returning it for happy filtering.

Determine cache function namespacing

Nacin recommended that the "wp" namespace not be used for these functions. I need to settle on a good namespace prefix. Thinking "memd" for the moment. Once that is done, will need to update unit tests.

Allow settings via Environment variables

First of all thanks for your work this.

Me, @franz-josef-kaiser and other fellows are very interested on the usage of this package on a pretty big website and integrate it in our workflow that is based on Composer and environment variables.

I already seen there's a PR about supporting Composer, and that's fine, so what is missing is the second part.

What I have in mind is something that affect only WP_Object_Cache constructor, that should be something like this:

public function __construct( $persistent_id = NULL ) {

    global $memcached_servers;

    // some code here

   $default_servers = array( array( '127.0.0.1', 11211 ) );

   if ( ! isset($memcached_servers) && ( $env = getenv( 'WP_MEMCACHED_SERVERS' ) ) ) {
     $servers = explode( ';', $env );
     $memcached_servers = array();
     foreach( $servers as $server ) {
          $data = explode( ':',  $server );
          if ( ! empty( $data ) ) {
            $port = isset( $data[1] ) && is_numeric( $data[1] ) ? (int) $data[1] : 11211;
            $memcached_servers[] = array( $data[0], $port );
          }               
       }
   }
   $this->servers =  $memcached_servers ? $memcached_servers : $default_servers;

   // rest of the code here
}

In this way would be pretty simple to add servers like this:

putenv( "WP_MEMCACHED_SERVERS=127.0.0.1:11211;127.0.0.2:11211" );

With a little edit on code above it would be also possible support unix socket (as proposed in #42) and for authentication (related: #32):

// unix socket
putenv( "WP_MEMCACHED_SERVERS=unix:/tmp/memcached.sock" );

// authentication
putenv( "WP_MEMCACHED_SERVERS=username:[email protected]:11211" );

Finally, a very similar approach can be used to support various Memcached settings (related: #40) using a single ENV var (e.g. WP_MEMCACHED_CONFIG) or more variables, one per setting.

I think that a configuration based on environment variables would be apprecciated by a lot people: Bedrock is pretty popular, and WP Starter is young but promising, even if I'm biased regarding the latter.

Moreover, per code above, it only has effect if global var is not set and the environment variable is, so it will not affect who don't use environment vars.

If you like this idea I can make a PR.

Slows down site

Any reason why this would add 6-10 seconds of page generation time? I'm assuming I have a configuration problem somewhere. I have both memcache and memcached pecl extensions installed, wp-config is configured as you specified and my memcached config is below:

-d
logfile /var/log/memcached.log
-m 512
-p 11211
-u memcache
-l 127.0.0.1
-c 4096
-k
-r
-t 8
-b 8196

Cheers,
Ed

Licensing

I failed to specify a license when this was initially released. Since then, I have accepted contributions from others. Following VVV's lead, I think it is important that current contributors have a say in the licensing.

I think we should settle on MIT or GPLv2 and I personally lean toward MIT, but am up for any thoughts folks have.

Can the following individuals please let me know your preference:

Thanks, everyone!

Unit test wrapper functions

All of the wp_cache_* functions have not been tested. The current unit testing directly tests the WP_Object_Cache methods. It should be relatively straight forward to port the tests over for tested the wrapper functions. It is important to do this testing in order to verify that the methods are being called correctly.

Using with Wordpress REST API

Possible noob question...I'm using the Wordpress REST API and have implemented this, but when I make an xhr request it doesn't seem to to be caching properly. The test script works and returns:

Value is 100. The WordPress Memcached Backend is working!

Is there anything else I need to do in order for this to work on data loaded via the wordpress REST API? This is the response header ...

Access-Control-Allow-Headers:Authorization
Access-Control-Expose-Headers:X-WP-Total, X-WP-TotalPages
Allow:GET
Cache-Control:no-cache, must-revalidate, max-age=0
Connection:Keep-Alive
Content-Length:1741
Content-Type:application/json; charset=UTF-8
Date:Sat, 14 May 2016 21:37:46 GMT
Expires:Wed, 11 Jan 1984 05:00:00 GMT
Keep-Alive:timeout=5, max=99
Last-Modified:
Pragma:no-cache
Server:Apache/2.2.22 (Ubuntu)
X-Content-Type-Options:nosniff
X-Powered-By:PHP/5.3.10-1ubuntu3.22
X-WP-DeprecatedFunction:register_api_field (since WPAPI-2.0; use register_rest_field instead)
X-WP-Total:1
X-WP-TotalPages:1

$memcached_servers compatibility with "the other plugin"

I'm not sure if this was intentional or discussed before, we use(d) a fork of this dropin: https://wordpress.org/plugins/memcached/ which I'm sure most are familiar with.

The format for defining $memached_servers global in that plugin is as such:

$memcached_servers = array( 'hostname:port' );

Whereas wordpress-pecl-memcached-object-cache uses:

$memcached_servers = array( array( 'hostname', 'port' ) );

This annoyingly makes the two configurations very similar but different. I am running the same codebase with each dropin, which makes it a pain to do different configuration. I just wondered if compatibility had been discussed for these?

Thanks!

Possible memory leak

Hi @tollmanz
Following some work on my side to test this plugin under load tests I thing I see an issue when non of the memcached servers are available.
When running the load test and stopping the memcached instance(s), over time, the usage of memory on the php server is increasing.

Once I start the memcached instance(s) again, the memory utilization is kept on the same level.

My setup is apache 2.4 with mod_php.
Memory is used by the apache/php processes.

I'll try to make sure this issue is not only due to my PR #54 #55 and if it isn't, I'll try to look into PHP memory dumps to troubleshoot that.
Are there any known memory issues?

For multiple single-site installs on single server, should WP_CACHE_KEY_SALT default to db_name + table_prefix?

I have multiple single-site installs on a single server. All use the same memcache server.

I want to make sure each site uses distinct keys to avoid collisions.

From the code, it looks like I have to manually specify a unique WP_CACHE_KEY_SALT in each site's wp-config.php to guarantee each site has unique namespacing of keys.

Might it be better to make WP_CACHE_KEY_SALT default to db_name + table_prefix? This should prevent collisions if I forget to define WP_CACHE_KEY_SALT. Some single-site installs on a single server will use the same database with different table prefixes, some will use different databases with the same table prefix, but a combination of the two should guarantee uniqueness. Inspired by here.

I also looked into using site_id + blog_id, but because they're single-site installs and thus unaware of each other, it doesn't look like this works. Alternatively, perhaps there's a variable for the domain name/subfolder that could be used instead?

I can submit a PR if desired, just wasn't sure if this was the best way to handle the issue... I'm rather new to Wordpress.

License

Hey hey, what's the license of this wonderful thing? I want to use it in another plugin I'm making, is that okelidokely?

hack^2

Would you use a define?

define('MEMCACHE_SERVERS', serialize(array(
    array(
        '127.0.0.1',
        11211
    ),
    array(
        'domain.com',
        11211
    )
)));

var_dump(unserialize(MEMCACHES_SERVER));

Caching shopping cart using SSL

Shortish version. If I activate this for my multisite, everything works except the shopping cart. That gets all weird and will show cached data, when it really shouldn't.

The whole site is https. Shouldn't that not be getting cached?

Refactor ByKey methods

Since removing the server keys from the internal cache (26116b1), all of the methods that have a ByKey relative, are essentially the same function other than the difference in the call to memcached. The code could be greatly simplified by trying to integrate methods with their ByKey relatives. This would likely involve adding another parameter to the functions that allow to toggle between the normal function and the ByKey version of the function.

Can I use this alongside a full-page cache like WP-Supercache or WP-FFPC?

This isn't so much of a bug report as a question about how object-caching in Wordpress actually works under the covers. I thought I understood Wordpress caching, but then I read some docs + code, and now I'm confused... any help is appreciated.

I'm trying to accomplish the following:

  1. Use Wordpress built-in caching mechanism to cache stuff for logged-in users. From my understanding, this stores the output of object compilation so PHP can work with pre-assembled objects and doesn't have to recompute values and re-hit the DB... among other things, it can make the admin panels faster. I've been happily using this plugin to tell Wordpress to use memcache as the backend for the built-in object cache with no issues.
  2. Add a full-page cache for logged-out users. I'd like to use WP-FFPC or WP-Supercache to serve pre-generated pages from Nginx/memcache or Nginx/disk and entirely skip the PHP interpreter/MySQL.

Conceptually these are very different, so I assumed they wouldn't conflict, but I just tried installing WP-FFPC and WP-Supercache, and both of them require that I set define('WP_CACHE', true); in wp-config.php, which makes me wonder if my mental model of Wordpress caching is inaccurate? Any idea if those full-page caching plugins will conflict with this object-cache?

Cross-posting here: petermolnar/wp-ffpc#40

Remove the global prefix

This needs testing, but there is a good chance this will mess up global groups. The fix would be to use prefixes like Boren's object cache.

Add server number awareness to *ByKey methods

It appears that the *ByKey methods in Memcached are very arbitrary. It is hard to match a key to a server. The following changes are suggested:

  1. In the event that there is a single server, route all *ByKey requests to a single $server_key for the runtime change. The getServerByKey method may need to be utilized to make this work correctly.

  2. Will likely need to create an internal mapping of server keys and servers in order to keep runtime cache and memcache servers in sync.

Tag releases

By now there are no tags. This makes it hard (or: impossible) to use anything aside from fake releases (branch aliasing) via Composer. This also makes it impossible to request this package without Composer using Git, cloning everything and then checking out the specific tag. This should get fixed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.