1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
slave.php
См. документацию.
1<?php
2
5
7
9{
10 public static function SetOnLine($node_id, $master_id)
11 {
12 global $DB;
13
14 $arNode = CClusterDBNode::GetByID($node_id);
15 if (!is_array($arNode))
16 {
17 return;
18 }
19
20 if ($arNode['ROLE_ID'] == 'SLAVE')
21 {
22 if ($master_id == 1)
23 {
24 $masterDB = $DB;
25 }
26 else
27 {
28 ob_start();
29 $masterDB = CDatabase::GetDBNodeConnection($master_id, true);
30 ob_end_clean();
31 }
32
33 $rs = $masterDB->Query('show master status', false, '', ['fixed_connection' => true]);
34 if ($arMasterStatus = $rs->Fetch())
35 {
36 ob_start();
37 $nodeDB = CDatabase::GetDBNodeConnection($arNode['ID'], true);
38 ob_end_clean();
39 if (is_object($nodeDB))
40 {
41 $rs = $nodeDB->Query("
42 CHANGE MASTER TO
43 MASTER_HOST = '" . $DB->ForSql($arNode['MASTER_HOST']) . "'
44 ,MASTER_USER = '" . $DB->ForSql($masterDB->DBLogin) . "'
45 ,MASTER_PASSWORD = '" . $DB->ForSql($masterDB->DBPassword) . "'
46 ,MASTER_PORT = " . $DB->ForSql($arNode['MASTER_PORT']) . "
47 ,MASTER_LOG_FILE = '" . $arMasterStatus['File'] . "'
48 ,MASTER_LOG_POS = " . $arMasterStatus['Position'] . '
49 ', false, '', ['fixed_connection' => true]);
50
51 if ($rs)
52 {
53 $rs = $nodeDB->Query('START SLAVE');
54 }
55
56 if ($rs)
57 {
58 $obNode = new CClusterDBNode;
59 $obNode->Update($node_id, ['MASTER_ID' => $master_id]);
60
62 CClusterSlave::AdjustServerID($arNode, $nodeDB);
63 }
64 }
65 }
66 }
67 elseif ($arNode['ROLE_ID'] == 'MASTER' && preg_match('/^(.+):(\\d+)$/', $arNode['DB_HOST'], $match))
68 {
69 $rs = $DB->Query('show master status', false, '', ['fixed_connection' => true]);
70 if ($arMasterStatus = $rs->Fetch())
71 {
72 ob_start();
73 $nodeDB = CDatabase::GetDBNodeConnection($arNode['ID'], true);
74 ob_end_clean();
75 if (is_object($nodeDB))
76 {
77 $nodeDB->Query('STOP SLAVE', false, '', ['fixed_connection' => true]);
78
79 $nodeDB->Query("
80 CHANGE MASTER TO
81 MASTER_HOST = '" . $DB->ForSql($arNode['MASTER_HOST']) . "'
82 ,MASTER_USER = '" . $DB->ForSql($DB->DBLogin) . "'
83 ,MASTER_PASSWORD = '" . $DB->ForSql($DB->DBPassword) . "'
84 ,MASTER_PORT = " . $DB->ForSql($arNode['MASTER_PORT']) . "
85 ,MASTER_LOG_FILE = '" . $arMasterStatus['File'] . "'
86 ,MASTER_LOG_POS = " . $arMasterStatus['Position'] . '
87 ', false, '', ['fixed_connection' => true]);
88
89 $nodeDB->Query('START SLAVE', false, '', ['fixed_connection' => true]);
90
91 $rs = $nodeDB->Query('show master status', false, '', ['fixed_connection' => true]);
92 if ($arMasterStatus = $rs->Fetch())
93 {
94 $rs = $DB->Query('STOP SLAVE', true, '', ['fixed_connection' => true]);
95
96 if ($rs)
97 {
98 $rs = $DB->Query("
99 CHANGE MASTER TO
100 MASTER_HOST = '" . $DB->ForSql($match[1]) . "'
101 ,MASTER_USER = '" . $DB->ForSql($arNode['DB_LOGIN']) . "'
102 ,MASTER_PASSWORD = '" . $DB->ForSql($arNode['DB_PASSWORD']) . "'
103 ,MASTER_PORT = " . $DB->ForSql($match[2]) . "
104 ,MASTER_LOG_FILE = '" . $arMasterStatus['File'] . "'
105 ,MASTER_LOG_POS = " . $arMasterStatus['Position'] . '
106 ', false, '', ['fixed_connection' => true]);
107 }
108
109 if ($rs)
110 {
111 $rs = $DB->Query('START SLAVE');
112 }
113
114 if ($rs)
115 {
116 $obNode = new CClusterDBNode;
117 $obNode->Update($node_id, ['MASTER_ID' => $master_id]);
118 $obNode->Update($master_id, ['MASTER_ID' => $node_id]);
119
121 CClusterSlave::AdjustServerID($arNode, $nodeDB);
122 }
123 }
124 }
125 }
126 }
127 }
128
129 public static function Pause($node_id)
130 {
131 global $DB;
132
133 $arNode = CClusterDBNode::GetByID($node_id);
134 if (!is_array($arNode))
135 {
136 return;
137 }
138
139 if ($node_id == 1)
140 {
141 $nodeDB = $DB;
142 }
143 else
144 {
145 ob_start();
146 $nodeDB = CDatabase::GetDBNodeConnection($arNode['ID'], true);
147 ob_end_clean();
148 }
149
150 if (!is_object($nodeDB))
151 {
152 return;
153 }
154
155 $rs = $nodeDB->Query('STOP SLAVE SQL_THREAD', false, '', ['fixed_connection' => true]);
156 if ($rs)
157 {
158 $ob = new CClusterDBNode;
159 $ob->Update($arNode['ID'], ['STATUS' => 'PAUSED']);
160 }
161 }
162
163 public static function Resume($node_id)
164 {
165 global $DB;
166
167 $arNode = CClusterDBNode::GetByID($node_id);
168 if (!is_array($arNode))
169 {
170 return;
171 }
172
173 if ($node_id == 1)
174 {
175 $nodeDB = $DB;
176 }
177 else
178 {
179 ob_start();
180 $nodeDB = CDatabase::GetDBNodeConnection($arNode['ID'], true, false);
181 ob_end_clean();
182 }
183
184 if (!is_object($nodeDB))
185 {
186 return;
187 }
188
189 $rs = $nodeDB->Query('START SLAVE', false, '', ['fixed_connection' => true]);
190 if ($rs)
191 {
192 $ob = new CClusterDBNode;
193 $ob->Update($arNode['ID'], ['STATUS' => 'ONLINE']);
194 }
195 }
196
197 public static function Stop($node_id)
198 {
199 global $DB;
200
201 $arNode = CClusterDBNode::GetByID($node_id);
202 if (!is_array($arNode))
203 {
204 return false;
205 }
206
207 if ($node_id == 1)
208 {
209 $nodeDB = $DB;
210 }
211 else
212 {
213 ob_start();
214 $nodeDB = CDatabase::GetDBNodeConnection($arNode['ID'], true, false);
215 ob_end_clean();
216 }
217
218 if (!is_object($nodeDB))
219 {
220 return false;
221 }
222
223 $rs = $nodeDB->Query('STOP SLAVE', false, '', ['fixed_connection' => true]);
224 if ($rs)
225 {
226 $ob = new CClusterDBNode;
227 if ($node_id == 1)
228 {
229 $res = $ob->Update($arNode['ID'], ['MASTER_ID' => false, 'STATUS' => 'ONLINE']);
230 }
231 else
232 {
233 $res = $ob->Update($arNode['ID'], ['STATUS' => 'READY']);
234 }
235
236 return $res;
237 }
238 else
239 {
240 return false;
241 }
242 }
243
244 public static function SkipSQLError($node_id)
245 {
246 global $DB;
247
248 $arNode = CClusterDBNode::GetByID($node_id);
249 if (is_array($arNode))
250 {
251 if ($node_id == 1)
252 {
253 $nodeDB = $DB;
254 }
255 else
256 {
257 ob_start();
258 $nodeDB = CDatabase::GetDBNodeConnection($arNode['ID'], true, false);
259 ob_end_clean();
260 }
261
262 if (is_object($nodeDB))
263 {
264 //TODO check if started just make active
265 $rs = $nodeDB->Query('STOP SLAVE', false, '', ['fixed_connection' => true]);
266
267 if ($rs)
268 {
269 $rs = $nodeDB->Query('SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1', true, '', ['fixed_connection' => true]);
270 if (!$rs)
271 {
272 return $nodeDB->GetErrorMessage();
273 }
274 }
275
276 if ($rs)
277 {
278 $nodeDB->Query('START SLAVE', false, '', ['fixed_connection' => true]);
279 }
280 }
281 }
282
283 return true;
284 }
285
286 public static function GetStatus($node_id, $bSlaveStatus = true, $bGlobalStatus = true, $bVariables = true)
287 {
288 global $DB;
289
290 $arNode = CClusterDBNode::GetByID($node_id);
291 if (!is_array($arNode))
292 {
293 return false;
294 }
295
296 if ($node_id == 1)
297 {
298 $nodeDB = $DB;
299 }
300 else
301 {
302 ob_start();
303 try
304 {
305 $nodeDB = CDatabase::GetDBNodeConnection($node_id, true, false);
306 }
307 catch (\Bitrix\Main\DB\ConnectionException $_)
308 {
309 $nodeDB = false;
310 }
311 ob_end_clean();
312 }
313
314 if (!is_object($nodeDB))
315 {
316 return false;
317 }
318
319 $arStatus = ['server_id' => null];
320
321 if ($bVariables)
322 {
323 $rs = $nodeDB->Query("show variables like 'server_id'", false, '', ['fixed_connection' => true]);
324 if ($ar = $rs->Fetch())
325 {
326 $arStatus['server_id'] = $ar['Value'];
327 }
328 }
329
330 $cacheID = 'slave_for_master';
331 $existSlave = false;
332 $managedCache = \Bitrix\Main\Application::getInstance()->getManagedCache();
333
334 if (
335 CACHED_b_cluster_dbnode !== false
336 && $managedCache->read(CACHED_b_cluster_dbnode, $cacheID, 'b_cluster_dbnode')
337 )
338 {
339 $existSlave = $managedCache->get($cacheID);
340 }
341 else
342 {
343 if (CClusterDBNode::GetList([], ['=MASTER_ID' => $node_id])->Fetch())
344 {
345 $existSlave = true;
346 }
347 $managedCache->set($cacheID, $existSlave);
348 }
349
350 if ($existSlave)
351 {
352 $arStatus = array_merge($arStatus, [
353 'File' => null,
354 'Position' => null,
355 ]);
356
357 if ($bSlaveStatus)
358 {
359 $rs = $nodeDB->Query('SHOW MASTER STATUS', true, '', ['fixed_connection' => true]);
360 if (!$rs)
361 {
362 return GetMessage('CLU_NO_PRIVILEGES', ['#sql#' => "GRANT REPLICATION CLIENT on *.* to '" . $nodeDB->DBLogin . "'@'%';"]);
363 }
364
365 $ar = $rs->Fetch();
366 if (is_array($ar))
367 {
368 foreach ($ar as $key => $value)
369 {
370 if ($key == 'Last_Error')
371 {
372 $key = 'Last_SQL_Error';
373 }
374
375 if (array_key_exists($key, $arStatus))
376 {
377 $arStatus[$key] = $value;
378 }
379 }
380 }
381 }
382 }
383
384 if ($arNode['MASTER_ID'] <> '')
385 {
386 $arStatus = array_merge($arStatus, [
387 'Slave_IO_State' => null,
388 'Slave_IO_Running' => null,
389 'Read_Master_Log_Pos' => null,
390 'Slave_SQL_Running' => null,
391 'Exec_Master_Log_Pos' => null,
392 'Seconds_Behind_Master' => null,
393 'Last_IO_Error' => null,
394 'Last_SQL_Error' => null,
395 'Com_select' => null,
396 ]);
397
398 if ($bSlaveStatus)
399 {
400 $rs = $nodeDB->Query('SHOW SLAVE STATUS', true, '', ['fixed_connection' => true]);
401 if (!$rs)
402 {
403 return GetMessage('CLU_NO_PRIVILEGES', ['#sql#' => "GRANT REPLICATION CLIENT on *.* to '" . $nodeDB->DBLogin . "'@'%';"]);
404 }
405
406 $ar = $rs->Fetch();
407 if (is_array($ar))
408 {
409 foreach ($ar as $key => $value)
410 {
411 if ($key == 'Last_Error')
412 {
413 $key = 'Last_SQL_Error';
414 }
415
416 if (array_key_exists($key, $arStatus))
417 {
418 $arStatus[$key] = $value;
419 }
420 }
421 }
422 }
423 }
424
425 if ($bGlobalStatus)
426 {
427 $rs = $nodeDB->Query("show global status where Variable_name in ('Com_select', 'Com_do')", true, '', ['fixed_connection' => true]);
428 if (is_object($rs))
429 {
430 while ($ar = $rs->Fetch())
431 {
432 if (!isset($arStatus['Com_select']))
433 {
434 $arStatus['Com_select'] = 0;
435 }
436
437 if ($ar['Variable_name'] == 'Com_do')
438 {
439 $arStatus['Com_select'] -= $ar['Value'] * 2;
440 }
441 else
442 {
443 $arStatus['Com_select'] += $ar['Value'];
444 }
445 }
446 }
447 else
448 {
449 $rs = $nodeDB->Query("show status like 'Com_select'", false, '', ['fixed_connection' => true]);
450 $ar = $rs->Fetch();
451 if ($ar)
452 {
453 $arStatus['Com_select'] += $ar['Value'];
454 }
455
456 $rs = $nodeDB->Query("show status like 'Com_do'", false, '', ['fixed_connection' => true]);
457 $ar = $rs->Fetch();
458 if ($ar)
459 {
460 $arStatus['Com_select'] -= $ar['Value'] * 2;
461 }
462 }
463 }
464
465 return $arStatus;
466 }
467
468 public static function GetList(): array
469 {
470 global $DB;
471 static $slaves = false;
472 if ($slaves === false)
473 {
474 $cacheID = 'db_slaves_v2';
475
477 $cache = Application::getInstance()->getManagedCache();
478 if (
479 CACHED_b_cluster_dbnode !== false
480 && $cache->read(CACHED_b_cluster_dbnode, $cacheID, 'b_cluster_dbnode')
481 )
482 {
483 $slaves = $cache->get($cacheID);
484 }
485 else
486 {
487 $slaves = [];
488
489 $rs = $DB->Query("
490 SELECT ID, WEIGHT, ROLE_ID, GROUP_ID
491 FROM b_cluster_dbnode
492 WHERE STATUS = 'ONLINE' AND (SELECTABLE is null or SELECTABLE = 'Y')
493 ORDER BY ID
494 ", false, '', ['fixed_connection' => true]);
495 while ($ar = $rs->Fetch())
496 {
497 $slaves[intval($ar['ID'])] = $ar;
498 }
499
500 if (CACHED_b_cluster_dbnode !== false)
501 {
502 $cache->set($cacheID, $slaves);
503 }
504 }
505 }
506 return $slaves;
507 }
508
513 public static function AdjustServerID($arNode, $nodeDB)
514 {
515 $rs = $nodeDB->Query("show variables like 'server_id'", false, '', ['fixed_connection' => true]);
516 if ($ar = $rs->Fetch())
517 {
518 if ($ar['Value'] != $arNode['SERVER_ID'])
519 {
520 $ob = new CClusterDBNode;
521 $ob->Update($arNode['ID'], ['SERVER_ID' => $ar['Value']]);
522 }
523 }
524 }
525
526 protected static function GetMaxSlaveDelay(): int
527 {
528 static $max_slave_delay = null;
529 if (!isset($max_slave_delay))
530 {
531 $max_slave_delay = (int) Option::get('cluster', 'max_slave_delay');
532 if (
533 Application::getInstance()->isInitialized()
534 && isset(Application::getInstance()->getKernelSession()['BX_REDIRECT_TIME'])
535 )
536 {
537 $redirect_delay = time() - Application::getInstance()->getKernelSession()['BX_REDIRECT_TIME'] + 1;
538 if (
539 $redirect_delay > 0
540 && $redirect_delay < $max_slave_delay
541 )
542 {
543 $max_slave_delay = $redirect_delay;
544 }
545 }
546 }
547 return $max_slave_delay;
548 }
549
550 protected static function IsSlaveOk($slave_id): bool
551 {
552 $cache = \Bitrix\Main\Data\Cache::createInstance();
553 if ($cache->initCache(
554 (int) Option::get('cluster', 'slave_status_cache_time'),
555 'cluster_slave_status_' . (int) $slave_id,
556 'cluster'
557 ))
558 {
559 $slaveStatus = $cache->getVars();
560 }
561 else
562 {
563 $slaveStatus = static::GetStatus($slave_id, true, false, false);
564 }
565
566 if (
567 !$slaveStatus
568 || $slaveStatus['Seconds_Behind_Master'] > static::GetMaxSlaveDelay()
569 || $slaveStatus['Last_SQL_Error'] != ''
570 || $slaveStatus['Last_IO_Error'] != ''
571 || $slaveStatus['Slave_SQL_Running'] === 'No'
572 )
573 {
574 if ($cache->startDataCache())
575 {
576 $cache->endDataCache($slaveStatus);
577 }
578 return false;
579 }
580 return true;
581 }
582
583 public static function GetRandomNode()
584 {
585 $slaves = static::GetList();
586 if (empty($slaves))
587 {
588 return false;
589 }
590
591 //Exclude slaves from other cluster groups
592 foreach ($slaves as $i => $slave)
593 {
594 $isOtherGroup = defined('BX_CLUSTER_GROUP') && ($slave['GROUP_ID'] != constant('BX_CLUSTER_GROUP'));
595 if (
596 defined('BX_CLUSTER_SLAVE_USE_ANY_GROUP')
597 && constant('BX_CLUSTER_SLAVE_USE_ANY_GROUP') === true
598 && $slave['ROLE_ID'] == 'SLAVE'
599 )
600 {
601 $isOtherGroup = false;
602 }
603
604 if ($isOtherGroup)
605 {
606 unset($slaves[$i]);
607 }
608 }
609
610 $found = false;
611 while (true)
612 {
613 if (empty($slaves))
614 {
615 return false;
616 }
617
618 $total_weight = 0;
619 foreach ($slaves as $i => $slave)
620 {
621 $total_weight += $slave['WEIGHT'];
622 $slaves[$i]['PIE_WEIGHT'] = $total_weight;
623 }
624
625 $rand = ($total_weight > 0 ? mt_rand(1, $total_weight) : 0);
626 foreach ($slaves as $i => $slave)
627 {
628 if ($rand <= $slave['PIE_WEIGHT'])
629 {
630 if ($slave['ROLE_ID'] == 'SLAVE')
631 {
632 if (!static::IsSlaveOk($slave['ID']))
633 {
634 unset($slaves[$i]);
635 continue 2;
636 }
637 }
638
639 $found = $slave;
640 break 2;
641 }
642 }
643 }
644
645 if (!$found || $found['ROLE_ID'] != 'SLAVE')
646 {
647 return false; //use main connection
648 }
649
650 return $found;
651 }
652}
static getInstance()
Определения application.php:98
static SetOnline($node_id)
Определения dbnode.php:250
static GetList($arOrder=false, $arFilter=false, $arSelect=false)
Определения dbnode.php:284
Update($ID, $arFields)
Определения dbnode.php:187
static GetByID($node_id, $arVirtNode=false)
Определения dbnode.php:79
Определения dbnode.php:5
Определения slave.php:9
static Stop($node_id)
Определения slave.php:197
static GetRandomNode()
Определения slave.php:583
static SkipSQLError($node_id)
Определения slave.php:244
static GetStatus($node_id, $bSlaveStatus=true, $bGlobalStatus=true, $bVariables=true)
Определения slave.php:286
static Pause($node_id)
Определения slave.php:129
static AdjustServerID($arNode, $nodeDB)
Определения slave.php:513
static GetMaxSlaveDelay()
Определения slave.php:526
static Resume($node_id)
Определения slave.php:163
static IsSlaveOk($slave_id)
Определения slave.php:550
static SetOnLine($node_id, $master_id)
Определения slave.php:10
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$res
Определения filter_act.php:7
global $DB
Определения cron_frame.php:29
IncludeModuleLangFile($filepath, $lang=false, $bReturnArray=false)
Определения tools.php:3778
GetMessage($name, $aReplace=null)
Определения tools.php:3397
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$ar
Определения options.php:199
if(empty($signedUserToken)) $key
Определения quickway.php:257
$i
Определения factura.php:643
$rs
Определения action.php:82