├── LICENSE ├── README.md ├── include.php ├── install ├── index.php ├── step.php ├── unstep.php └── version.php └── lang ├── en └── install │ ├── index.php │ ├── step.php │ └── unstep.php └── ru └── install ├── index.php ├── step.php └── unstep.php /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Dmitry Kozlov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dimmount.rediscache 2 | Модуль Битрикс для использования Redis в роли сервера кеша 3 | 4 | ## Установка Redis 5 | 6 | Итак, для начала устанавливаем redis. (если у вас windows, то можно скачать инсталлятор отсюда https://github.com/MSOpenTech/redis/releases) 7 | Поскольку сервер будет использоваться для хранения кэша данных, то настроим в конфиге максимальный объем используемой памяти: 8 | ``` 9 | maxmemory 100mb 10 | ``` 11 | 12 | и политику вытеснения из памяти: 13 | 14 | ``` 15 | maxmemory-policy volatile-ttl 16 | ``` 17 | 18 | данная политика означает, что при нехватке выделенной памяти для новой записи, будут выброшены записи, время жизни которых наиболее приближено к окончанию. 19 | 20 | ## Настройка PHP 21 | 22 | Для работы с redis в PHP необходимо установить расширение https://github.com/phpredis/phpredis(под windows готовые DLL можно взять отсюда http://www.apachelounge.com/viewtopic...php?t=6359) 23 | ``` 24 | extension=php_igbinary.dll 25 | extension=php_redis.dll 26 | ``` 27 | 28 | ## Настройка Bitrix 29 | 30 | Модуль устанавливается обычным способом. Во время установки в файл .settings вносится настройка кеша: 31 | ```php 32 | 'type' => array( 33 | 'class_name' => 'CPHPCacheRedis', 34 | 'required_file' => 'modules/{имя модуля}/include.php' 35 | ) 36 | ``` 37 | 38 | при деинсталляции модуля настройки возвращаются к типу кеширования "files" 39 | 40 | По умолчанию для сервера Redis используются стандартные адрес 127.0.0.1 и порт 6397 41 | 42 | Для ручного указания адреса сервера можно задать константы в dbconn.php 43 | ```php 44 | define("BX_REDIS_IP", '127.0.0.1'); 45 | define("BX_REDIS_PORT", '6379'); 46 | ``` 47 | 48 | ## Очистка кэша (cleanDir) 49 | 50 | При кешировании в битриксе используются три уровня: 51 | 52 | 57 | 58 | когда мы в первый раз делаем запись в кэш, то создаются 3 записи: 59 | 60 | 65 | 66 | При массовой очистке кэша, например функцией cleanDir или кнопкой очистки кэша из админки, битрикс поступает следующим образом: 67 | 68 | 72 | 73 | Таким образом записи типа filename остаются «бесхозными» и продолжают висеть в памяти пока не истечет их время жизни или они не будут вытеснены политикой ограничения размера памяти. 74 | Однако redis позволяет получить список ключей по маске, поэтому в данном модуле все ключи, соответствующие маске удаляемого уровня, а потом уже удаляется сама запись 75 | 76 | ```php 77 | $keys = self::$obRedis->keys(self::$basedir_version[$basedir] . "|*"); 78 | self::$obRedis->del($keys); 79 | self::$obRedis->del($this->sid . $basedir); 80 | ``` 81 | -------------------------------------------------------------------------------- /include.php: -------------------------------------------------------------------------------- 1 | CPHPCacheRedis(); 39 | } 40 | 41 | /** 42 | * Инициализация соединения с redis 43 | */ 44 | public function CPHPCacheRedis() 45 | { 46 | if (class_exists('Redis')) { 47 | try { 48 | if (!is_object(self::$obRedis)) { 49 | $redisIP = (defined('BX_REDIS_IP') ? BX_REDIS_IP : '127.0.0.1'); 50 | $redisPort = (defined('BX_REDIS_PORT') ? BX_REDIS_PORT : '6379'); 51 | self::$obRedis = new Redis(); 52 | self::$obRedis->connect($redisIP, $redisPort); 53 | } 54 | 55 | if (!defined('BX_REDISCACHE_CONNECTED')) { 56 | if (self::$obRedis->ping() === '+PONG') { 57 | define('BX_REDISCACHE_CONNECTED', true); 58 | register_shutdown_function(['CPHPCacheRedis', 'close']); 59 | } 60 | } 61 | 62 | $this->sid = 'BX'; 63 | if (defined('BX_CACHE_SID')) { 64 | $this->sid = BX_CACHE_SID; 65 | } 66 | } catch (RedisException $e) { 67 | \AddMessage2Log($e->getMessage(), 'dimmount.rediscache'); 68 | } 69 | } 70 | } 71 | 72 | /** 73 | * Закрытие соединения с redis 74 | */ 75 | public function close() 76 | { 77 | // В некоторых модулях битрикса обнаружен баг (замечено в webservice) 78 | // В эпилоге битрикс закрывает соединение с кэшем, а потом снова обращается к кэшу, что вызывает ошибку 79 | // Поэтому закрытие временно коментируем. По завершении хита соединение с редисом все равно закроется 80 | 81 | // if (defined('BX_REDISCACHE_CONNECTED') && is_object(self::$obRedis)) { 82 | // self::$obRedis->close(); 83 | // } 84 | } 85 | 86 | /** 87 | * @return bool флаг наличия соединения с redis 88 | */ 89 | public function IsAvailable() 90 | { 91 | return defined('BX_REDISCACHE_CONNECTED'); 92 | } 93 | 94 | /** 95 | * Очистка кеша 96 | * 97 | * @param $basedir 98 | * @param bool $initdir 99 | * @param bool $filename 100 | * 101 | * @return bool 102 | */ 103 | public function clean($basedir, $initdir = false, $filename = false) 104 | { 105 | if (is_object(self::$obRedis)) { 106 | if ($filename) { 107 | if (!isset(self::$basedir_version[$basedir])) { 108 | self::$basedir_version[$basedir] = self::$obRedis->get($this->sid . $basedir); 109 | } 110 | 111 | if (self::$basedir_version[$basedir] === false || self::$basedir_version[$basedir] === '') { 112 | return true; 113 | } 114 | 115 | if ($initdir) { 116 | $initdir_version = self::$obRedis->get(self::$basedir_version[$basedir] . '|' . $initdir); 117 | if (!$initdir_version) { 118 | return true; 119 | } 120 | } else { 121 | $initdir_version = ''; 122 | } 123 | 124 | self::$obRedis->del(self::$basedir_version[$basedir] . '|' . $initdir_version . '|' . $filename); 125 | } else { 126 | if ($initdir) { 127 | if (!isset(self::$basedir_version[$basedir])) { 128 | self::$basedir_version[$basedir] = self::$obRedis->get($this->sid . $basedir); 129 | } 130 | 131 | if (self::$basedir_version[$basedir] === false || self::$basedir_version[$basedir] === '') { 132 | return true; 133 | } 134 | 135 | $initdir_version = self::$obRedis->get(self::$basedir_version[$basedir] . '|' . $initdir); 136 | if (!$initdir_version) { 137 | return true; 138 | } 139 | 140 | $keys = self::$obRedis->keys(self::$basedir_version[$basedir] . '|' . $initdir_version . '|*'); 141 | self::$obRedis->del($keys); 142 | self::$obRedis->del(self::$basedir_version[$basedir] . '|' . $initdir); 143 | } else { 144 | if (!isset(self::$basedir_version[$basedir])) { 145 | self::$basedir_version[$basedir] = self::$obRedis->get($this->sid . $basedir); 146 | } 147 | 148 | if (self::$basedir_version[$basedir] === false || self::$basedir_version[$basedir] === '') { 149 | return true; 150 | } 151 | 152 | $keys = self::$obRedis->keys(self::$basedir_version[$basedir] . '|*'); 153 | self::$obRedis->del($keys); 154 | self::$obRedis->del($this->sid . $basedir); 155 | if (isset(self::$basedir_version[$basedir])) { 156 | unset(self::$basedir_version[$basedir]); 157 | } 158 | } 159 | } 160 | 161 | return true; 162 | } 163 | 164 | return false; 165 | } 166 | 167 | /** 168 | * Чтение пары ключ/значение из кеша 169 | * 170 | * @param $arAllVars 171 | * @param $basedir 172 | * @param $initdir 173 | * @param $filename 174 | * @param $TTL 175 | * 176 | * @return bool 177 | */ 178 | public function read(&$arAllVars, $basedir, $initdir, $filename, $TTL) 179 | { 180 | if (!isset(self::$basedir_version[$basedir])) { 181 | self::$basedir_version[$basedir] = self::$obRedis->get($this->sid . $basedir); 182 | } 183 | 184 | if (self::$basedir_version[$basedir] === false || self::$basedir_version[$basedir] === '') { 185 | return false; 186 | } 187 | 188 | if ($initdir) { 189 | $initdir_version = self::$obRedis->get(self::$basedir_version[$basedir] . '|' . $initdir); 190 | if (!$initdir_version) { 191 | return false; 192 | } 193 | } else { 194 | $initdir_version = ''; 195 | } 196 | 197 | $serialAllVars = self::$obRedis->get(self::$basedir_version[$basedir] . '|' . $initdir_version . '|' . $filename); 198 | 199 | if (!$serialAllVars) { 200 | return false; 201 | } 202 | 203 | $this->read = strlen($serialAllVars); 204 | $arAllVars = unserialize($serialAllVars); 205 | 206 | return true; 207 | } 208 | 209 | /** 210 | * Запись пары ключ/значение в кеш 211 | * 212 | * @param $arAllVars 213 | * @param $basedir 214 | * @param $initdir 215 | * @param $filename 216 | * @param $TTL 217 | */ 218 | public function write($arAllVars, $basedir, $initdir, $filename, $TTL) 219 | { 220 | if (!isset(self::$basedir_version[$basedir])) { 221 | self::$basedir_version[$basedir] = self::$obRedis->get($this->sid . $basedir); 222 | } 223 | 224 | if (!self::$basedir_version[$basedir]) { 225 | self::$basedir_version[$basedir] = $this->sid . md5(mt_rand()); 226 | self::$obRedis->set($this->sid . $basedir, self::$basedir_version[$basedir]); 227 | } 228 | 229 | if ($initdir) { 230 | $initdir_version = self::$obRedis->get(self::$basedir_version[$basedir] . '|' . $initdir); 231 | if (!$initdir_version) { 232 | $initdir_version = $this->sid . md5(mt_rand()); 233 | self::$obRedis->set(self::$basedir_version[$basedir] . '|' . $initdir, $initdir_version); 234 | } 235 | } else { 236 | $initdir_version = ''; 237 | } 238 | 239 | $serialAllVars = serialize($arAllVars); 240 | $this->written = strlen($serialAllVars); 241 | 242 | self::$obRedis->set(self::$basedir_version[$basedir] . '|' . $initdir_version . '|' . $filename, 243 | $serialAllVars, (int)$TTL); 244 | } 245 | 246 | /** 247 | * Унаследовано от интерфейса ICacheBackend всегда возвращает false 248 | * 249 | * @param $path 250 | * 251 | * @return bool 252 | */ 253 | public function IsCacheExpired($path) 254 | { 255 | return false; 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /install/index.php: -------------------------------------------------------------------------------- 1 | MODULE_VERSION = $arModuleVersion['VERSION']; 35 | $this->MODULE_VERSION_DATE = $arModuleVersion['VERSION_DATE']; 36 | 37 | $this->MODULE_NAME = GetMessage('DIMMOUNT_REDISCACHE_INSTALL_NAME'); 38 | $this->MODULE_DESCRIPTION = GetMessage('DIMMOUNT_REDISCACHE_INSTALL_DESCRIPTION'); 39 | $this->PARTNER_NAME = GetMessage('DIMMOUNT_REDISCACHE_PARTNER'); 40 | $this->PARTNER_URI = GetMessage('DIMMOUNT_REDISCACHE_PARTNER_URI'); 41 | } 42 | 43 | public function DoInstall() 44 | { 45 | global $APPLICATION; 46 | RegisterModule($this->MODULE_ID); 47 | 48 | $cacheConfig = [ 49 | 'type' => [ 50 | 'class_name' => 'CPHPCacheRedis', 51 | 'required_file' => 'modules/' . $this->MODULE_ID . '/include.php' 52 | ] 53 | ]; 54 | 55 | $config = \Bitrix\Main\Config\Configuration::getInstance(); 56 | $config->addReadonly('cache', $cacheConfig); 57 | $config->saveConfiguration(); 58 | 59 | $APPLICATION->IncludeAdminFile(GetMessage('BARS46_REDISCACHE_INSTALL_MODULE'), __DIR__ . '/step.php'); 60 | } 61 | 62 | public function DoUninstall() 63 | { 64 | global $APPLICATION; 65 | 66 | $cacheConfig = [ 67 | 'type' => 'files' 68 | ]; 69 | 70 | $config = \Bitrix\Main\Config\Configuration::getInstance(); 71 | $config->addReadonly('cache', $cacheConfig); 72 | $config->saveConfiguration(); 73 | 74 | UnRegisterModule($this->MODULE_ID); 75 | $APPLICATION->IncludeAdminFile(GetMessage('BARS46_REDISCACHE_UNINSTALL_MODULE'), __DIR__ . '/unstep.php'); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /install/step.php: -------------------------------------------------------------------------------- 1 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /install/unstep.php: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /install/version.php: -------------------------------------------------------------------------------- 1 | '1.0.0', 8 | 'VERSION_DATE' => '2017-08-30 00:00:00' 9 | ]; 10 | -------------------------------------------------------------------------------- /lang/en/install/index.php: -------------------------------------------------------------------------------- 1 |