Продолжая тему кэширования. Мемкэш прекрасно подходит для хранения сессий, но как узнать число активных пользователей и выделить среди этих пользователей зарегистрированных? Напрашивается решение, с использованием MEMORY таблицы MySQL. Но вот беда. В MEMORY нельзя использовать поля типа TEXT и соотвественно нельзя сохранить даже небольшой объём данных (ограничиваемся 255 символами поля типа CHAR/VARCHAR). Какой отсюда выход? Объединить две методики. В мемкэше хранить данные, в MEMORY таблице только информацию о пользователе. PHP: <?php require_once './Session/Session.php'; require_once './Cache/Cache.php'; require_once './Db/Db.php'; require_once './Toolkit/Toolkit.php'; class MySessionStorage extends MemorySessionStorage { private $db; private $userId = 0; public function __construct() { parent::__construct(Toolkit::instance()->getCache()); $this->db = Toolkit::instance()->getDb(); } public function setUserId($id) { $this->userId = $id; } public function getUserId() { return $this->userId; } public function getOnlineCount() { $query = ' SELECT COUNT(*) AS count FROM session WHERE ses_time > (UNIX_TIMESTAMP() - 300) '; return $this->db->query($query)->fetchOne('count'); } public function read($session_id) { $query = ' SELECT user_id FROM session WHERE ses_id = ? '; $this->userId = $this->db->query($query, $session_id)->fetchOne('user_id'); return parent::read($session_id); } public function write($session_id, $data) { $query = ' REPLACE INTO session (ses_id, user_id, ses_time) VALUES (?, ?, UNIX_TIMESTAMP()) '; $this->db->query($query, array($session_id, $this->userId)); return parent::write($session_id, $data); } } try { Toolkit::instance()->setDb(new Db(array('server' => 'localhost', 'user' => 'root', 'database' => 'test'))); Toolkit::instance()->setCache(Cache::factory('memory')); $session = new Session(new MySessionStorage()); $session->start(); if (!$session->has('time')) { $session->set('time', time()); } if (!$session->getStorage()->getUserId()) { $session->getStorage()->setUserId(321); } print 'Online: ' . $session->getStorage()->getOnlineCount(); } catch (Exception $e) { print $e->getMessage(); } [sql]CREATE TABLE `session` ( ses_id char(32) NOT NULL default '', user_id int(11) NOT NULL default '0', ses_time int(10) unsigned NOT NULL default '0', PRIMARY KEY (ses_id) ) ENGINE=HEAP DEFAULT CHARSET=utf8;[/sql] Сорсы тут: http://sergey89.ru/files/php/memcached-sessions.tar.gz p.s. может я немного не выспался и не увидел более простого решения. просветите.
Sergey89 Все правильно, нефиг в сессиях хранить большие объемы данных. Не для этого они придуманы. Сам всегда храню сессии в MEMORY таблице.
озадачили :? хм, я вот раньше делал так: таблица session (userid или 0, если %anonymous%; hash=md5(ip+useragent), только если %anonymous%; timestamp последнего действия; location), далее просто таблица. при открытии любой страницы, удаляем из таблицы все записи, где timestamp отличается от текущего time() на 5 минут засылаем или обновляем свою запись выводим все записи, что там есть, и на основе их формируем статистику. /me наверно быдлдокодер?
Народ вы че. Совсем мануал читать перестали. VARCHAR хрен знает с какой дремучей версии 64К размер. Если кодировка UTF8 - 64K/3
А какие проблемы? [sql]mysql> use test; Database changed mysql> DROP TABLE IF EXISTS `test`.`tst`; Query OK, 0 rows affected (0.83 sec) mysql> CREATE TABLE `test`.`tst` ( -> `vrchar` varchar(64000) default NULL, -> KEY `vrchar` USING BTREE (`vrchar`(1024)) -> ) ENGINE=MEMORY DEFAULT CHARSET=utf8; ERROR 1074 (42000): Column length too big for column 'vrchar' (max = 21845); use BLOB or TEXT instead mysql> DROP TABLE IF EXISTS `test`.`tst`; Query OK, 0 rows affected, 1 warning (0.02 sec) mysql> CREATE TABLE `test`.`tst` ( -> `vrchar` varchar(21000) default NULL, -> KEY `vrchar` USING BTREE (`vrchar`(1024)) -> ) ENGINE=MEMORY DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.09 sec) mysql>[/sql]
EugeneTM Пипец решение... теперь подумай, сколько будет жрать памяти такая таблица, если на сайт зайдет человек 1000, плюс учитывая устаревшие, но еще не удаленные сессии? Таблица-то FIXED типа, а не DYNAMIC, и все поля всегда занимают по максимуму.
А кто сказал что столько нужно? Это во первых. Во вторых - даже если 100К на сессию * 1000 = 100М Это что - много? Да и memcached не в вакууме живет - тоже память ест. Несколько меньше конечно, но не на порядки. У БД плюс возможность обработки запросами , особенно групп записей. Велосипедеразм по прикручиванию к индексам memcashed подобного функционала хуже на много. Просто смотреть нужно - что от сессий нужно. Если тупо SID держать , нах БД не нужна. А если я дуплю update'ми во время сеанса все телодвижения пользователя и хрен какой сервак их потянет если на диск буду каждый пихать. А по gc handler'у, обработанные одним запросом, итоги по всем устаревшим пользователям в базу пихаю. Причем при обработке цепляю и данные из самой базы. Расскажи мне - как ты это с memcashed сделаешь? Только не надо квадратные колеса строить из обновим данные memcashed, потом на клиента их притянем, потом на клиента из БД данных заберем, потом чегонить посчитаем , а потом как запрос построим , да в базу как затолкаем. Реальный гемор - контроль max heap size и возможность сваливания в своп. Хотя если продуманно сделать - решаемо.
EugeneTM Да, это много. Не на каждом хостинге тебе позволят вот так, за красивые глаза, скушать 100 Мб оперативной памяти. Я полностью согласен, что сессии надо хранить в БД, а не в мемкеше. Я говорю, что "тяжелых" сессий быть не должно. Что у тебя там такого хранится, что для каждого пользователя надо постоянно несколько десятков, или даже сотен, килобайт, сессионных данных? Мне в голову приходят только данные формы. Но это надо делать аяксом (храня данные между запросами в браузере клиента, а не на сервере), ну или в худшем случае хранить такие данные в отдельной таблице, обычной, а не MEMORY, только для тех. кому это действительно нужно, а не для всех подряд.
Собственно правильное решение у человека, потому что если вам нужна функциональность "User is online" и при этом в сессии должно храниться достаточно прилично данных, то это база + memcached либо какая-то собственная разработка, которая умеет хранить сессии, делать им expire, обновлять и выдавать из них данные. Для базы FIXED не проблема, ведь не нужно пихать в базу кучу полей. Хватает UID + last_access, а это не много весит. При md5 UID сессии + timestamp это 36 байт на юзера. При 10 000 юзеров это ~352 KB, что очень мало. Всё остальное в memcached.
По порядку Если у тебя больше 1 000 пользователей одновременно сидят и интенсивно юзают БД, то 100М рамы на фоне остальных потребностей - мелочь. И речь идет уже не о хостинге , а о своих серваках. Потому что не только по памяти тебе не позволят. Чего и где хранить - смотреть надо по задаче, а не искать серебрянную пулю на все случаи жизни. Про что там хранится - в моем посте написано, читай. Про формы там ни слова.
EugeneTM Этот набор слов я должен быть прочитать? И где здесь написано, какие данные ты предлагаешь таким макаром хранить в сессиях? Главное - с чего ты взял, что я за мемкеш? Я же по-русски написал в начале темы:
Почему сессии использовать для хранить данные? К ним можно туеву хучу функционала прицепить , и получить охрененно более эффективное приложение. ЗЫ Ну а если все что пишут набор слов который ты читать не должен, но ответить считаешь правильным... Мож ты просто чего недопонимаешь