Laravel multiple memcached: failover does not work - php

I have two memcached servers. I set up the following config and my expectation was that my PHP app can use alive memcached even if one of the two servers is down. But it did not work. I got "No Memcached servers added" error when I execute memcached's get() method.
'memcached' => [
'driver' => 'memcached',
'options' => [
Memcached::OPT_CONNECT_TIMEOUT => 10,
Memcached::OPT_DISTRIBUTION => Memcached::DISTRIBUTION_CONSISTENT,
Memcached::OPT_SERVER_FAILURE_LIMIT => 2,
Memcached::OPT_REMOVE_FAILED_SERVERS => true,
Memcached::OPT_RETRY_TIMEOUT => 1,
],
'servers' => [
[
'host' => 'xxx.0.0.1', 'port' => 11211, 'weight' => 100,
],
[
'host' => 'xxx.0.0.2', 'port' => 11211, 'weight' => 100,
],
],
],
I'm using the latest version of memcached servers and client.
memcached 1.4.25-2ubuntu1
php-memcached version 3.0.0b1
libmemcached version 1.0.18
Do you have any ideas?
Edit 1
"No Memcached servers added" error is came from here.
https://github.com/illuminate/cache/blob/master/MemcachedConnector.php
Edit 2
I found Memcached::XXX options are integer values. So options values are not passed to the server. I fixed this but the result was not changed.
'options' => array('10', '1', '2', true, '1')
Edit 3
Laravel's cache example setting is memtioned here
https://github.com/laravel/laravel/blob/master/config/cache.php#L60
Edit 4
I tried it by using PHP without Laravel then I figured out that getVersion() returned null when one of the two server is dead.
<?php
$m = new Memcached();
$m->addServer('127.0.0.1', 11211);
$m->addServer('127.0.0.1', 11212);
$status = $m->getVersion();
if ($status == null){
echo "null";
} else {
echo "not null";
}
* when both the two servers are alive
// not null
// $status = array('127.0.0.1:11211' => '1.4.25', '127.0.0.1:11212' => '1.4.14')
* when one of the two server is dead
// null
// $status = null

I was struggling with this for a couple of days now and I finally found a solution for it https://packagist.org/packages/fingo/laravel-cache-fallback
It is quite easy to install:
composer require fingo/laravel-cache-fallback
Add the provider Fingo\LaravelCacheFallback\CacheFallbackServiceProvider::class into 'config/app.php`
Default fallback order is: redis, memcached, database, cookie, file, array.If needed to change fallback order, publish vendors: php artisan vendor:publish --provider="Fingo\LaravelCacheFallback\CacheFallbackServiceProvider"
I'm using Laravel 5.2 with PhP7, the requirements for the library are:php: ~5.6|~7.0, illuminate/cache: ~5.1
LE: I've implemented a different way to failover from one Memcached server to the other one and if both of them are down then it will failover to the 'file' driver.
config/cache.php:
'memcached' => [
'driver' => 'memcached',
// To use the options we need to install the PHP driver: sudo yum install php-memcached
'options' => [
Memcached::OPT_CONNECT_TIMEOUT => 3,
Memcached::OPT_DISTRIBUTION => Memcached::DISTRIBUTION_CONSISTENT,
Memcached::OPT_SERVER_FAILURE_LIMIT => 2,
Memcached::OPT_REMOVE_FAILED_SERVERS => true,
Memcached::OPT_RETRY_TIMEOUT => 1,
],
'servers' => [
[
'host' => 'xxx.xxx.xxx.xxx',
'port' => 11211,
'weight' => 90,
],
]
],
'memcached249' => [
'driver' => 'memcached',
// To use the options we need to install the PHP driver: sudo yum install php-memcached
'options' => [
Memcached::OPT_CONNECT_TIMEOUT => 3,
Memcached::OPT_DISTRIBUTION => Memcached::DISTRIBUTION_CONSISTENT,
Memcached::OPT_SERVER_FAILURE_LIMIT => 2,
Memcached::OPT_REMOVE_FAILED_SERVERS => true,
Memcached::OPT_RETRY_TIMEOUT => 1,
],
'servers' => [
[
'host' => 'xxx.xxx.xxx.xxx',
'port' => 11211,
'weight' => 100,
],
]
],
config/cache_fallback.php
return [
'fallback_order' => [
'memcached',
'memcached249',
'file',
]
];
The only problem is that if the first memcached server is down, it slows down the entire system (but at least it's not breaking the main server). Hope this helps :)

Related

How works findOneAndUpdate in php with mongodb in concurence case (concurrency control)

I used mongodb db.version() 5.0.9 with PHP 7.4.30
I worked with queue based on mongo db and in architecure present possibility to scaling, so could be several workers. My question - how I can protect my record from the concurence query, when two workers try to execute findOneAndUpdate in the same time ? Or maybe findOneAndUpdate has this opportunity by default ?
$document = $this->collection->findOneAndUpdate(
[
'$and' => [
[
'job_type' => 'metrics'
],
$conditionDelivered,
[
'id.pub_key_digest' => [
'$exists' => true
]
],
[
'timestamp' => [
'$gt' => $timestampOffset
]
],
],
],
[
'$set' => $setSection,
],
[
'sort' => [
'timestamp' => 1,
],
'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER
]
);
$filter
{"$and":[{"job_type":"metrics"},{"alert_delivered_at":{"$exists":false},"timescale_delivered_at":{"$exists":false}},{"id.pub_key_digest":{"$exists":true}},{"timestamp":{"$gt":1291852800000000000}}]}
$update
{"$set":{"alert_consumer_id":"consumer_62b2d4e4520339.76461865","alert_delivered_at":{"$date":{"$numberLong":"1655887076643"}},"timescale_delivered_at":{"$date":{"$numberLong":"1655887076643"}}}}
and $options
{"sort":{"timestamp":1},"writeConcern":{"w":"majority"},"returnDocument":2}
Could you explain please best way for find and update data with guarantee which will be executed by only one worker, some lock, the other workers will be work with another records ?

Rollbar is not seen by Laravel 8.0

I have installed the Rollbar 7.0 into Laravel 8.0. PHP version is 7.4
I am trying to send a test exception message using a simple Console command but that sends me nothing.
My configs are the following:
config/app.php:
return [
'providers' => [
Rollbar\Laravel\RollbarServiceProvider::class
...
]
config/logging.php:
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['other', 'rollbar'],
'ignore_exceptions' => false,
],
'rollbar' => [
'driver' => 'monolog',
'handler' => MonologHandler::class,
'access_token' => env('ROLLBAR_TOKEN'),
'level' => env('ROLLBAR_LEVEL'),
'enabled' => true,
'environment' => env('ROLLBAR_ENVIRONMENT'),
]
....
config/services.php (but seems to be that it doesn't work)
'rollbar' => [
'access_token' => env('ROLLBAR_TOKEN'),
'environment' => env('ROLLBAR_ENVIRONMENT'),
'level' => env('ROLLBAR_LEVEL')
],
app.env:
ROLLBAR_TOKEN=real_token
ROLLBAR_LEVEL=debug
ROLLBAR_ENVIRONMENT=backend_test
And the console command itself has the following view:
public function handle()
{
// Rollbar::init([
// 'driver' => 'monolog',
// 'handler' => MonologHandler::class,
// 'access_token' => env('ROLLBAR_TOKEN'),
// 'level' => env('ROLLBAR_LEVEL'),
// 'enabled' => true,
// 'environment' => env('ROLLBAR_ENVIRONMENT'),
// ]);
try{
$x = 4/0;
} catch(\Exception $exception) {
Rollbar::error('caught demo exception', ["details" => $exception->getMessage()]));
Rollbar::flush();
exit(1);
}
}
So when it is like this, the rollbar stays silent. But if I uncomment the initialisation, that works well, sending a debug message to the rollbar.
That doesn't work all over the project too.
Could you please advice me, what could I do here in order to make it work globally with initialising in every file?
upd: I've also cleared config cache and tried to make a rollbar as a default
Laravel in app/logging.php has a default channel configuration. Normally "default" should mean that there are some other working channel too but here, somehow it the meaning is like "the only used channel". Or I just do not fully understand how should it work. So my rollbar channel seems to be overriden by the another "default" one, that is why the system doesn't use it. So the solution is to switch the default channel:
'default' => env('LOG_CHANNEL', 'stack'),
when the rollbar is included to stack channel or just
'default' => env('LOG_CHANNEL', 'rollbar'),
when it is not.

Laravel 6 Horizon Slow - long wait time

I am using https://laravel.com/docs/6.x/horizon to manage the queue on my application (using redis backend).
The jobs on the queue are ephemeral - each queued job is supposed to make an api call (to a third party) and write the response to db.
Today I noticed lots of jobs are stuck / processing very slowly:
I am running 10 queue workers with sufficient memory on the host node. This is my config/horizon.php
return [
'domain' => null,
'path' => 'horizon',
'use' => 'default',
'prefix' => env('HORIZON_PREFIX', 'horizon:'),
'middleware' => ['web', 'basic.api.credential.auth'],
'waits' => [
'redis:default' => 60,
],
'trim' => [
'recent' => 60,
'completed' => 60,
'recent_failed' => 40320,
'failed' => 40320,
'monitored' => 40320,
],
'fast_termination' => false,
'memory_limit' => 512,
'environments' => [
'production' => [
'queue-1' => [
'connection' => 'redis',
'queue' => ['default'],
'balance' => 'simple',
'processes' => 10,
'tries' => 2,
'timeout' => 1800, // 30 Minutes
'memory' => 512,
],
],
// ...
],
];
I checked the remote api server to see if the bottleneck is there, but it's responding quite fast (less than 1 sec per api call). Checking the server, I can't see any load on it and the overall memory/cpu utilisation is quite low.
Laravel v6.18.37
PHP v7.3.21
Horizon v3.7.2
Any ideas what's causing such a huge slowdown? How do I debug this to find out what's going on?
I even tried restarting the server and it did not help. I am not seeing any timeouts / errors in the logs either.
The problem turned out to be on the database, a few table that we use for lookup was not properly optimised - after adding indexes, the speed improved tremendously.
Sorry false alarm.

EAuth Extension Yii2, Class nodge\eauth\EAuth does not exist

I am trying to use EAuth extension in Yii2 advanced application. I installed it through composer and it installed it under vendor directory and configured as mentioned here (did the config in common/config/main). So, following is the directory structure for that:
root
vendor
nodege
lightopenid
provider
*files go here*
yii2-eauth
src
*files go here*
EAuth.php is under src folder. In controller I have done this in use:
use nodge\eauth\EAuth;
and when I do this:
$eauth = Yii::$app->get('eauth')->getIdentity($serviceName);
I get the following error:
Class nodge\eauth\EAuth does not exist
What am I doing wrong? Any help?
Update:
This is my config:
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
],
'eauth' => [
'class' => 'nodge\eauth\EAuth',
'popup' => true, // Use the popup window instead of redirecting.
'cache' => false, // Cache component name or false to disable cache. Defaults to 'cache' on production environments.
'cacheExpire' => 0, // Cache lifetime. Defaults to 0 - means unlimited.
'httpClient' => [
// uncomment this to use streams in safe_mode
//'useStreamsFallback' => true,
],
'services' => [// You can change the providers and their classes.
'google' => [
// register your app here: https://code.google.com/apis/console/
'class' => 'nodge\eauth\services\GoogleOAuth2Service',
'clientId' => '...',
'clientSecret' => '...',
'title' => 'Google',
],
'facebook' => [
// register your app here: https://developers.facebook.com/apps/
'class' => 'nodge\eauth\services\FacebookOAuth2Service',
'clientId' => '---',
'clientSecret' => '---',
],
'yahoo' => [
'class' => 'nodge\eauth\services\YahooOpenIDService',
//'realm' => '*.example.org', // your domain, can be with wildcard to authenticate on subdomains.
],
],
],
],

How to configure cakephp to use memcached

I'm trying to use an external cache engine, memcached, to power my CakePHP app.
I have an AWS EC2 instance running the app and also an AWS ElastiCache Cluster with one node using memcached. The memcache and memcached php modules are also installed and enabled.
The configuration in the app.php file is as follows:
'Cache' => [
'default' => [
'className' => 'File',
'path' => CACHE,
],
'elastic' => [
'className' => 'Cake\Cache\Engine\MemcachedEngine',
'compress' => false,
'duration' => '+2 minutes',
'groups' => [],
'host' => 'yyy.euw1.cache.amazonaws.com:11211',
'username' => null,
'password' => null,
'persistent' => false,
'prefix' => 'cake_',
'probability' => 100,
'serialize' => 'php',
'servers' => ['yyy.euw1.cache.amazonaws.com:11211'],
'options' => [],
'lock' => true
]
To select whether or not to query the database, this condition is used:
if (($car = Cache::read('car', 'elastic')) === false) {
$car = $this->Cars->get();
Cache::write('car', $car, 'elastic');
}
Unfortunately, after a long page load I get this error:
"elastic cache was unable to write to DebugKit\Cache\Engine\DebugEngine cache"
Does anyone knows the origin of this error? Can someone guide me through the configuration of memcached for cakephp, using an external cache engine?
Thank you upfront!
Thank you for your reply.
This issue is now closed. We had to allow IP access between EC2 and CloudCache Cluster.

Categories