├── 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 |
53 | - basedir
54 | - initdir
55 | - filename
56 |
57 |
58 | когда мы в первый раз делаем запись в кэш, то создаются 3 записи:
59 |
60 |
61 | - запись с ключом basedir, которая содержит рандомный хэш basedir_version
62 | - запись с ключом basedir_version . "|" . init_dir , которая содержит рандомный хэш initdir_version
63 | - и собственно наша запись с ключом basedir_version . "|" . initdir_version . "|" filename , содержащая кэшируемые данные
64 |
65 |
66 | При массовой очистке кэша, например функцией cleanDir или кнопкой очистки кэша из админки, битрикс поступает следующим образом:
67 |
68 |
69 | - очищает запись с ключом basedir_version . "|" . init_dir (в случае с cleanDir)
70 | - очищает запись с ключом basedir (в случае с «очистить кэш» из админки)
71 |
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 |
2 | /**
3 | * Copyright (c) 2017. Dmitry Kozlov. https://github.com/DimMount
4 | */
5 |
6 | if(!check_bitrix_sessid()) {
7 | return;
8 | }
9 |
10 | echo CAdminMessage::ShowNote(GetMessage('MOD_INST_OK'));
11 |
12 | echo CAdminMessage::ShowNote(GetMessage('DIMMOUNT_REDISCACHE_SETTINGS_COMPLETE'));
13 | ?>
14 |