automattic / wp-memcached Goto Github PK
View Code? Open in Web Editor NEWMemcached Object Cache for WordPress.
Home Page: https://wordpress.org/plugins/memcached/
License: GNU General Public License v2.0
Memcached Object Cache for WordPress.
Home Page: https://wordpress.org/plugins/memcached/
License: GNU General Public License v2.0
=== Memcached Object Cache === Contributors: ryan, sivel, andy, nacin, barry, ethitter, nickdaugherty, batmoo, simonwheatley, jenkoian, bor0, aidvu Tags: cache, memcached Requires at least: 5.3 Tested up to: 6.0 Stable tag: 4.0.0 Requires PHP: 7.4.0 Use memcached and the PECL memcache extension to provide a backing store for the WordPress object cache. == Description == Memcached Object Cache provides a persistent backend for the WordPress object cache. A memcached server and the PECL memcache extension are required. == Installation == 1. Install [memcached](http://danga.com/memcached) on at least one server. Note the connection info. The default is `127.0.0.1:11211`. 1. Install the [PECL memcache extension](http://pecl.php.net/package/memcache) 1. Copy object-cache.php to wp-content 1. Add the `WP_CACHE_KEY_SALT` constant to the `wp-config.php`: ```php define( 'WP_CACHE_KEY_SALT', '...long random string...' ); ``` This helps prevent cache pollution when multiplte WordPress installs are using the same Memcached server. The value must be unique for each WordPress install. == Frequently Asked Questions == = How can I manually specify the memcached server(s)? = Add something similar to the following to wp-config.php above `/* That's all, stop editing! Happy blogging. */`: ` $memcached_servers = array( 'default' => array( '10.10.10.20:11211', '10.10.10.30:11211' ) ); ` The top level array keys, are cache groups, where 'default' corresponds to any cache group that is not explicitly defined. This allows for specifying memcached servers that only handle certain cache groups. The most common use is only specifying 'default'. Possible cache groups are: ` {$taxonomy}_relationships {$meta_type}_meta {$taxonomy}_relationships blog-details blog-id-cache blog-lookup bookmark calendar category comment counts general global-posts options plugins post_ancestors post_meta posts rss site-lookup site-options site-transient terms themes timeinfo transient user_meta useremail userlogins usermeta users userslugs widget ` == Changelog == = 4.0.0 = * Add preemptive filter pre_wp_cache_get * Add flush_number replication to prevent accidental flush due to flush_number eviction, server rotation, etc. = 3.2.2 = * Remove filter, and base key stripping on presence of `key_salt` = 3.2.1 = * Fix bug allowing **slow-ops** entries to have the same key, so toggling doesn't work = 3.2.0 = * Better stats(). Now shows cache group/individual calls with size of the payload and timings. * PHP 5.6.20 is now required * Fix **get_multi** to show per group calls * Added filter **(memcached_strip_keys)** to bypass memcached key stripping * Special group for **slow-ops** ( > 5ms ) with backtrace = 3.1.0 = * Add **wp_cache_get_multi** * Add support for the **$found** parameter * Set a variable for $max_expiration to 30 days * Code style changes * Different coloring for unknown stats group * Store host/port on failure_callback * Default stats counts = 3.0.2 = * Better output of HTML = 3.0.1 = * Fix key generation error in switch_to_blog() = 3.0.0 = * Flush site cache by rotating keys * Flush global cache when flushing main site = 2.0.6 = * Flush the local cache on wp_cache_flush() = 2.0.5 = * Fix missing global in switch_to_blog = 2.0.4 = * Remove deprecated constructor = 2.0.3 = * Support for unix sockets = 2.0.2 = * Break references by cloning objects * Keep local cache in sync with memcached when using incr and decr * Handle limited environments where is_multisite() is not defined * Fix setting and getting 0 * PHP 5.2.4 is now required * Use the WP_CACHE_KEY_SALT constant if available to guarantee uniqueness of keys
Various systems reset the stats array to an empty array, which deletes all of the keys, such as 'get'
and 'add'
. Common examples include:
flush_cache
method: https://github.com/WordPress/wordpress-develop/blob/master/tests/phpunit/includes/abstract-testcase.php#L343wp_clear_object_cache
method: https://github.com/wp-cli/wp-cli/blob/5dc1c5835dcf532dd8530b83c32a2e249211df94/php/utils-wp.php#L300This was recently fixed in the VIP WP CLI helper: Automattic/vip-go-mu-plugins@515b71d
Since the property is public and we can't control for every use case, one thing we can do is to ensure that the increments are happening safely, rather than assuming the property exists, as is done here: https://github.com/Automattic/wp-memcached/blob/master/object-cache.php#L319
It's useful debugging data that tracks how long each operation takes.
Since they are very different operations.
SETs are currently not tracking stats in the way other operations are.
Have you had any reports of data loss concerning widgets? We have had two sites in quick succession report issues where sections of widgets under Appearance->Widgets have been apparently deleted. I can confirm this was not user error. We have deactivated Memcache as a precaution.
We are on the latest version 4.0.0 and Wordpress 5.8.1. We also run HyperDB v1.7.
Hello,
We used wp memcached successfully on a customer website, but recently we had to disable it because a specific plugin did not work correctly, more info here (french) : https://wordpress.org/support/topic/le-paiement-oney-ne-fonctionne-plus/
The specific plugin relies on transients and apparently when we enable object caching transients are not reliable anymore.
The plugin author recommended us to switch to WP Rocket (sic) in which there is an option not to cleanup transients in database, which apparently fixes the problem.
Does anybody knows if there is such a possibility for wp memcached ? Or maybe we could add some filters to exclude this plugin from object cache ?
Thank you for your help :)
Mathieu.
Hey I'd like to fork this for my own needs but would feel better if there was a license attached. I was surprised to find code in Automattic/ without one.
I am assuming GPL2 since it's derived-ish(?) from core wordpress but I'd love a clarification.
Hi,
I have noticed some deprecations in PHP 8.2. Will the object cache class be updated soon to be compatible with PHP 8.2?
Best regards,
Himanshu
It works OK when I configure Memcached to use a TCP connection (listening on 127.0.0.1 on port 11211), but it doesn't work when I configure Memcached to use unix sockets, which would allow higher speeds, although 'object-cache.php' supports unix sockets.
To make Memcached use a unix socket instead of a TCP connection, in the /etc/memcached.conf
file, I commented out the port and IP address lines and added the socket and permissions lines, like this:
#-p 11211
#-l 127.0.0.1
-s /var/run/memcached/memcached.sock
-a 775
Also, I added the following lines to the wp-config.php
file of the WordPress website:
$memcached_servers = array( 'default' => array(
'unix://var/run/memcached/memcached.sock')
);
I restarted Memcached and indeed, memcached.sock
was created in the '/var/run/memcached
directory which was owned by the memcache
user, but all the webpages became very slow. They loaded, but very slowly. When I returned to TCP connections it worked again and I could see that Memcached stored data in RAM. I experimented with different permissions for the socket file, so as to give www-data
read access to it, but in vain.
What can be wrong ?
I'm using Debian 10, Nginx 1.14.2, WordPress 5.4.2.
In 47938 the wp_cache_get_multiple
function was implemented. This drop-in should also implement this function.
Hello
The installation instructions are a bit confusing.
I've copied object-cache.php
under /wp-content/object-cache.php
and nothing happens. There's no indication of the cache working anywhere in the WP admin, site load speed has not changed.
If I try copying the file under /wp-content/plugins/memcached/object-cache.php
it shows up as a plugin on the WP Plugins section but can't turn it on as it can't redeclare wp_cache_add()
Memcached is installed and running properly, stats show some bytes written/read so maybe it's actually working? Can't know for sure without browsing through the cache...
Also I run WPMU, does that make any difference?
Cheers!
Hi, we have been using your memcached plugin for what is probably years now but in the past couple of weeks we have noticed the cache clearance isn't working as usual. Usually WP Admin changes take effect immediately but in some cases (almost randomly) changes do not take effect without a delay. Is there any known issue we should be aware of?
Hi, how to exclude wp-admin from memcached? because after did something on wp-admin (such as edit post, or upload image) the content won't change
WordPress 6.1 will add the new function wp_cache_flush_group()
, see https://core.trac.wordpress.org/ticket/4476:
Currently, you have to specify the id of the cached item in order to delete it via wp_cache_delete, or you have to flush the entire cache via wp_cache_flush.
Instead, it would be helpful if one were able to delete an entire group without having to flush all of the cache[s].
Please consider utilizing that function in the Memcached drop-in (https://github.com/Automattic/vip-go-mu-plugins/blob/develop/drop-ins/object-cache/object-cache-next.php).
Currently, wp_cache_flush_group()
is not used in the drop-in.
It certainly would be necessary to wrap the function call with an if ( function_exists( 'wp_cache_flush_group' ) )
check.
It can occur during a lot of situation:
wp-cli
fails): I guess it's shouldn't even load if PHP_SAPI === 'cli'
In all these and others cases, the extensions should definitely NOT trigger a fatal error.
While wp_cache_get_multi()
isn't part of Core's object cache API, this plugin's $wp_object_cache
class provides the get_multi()
method, which WordPress.com's version wraps in wp_cache_get_multi()
. Other drop-ins, such as for Redis and Memcached, provide this function, and Core is considering adding it: https://core.trac.wordpress.org/ticket/20875.
I have tried both the "official" version of this listed on the WP Plugins "memcached", as well as just trying the version from this repo, which is slightly different.
Memcached server & PECL memcache extension are both installed and working. And both versions of the plugin work fine.
...Except that they both cause a fatal error whenever I try to use wp cli to do anything. And because they are drop ins rather than "regular" plugins, --skip-plugins does not work.
Have also tried the Use Memcached plugin, which is a "standard" WP plugin. It also breaks wp cli, but responds to --skip-plugins=use-memcached. However that plugin breaks the rest of my site (which is being used as a headless backend to JS framework frontend, so specifically seems to be breaking the REST API & WPGraphQL...but I digress).
With this particular version (of object-cache.php from this repo), the wp cli error is:
Fatal error: Uncaught Error: Class 'Memcache' not found
...on line 1073
The full message is attached as image here:
...since wp cli in critical to our workflow, and flushing the cache from the cli an often used function, renaming object-cache.php to object-cache.php.OFF is not a particularly good work around.
Am suspecting the bug may be with wp cli, so reporting the issue there too.
Thanks much,
Morgan
🙏
Hello,
I have 2 questions:
Asking because in the plugin repo we see:
This plugin hasn’t been tested with the latest 3 major releases of WordPress. It may no longer be maintained or supported and may have compatibility issues when used with more recent versions of WordPress.
When using the object-cache.php drop-in with multiple sites, users will see unexpected behaviour (such as being redirected to site A when they attempt to load site B).
To avoid this, one must define WP_CACHE_KEY_SALT
in wp-config.php
.
It would be very helpful to put this in the README.
Introduced in WordPress/wordpress-develop@832b6c3.
Due to how this drop-in caches data internally, $found
will become true
after the first GET, even if it doesn't exist in Memcache.
This is at best confusing, and at worst causes code to think the value in memcache is false
, when it doesn't actually exist.
wp> $found = null;
wp> wp_cache_get( 'foo', null, false, $found );
bool(false)
wp> $found;
bool(false)
wp> wp_cache_get( 'foo', null, false, $found );
bool(false)
wp> $found;
bool(true)
Implement new functions, wp_cache_add_multiple, wp_cache_set_multiple and wp_cache_delete_multiple functions.
$to_get
seems never defined and generating Undefined variable: to_get
notices. Is that dead code?
Lines 332 to 336 in f19d6b0
To reproduce the notices, use wp-memcached with advanced-post-cache.
NOTICE: wp-content/object-cache.php:348 - Undefined index: set
wp_dashboard_setup, wp_check_browser_version, set_site_transient, wp_cache_set, WP_Object_Cache->set
NOTICE: wp-content/object-cache.php:188 - Undefined index: delete
wp_dashboard, do_meta_boxes, call_user_func, wp_dashboard_quick_press, get_default_post_to_edit, wp_insert_post, wp_set_post_categories, wp_set_post_terms, wp_set_object_terms, wp_cache_delete, WP_Object_Cache->delete
On the back of #40 & #43 that changed the behaviour of the $found
parameter to reflect the status of the data in memcache, however, it breaks a different-but-similar case: non-persistent groups.
For example:
wp> wp_cache_add_non_persistent_groups( [ 'example' ] );
NULL
wp> wp_cache_set( 'example', 'example', 'example' );
bool(true)
wp> wp_cache_get( 'example', 'example', false, $found );
string(7) "example"
wp> $found
bool(false)
In this case, the value was never going to exist within memcache and it was found in the cache, so I would argue that $found
should be true in this case.
I personally ran into this with Cavalcade, where it relies upon the $found
parameter working with non-persistent groups: https://github.com/humanmade/Cavalcade/blob/master/inc/class-job.php#L366-L368
A bit of an edge case now, but intval( microtime( true ) * 1e6 )
in rotate_site_keys()
and rotate_global_keys()
can overflow in 32-bit integers and the memcached daemon throws errors if the Memcache::increment
method is called on a negative value.
Checking for PHP_INT_SIZE == 4
and just using time()
instead of microtime()
is a quick fix.
Per https://core.trac.wordpress.org/ticket/4476
This would require adding an additional flush group on a per-cache-group basis.
Falling back to wp_cache_flush()
would cause issues if a plugin on the main site attempted to flush a specific cache group, as it'd rotate every cache.
Test all the things.
We found with the latest WordPress v6.5 update that when updating core, it is not just necessary to rename or delete object-cache.php
but also to then flush the cache before re-enabling object-cache.php
.
If this doesn't happen, when you try to access the dashboard, the site tries to update the WordPress database but displays a notice to say it's already been updated and directs the user to the home page rather than the dashboard preventing access to the dashboard until object-cache.php
has been disabled or the cache has been flushed.
Is there a way to automatically disable object-cache.php
when a core update is in progress then flush the cache and re-enable object-cache.php
when the update is successful?
I feel like this may also be required when performing plugin updates or even theme updates?
This issue probably presented on previous core updates but we're new to Memcached.
Oliver
Hello,
Our company currently use page caching with WP Super Cache which is really great :)
Since WordPress 6.1 there is a "object cache" health warning in WordPress.
Besides, some of our customers use heavy (bought) themes/templates with N+1 queries, many loops, etc. making some pages load slowly when not cached (sometimes more than 2 seconds with repeated SQL queries).
Could we just install wp-memcached to improve this ? Will it work with WP Super Cache ? Or is it better to use a single plugin (maybe BatCache or W3 Total Cache) ?
Moreover, we use nginx_mod_pagespeed to optimize JS/CSS/HTML, but this module has been abandoned by the Apache foundation so we will soon have to remove it. Maybe W3 Total Cache would cover it all ? Or is there a better solution ?
Thank you for your great plugins and for your help :)
Mathieu.
Hello,
Thank you for this module, it rocks :)
Is it possible to disable the cache object on a specific website in a wordpress network ? Is there any constant and/or filter we could use ?
As I could not find it I added a filter in the object-cache.php but I'm not sure if it's required and/or in the right place :
function wp_cache_set( $key, $data, $group = '', $expire = 0 ) {
global $wp_object_cache;
if ( defined( 'WP_INSTALLING' ) == false && apply_filters( 'ircf_wp_cache_disabled', false ) == false) {
return $wp_object_cache->set( $key, $data, $group, $expire );
} else {
return $wp_object_cache->delete( $key, $group );
}
}
Thank you very much :)
Mathieu.
According to the WordPress docs, wp_cache_flush()
should return true
on success or false
on failure, but it is always returning null
through the flush()
class function.
This object cache is distributed on https://wordpress.org/plugins/memcached/ as a plugin, but can't actually be used as one. The installation instructions do suggest it requires extra configutaration, but since most plugins only have junk there, no-one looks at it.
Due to the number of end-users who attempt to install it (See the support threads), only to be met with a fatal error, we should disable the plugin activation aspect of the plugin and present a useful error message to the end-user, rather than simply showing a fatal error.
I'm not sure of the best method to achieve this, but if it's going to be on WordPress.org/plugins it would be great to remove that "limitation".
Hi,
Just wondering, would it be possible to get a new release out, there's a lot of servers out there writing deprecation notes to the error logs.
The plugin is awesome, thanks for maintaining it!
Best regards,
Ed
Memcache has a key length limit of 250 characters. Problems can arise if a cache key greater than this is used. It seems memcache truncates the key so it is very possible to have collisions and unexpected behavior. Other object caches can handle very large keys so this object cache should check if a key is too long and hash it with md5 or similar to prevent problems.
Hi,
We have a cron event that when run can occasionally take some time to complete, especially if previous instances have failed as there is more to do.
The site in question runs perfectly in all other aspects with object-cache.php installed however, we have since discovered that we see the following errors in debug.log ...
[19-Mar-2024 16:49:06 UTC] PHP Fatal error: Maximum execution time of 30 seconds exceeded in /wp-content/object-cache.php on line 790
[19-Mar-2024 16:49:06 UTC] E_ERROR: Maximum execution time of 30 seconds exceeded in /wp-content/object-cache.php on line 790
[19-Mar-2024 16:52:56 UTC] PHP Fatal error: Maximum execution time of 30 seconds exceeded in /wp-content/object-cache.php on line 790
[19-Mar-2024 16:52:56 UTC] E_ERROR: Maximum execution time of 30 seconds exceeded in /wp-content/object-cache.php on line 790
[19-Mar-2024 16:53:29 UTC] PHP Fatal error: Maximum execution time of 30 seconds exceeded in /wp-content/object-cache.php on line 790
[19-Mar-2024 16:53:29 UTC] E_ERROR: Maximum execution time of 30 seconds exceeded in /wp-content/object-cache.php on line 790
When object-cache.php is deleted the issue no longer presents itself.
Why would having the object-cache.php installed introduce a PHP execution time limit?
Please advise.
Many thanks,
Oliver
In get_multi()
, we have:
if ( $to_get ) {
$vals = $mc->get_multi( $to_get );
The variable $to_get doesn't exist anywhere else in the code.
This is causing an Undefined variable: to_get
warning to appear.
Plugin not activated due to Fatal error: Cannot redeclare wp_cache_add().
It should be a way to avoid this issue when installing the plugin from the wordpress repo https://fr.wordpress.org/plugins/memcached/
Even if you instruct in your REAMDE to install memcached the object-cache is using memcache (without d) extension.
I think it can be renamed as wp-memcache in order to distinguish with for instance https://github.com/joomlaworks/wp-memcached-object-cache which is using memcached
Would be nice to see the past versions tags here on github ;)
The correct implementation has a $found
reference param, because your cache should allow any possible return value. Otherwise you'll never be able to cache false values.
function wp_cache_get( $key, $group = '', $force = false, &$found = null )
Hi everyone,
maybe a silly question here: but why don't use Memcached
(with the d) in this implementation? It seems that in php7.0 memcached is preferred (or am I wrong?)
I recently encountered pathological behaviour when Memcache writes succeed but reads fail.
As a summary of what the conditions/behaviour of wp-memcached v4.0.0 and a single key:
add
succeeds and the key is written to both the local cache and memcache.get
: initially the local cache lookup fails, the memcache lookup fails†, but memcache add
also fails down the ([mc already]
) path because the existing cache value is detected. This path does not write to the local cache: Lines 189 to 193 in 92ed289
add
again). For keys like alloptions
, this means hundreds of SQL queries.† why does the memcache lookup fail after a successful add
? Well, in my case it was because wp-memcached and Google's Memcache API had different assumptions about memcache flag support (I've raised a bug with Google). But there are other realistic scenarios, such as memcache being unavailable (e.g. failing all get
operations) or memcache servers that only provide eventual consistency.
I understand that the existing behaviour is intentional: by not setting the local cache when the write fails, we would normally expect the next call to get
to succeed in a memcache lookup and then populate the local cache. But admins add the Memcached Object Cache in order to improve performance and reliability, so if the memcached starts failing reads, the performance degradation and SQL server load will actually be much worse than the default WordPress behaviour with a local object cache (which limits key lookups to once per request). The downside seems to be that the add
is only going to get retried once per request (rather than once per lookup), which seems like an acceptable trade-off to me.
If the maintainers agree, I can send a PR. Also open to some class option similar to default_expiration
that could be set in one place to opt in to my proposed local caching behaviour.
Is there any way to include object-cache.php file in repository and disable it in development environment with a constant or something?
WP 6.0 introduced wp_cache_flush_runtime()
. As of WordPress/wordpress-develop@c204a6a, the method is called in WP's unit test framework, triggering this error:
Unexpected incorrect usage notice for wp_cache_flush_runtime.
Your object cache implementation does not support flushing the in-memory runtime cache. (This message was added in version 6.1.0.)
There are two default
groups in this list - in the 2nd and 6th positions.
When clicking the one in the 6th position, then the list for the one in the 2nd position appear in the panel below this list i.e. I can't access details of the requests that had 163 bytes.
There appears to be a couple of instances (1, 2) where a missing group name gets set as default
, and it's the group name that is used for the toggle.
Prior to 3.2.0 we limited the number of ops shown to 500. I believe it would still be good to have a soft limit like this. When debugging sites with caching issues, that are doing tens or hundreds of thousands of ops per transaction, this can cause the browser to lock up trying to load and parse all of the data.
Now, it's obvious that the site is _doing_it_wrong()
but having the ability to use Debug Bar to help debug the issue and related issues would be really helpful.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.