Laravel 8: Memcache and Memcached

dakata__92

Super Moderator
Открих, че имам проблеми с кеширането под драйвър memcached. Изобщо не се запазват нещата и на практика нямам кеширане, но и никаква грешка не ми излиза никъде. Временно смених кеширането да е във файлове и си работи нормално, но се чудех защо нещата под memcached не вървят. Имам инсталирани на сървъра Memcache и Memcached.

config/cache.php
Код:
        'memcached' => [
            'driver' => 'memcached',
            'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
            'sasl' => [
                env('MEMCACHED_USERNAME'),
                env('MEMCACHED_PASSWORD'),
            ],
            'options' => [
                // Memcached::OPT_CONNECT_TIMEOUT => 2000,
            ],
            'servers' => [
                [
                    'host' => env('MEMCACHED_HOST', '127.0.0.1'),
                    'port' => env('MEMCACHED_PORT', 11211),
                    'weight' => 100,
                ],
            ],
        ],

Забелязах, че на сървъра за memcache е настроен default_port - 11211.
Тъй като Laravel използва другата библиотека memcached се чудех дали проблема е в настройките на работната рамка? Можете ли да ми дадете насоки, как да реша проблема?

Memcache:

Memcached:
 
Подадох в env и MEMCACHED_PERSISTENT_ID=test_slug заедно с CACHE_DRIVER=memcached, но отново не сработи този драйвър. За жалост работя с по-бавният вариант под файлове, но това ме дразни и не мога да разбера защо не работи.

Ако тествам кода по този начин в някой модел, то няма проблем и сработва, а през ларавел не желае....
Код:
        $m = new Memcached();
        $m->addServer('127.0.0.1', 11211);
        if ($m->get('key') != 'test') {
            $m->set('key', 'test');
        }
        dd($m->get('key'));

Ползвам cache()->remember();
 
Не за грешки. Проследи ли с дебъгера какво се случва. Също пробва ли с фасадата

Код:
Cache::remember()
вместо с хелпъра.

Други cache драйвъри имаш ли в config-а.
Пробвай да зададеш конкретен store

Код:
Cache::store('memcached')->remember()

Най-лесно е да тръгнеш стъпка по стъпка с дебъгера и да видиш дали имаш правилните стойности до извикването на Memcached.
 
Revelation каза:
Не за грешки. Проследи ли с дебъгера какво се случва. Също пробва ли с фасадата

Код:
Cache::remember()
вместо с хелпъра.

Други cache драйвъри имаш ли в config-а.
Пробвай да зададеш конкретен store

Код:
Cache::store('memcached')->remember()

Най-лесно е да тръгнеш стъпка по стъпка с дебъгера и да видиш дали имаш правилните стойности до извикването на Memcached.

Не съм пробвал с фасадата, но ще тествам днес. Ще подам и store освен от конфигурацията, но не мисля, че това ще реши казуса. Конфигурацията е наред и нямам нищо друго в нея.
 
Явно не си фен на xdebug.

Ларавел регистрира описаните в конфигурацията сървъри, само ако няма нищо в pool-а. Ако Memcached има нещо регистрирано, то ще използва него, но това не го прави правилния избор. Можеш да видиш с твоя тест като извикаш getServerList() метода на Memcached. Ако няма нищо, тогава Ларавел си регистрира сървърите описани в твоя конфиг файл и означава, че проблема идва от другаде.

Имаш ли MEMCACHED_USERNAME и MEMCACHED_PASSWORD сетнати? Според твоя тест не ти трябват. Ларавел за да използва sasl масива в конфигурацията трябва да съдържа 2 стойности. Не е описано как Memcached приема null-еви стойности, но бих ти предложил да ги закоментираш или махнеш от масива в конфигурационния файл, така Ларавел няма да се опитва да сетва credentials, понеже дори и да са null стойности count([null, null]) също връща 2.

Другото, което е - в твоя тест не използваш persistent id параметъра, но подаваш такъв на Ларавел. За всеки persistent id се създава различна инстанция и съответно getServerList() ще върне различни резултати, което ще рече, че теста ти не е много коректен.

Още нещо, което можеш да провериш е дали стойностите от env файла реално се сетват.
 
Днес има доста работа по системата. Ако не успея то утре ще изтествам твоите предложения и ще върна отговор. Благодаря за предложенията :!:
 
Revelation каза:
Явно не си фен на xdebug.

Ларавел регистрира описаните в конфигурацията сървъри, само ако няма нищо в pool-а. Ако Memcached има нещо регистрирано, то ще използва него, но това не го прави правилния избор. Можеш да видиш с твоя тест като извикаш getServerList() метода на Memcached. Ако няма нищо, тогава Ларавел си регистрира сървърите описани в твоя конфиг файл и означава, че проблема идва от другаде.

Имаш ли MEMCACHED_USERNAME и MEMCACHED_PASSWORD сетнати? Според твоя тест не ти трябват. Ларавел за да използва sasl масива в конфигурацията трябва да съдържа 2 стойности. Не е описано как Memcached приема null-еви стойности, но бих ти предложил да ги закоментираш или махнеш от масива в конфигурационния файл, така Ларавел няма да се опитва да сетва credentials, понеже дори и да са null стойности count([null, null]) също връща 2.

Другото, което е - в твоя тест не използваш persistent id параметъра, но подаваш такъв на Ларавел. За всеки persistent id се създава различна инстанция и съответно getServerList() ще върне различни резултати, което ще рече, че теста ти не е много коректен.

Още нещо, което можеш да провериш е дали стойностите от env файла реално се сетват.
Пробвах всичко, което си споменал:
use Illuminate\Support\Facades\Cache;
Код:
        Cache::put('key', 'test', 5);
        if ( Cache::has('key')) {
            dd(Cache::get('key'));
        }
        dd('not cache');
Код:
        Cache::store('memcached')->put('key', 'test', 5);
        if ( Cache::store('memcached')->has('key')) {
            dd(Cache::store('memcached')->get('key'));
        }
        dd('not cache');
еnv - то се сетва и настройките са коректни. Коментирах sassl същата работа. Потърсих вариант да видя как мога да взема инстанцията, на Memcached създадена от Ларавел за да мога дирекно да попитам за getServerList, но не успях да се ориентирам нещо. Както и да е изглежда всичко ми е наред по конфигурацията и настройките на сървъра, а кеширане няма. Ако е на файлове всичко е коректно.

Memcached извикан директно работи:
Код:
        $m = new Memcached();
        $m->addServer('127.0.0.1', 11211);
        dump($m->getServerList());
        if ($m->get('key')) {
            dd($m->get('key'));
        }
        $m->set('key', 'test', 5);

        dd('not cache');

На къде и как да се обърна към Ларавелските фасади и прочие, за да видя защо там не сработва? Ако може и някакъв тест да споделите, че аз вече не знам какво не тествах...
 
Опитай с направата на нов клас и extend-ни Illuminate\Cache\MemcachedConnector

Код:
use Illuminate\Cache\MemcachedConnector;

class CustomCacheTest extends MamcachedConnector
{
    private $memcached;

    public function __construct()
    {
        $this->memcached = $this->getMemcached(null, [], []); 
        // или $this->createMemcachedInstance() ако искаш директно. Двата варианта ще върнат едно и също.
    }
    
    public function dump()
    {
        dd($this->memcached);
    }
}

след това, ако искаш подай инстанцията на Illuminate\Cache\MemcachedStore и тествай с wrapper-а.

Общо взето те интересуват класовете тука https://github.com/laravel/framework/tree/8.x/src/Illuminate/Cache - Repository, MemcachedConnector, MemcachedStore.

П.П. Но сериозно те съветвам да си подкараш дебъгера. Може да ти писне от мен да го повтарям, но по-хубаво нещо от това няма.
 
Пробвах така и сработи кеширането.
Код:
use Illuminate\Cache\MemcachedConnector;

class Test extends MamcachedConnector
{
    public function __construct()
    {
        $m = $this->connect(config('cache.stores.memcached.servers'));
        dump($m->getServerList());
        if ($m->get('key')) {
            dd($m->get('key'));
        }
        $m->set('key', 'test', 5);

        dd('not cache');
    }
    
}
Нкоя фасада ли се базика с мен, не знам. Интересно ми е къде точно се подава конфигурацията и се вика драйвъра, за да видя и дебъгна точно там.

dd(cache()->driver('memcached'));

ми връща всичко коректно:

Код:
Illuminate\Cache\Repository {#1421 ▼
  #store: Illuminate\Cache\MemcachedStore {#1423 ▼
    #memcached: Memcached {#1419 ▼
      servers: array:1 [▼
        0 => array:3 [▼
          "host" => "127.0.0.1"
          "port" => 11211
          "type" => "TCP"
        ]
      ]
      options: {}
    }
    #prefix: "laravel_prefix:"
    #onVersionThree: true
  }
  #events: Illuminate\Events\Dispatcher {#27 ▶}
  #default: 3600
}

Пробвах и това:
Код:
        dump(\cache()->store('memcached')->put('key', 'test', 5));
        dump(\cache()->store('memcached')->has('key'));
        dd(\cache()->store('memcached')->get('key'));
Връща:
true
false
null
 
Ако ми остане време ще тествам при мен. Проследявайки кода, всичко изглежда наред. С просто око от това, което проследих не видях някъде, където има проблем, но без да проследя отгоре до долу какво се случва само стрелям на посоки.

На каква ОС тестваш и с коя конкретно версия на Ларавел 8 работиш? Също гледал ли си дали има нови пачове?
Кажи си пълната версия на PHP, за да мога да се доближа максимално до твоята среда.

Иначе пробвай и този bypass:

Код:
cache()->store('memcached')->getStore()->getMemcached()->set('key', 'test', 5);
cache()->store('memcached')->getStore()->getMemcached()->get('key');

// както и

$cache = cache()->store('memcached');
$cache->put('key', 'test', 5);
$cache->get('key');
 
PHP Version 7.3.22
Laravel: 8.16.0
Nginx Linux

С малко преработки и тестове на примерите ти, този код сработи, но няма repository-то налично, като методи (has, put...)!
Код:
        $cache = cache()->store('memcached')->getStore()->getMemcached();
        $cache->set('key', 'test', 5);
        dd($cache->get('key'));
Нещо не е както трябва ми се струва и не знам проблема от мен ли е или от Ларавел.
 
Няма ги, защото така използваш memcached директно.

Нещо ме навява на мисълта, че префикса, който слага Laravel бъгва нещо нещата.

Нека поне видим при запазване ли не работи или при взимане:

Код:
cache()->store('memcached')->put('key', 'test', 10);
dump(cache()->store('memcached')->getStore()->getMemcached()->fetchAll()); // да видим дали въобще има нещо запазено

// и след това

cache()->store('memcached')->get('key');
cache()->store('memcached')->getStore()->getMemcached()->getResultCode(); // да видим последната операция какъв код връща

Понеже get() на wrapper-а извиква getResultCode() не съм сигурен дали извикването на този getResultCode() няма да върне резултат за предния getResultCode() понеже пише, че връща кода на последния извикан Memcached метод.

П.П. Ако нямаш сетнат префикс, след горните тестове опитай да си зададеш ръчно име чрез CACHE_PREFIX в env файла.
 
Тествах кода от примера ти:
Код:
        cache()->store('memcached')->put('key', 'test', 10);
        dump(cache()->store('memcached')->getStore()->getMemcached()->fetchAll()); 
        dump(cache()->store('memcached')->get('key'));
        dd(cache()->store('memcached')->getStore()->getMemcached()->getResultCode());
Връща ми:
Код:
false
null
16

Смених и префикса на кеша, пак същата работа.
 
Добре, това доказва, че записването не работи. В предния пост забравих, но да тестваме и следното:

Код:
cache()->store('memcached')->put('key', 'test', 10);
cache()->store('memcached')->getStore()->getMemcached()->getResultCode();
cache()->store('memcached')->getStore()->getMemcached()->getResultMessage();

Да разберем какъв код ще върне току-виж ни посочи причината.

Бих тествал и това (обратния процес):

Код:
cache()->store('memcached')->getStore()->getMemcached()->set('key', 'test', 10);
cache()->store('memcached')->get('key');

Ще е желателно да премахнеш префикса или да го добавиш на set() иначе get() на wrapper-a ще търси за ключ PREFIXkey.

Ако и get() не сработи малко оставам с вързани ръце докато лично не дебъгна какво се случва. Проблема е, че ако при мен сработи, няма да мога да открия проблема.

Иначе още идеи ми идват, които можеш да тестваш:
1. Инсталираш предходна версия на Ларавел и пробваш там. Ако там проработи значи има нещо специфично при Ларавел 8.
2. Преинсталираш Ларавел 8.
3. Слагаш предходна версия на Ларавел 8.
 
Код:
        cache()->store('memcached')->put('key', 'test', 10);
        dump(cache()->store('memcached')->getStore()->getMemcached()->fetchAll());
        dump(cache()->store('memcached')->get('key'));
        dump(cache()->store('memcached')->getStore()->getMemcached()->getResultMessage());
        dd(cache()->store('memcached')->getStore()->getMemcached()->getResultCode());

false
null
"NOT FOUND"
16


Код:
	dump(cache()->store('memcached')->getStore()->getMemcached()->set('key', 'test', 10));
        dd(cache()->store('memcached')->get('key'));

true
null


Код:
        dump(cache()->store('memcached')->getStore()->getMemcached()->set('key', 'test', 10));
        dd(cache()->store('memcached')->get('key'));
Първо върна:

true
null

В еnv оставих
CACHE_PREFIX=
и върна:

true
"test"

Тоест така сработи.
 
dakata__92 каза:
Код:
        cache()->store('memcached')->put('key', 'test', 10);
        dump(cache()->store('memcached')->getStore()->getMemcached()->fetchAll());
        dump(cache()->store('memcached')->get('key'));
        dump(cache()->store('memcached')->getStore()->getMemcached()->getResultMessage());
        dd(cache()->store('memcached')->getStore()->getMemcached()->getResultCode());

false
null
"NOT FOUND"
16

Това не е същото, като това, което ти дадох. getResultCode() и getResultMessage() дават резултат на последната операция, която в моя случай исках да е на put(), а ти го изпълняваш на get(). Виж моя пример и ги сложи веднага след put() извикването.

Като допълнение, ако искаш тествай и add() метода.

Поне знаем също, че get() сработи.
 

Горе