- vừa được xem lúc

Symfony 4 + ECCUBE , làm thế nào để luân chuyển query giữa các node master slave

0 0 27

Người đăng: Phan Ngoc

Theo Viblo Asia

Mở đầu

Hắn nhiều người trong chúng ta có biết qua master slave node trong RDS , mặc định các framework PHP nổi tiếng như PHP , Symfony đều có hỗ trợ config master slave endpoint, để việc luân chuyển query được hiệu quả, các query WRITE sẽ được chuyển qua node WRITE, các query READ (SELECT) sẽ được chuyển qua node READ.

Vấn đề.

Và đây chính là lúc vấn đề bắt đầu 🙃🙃🙃🙃 . ECCUBE được viết dựa trên symfony 4, nhưng lại custom theo kiểu:

Tất cả request được wrap trong 1 câu transaction của query DB, dù request đó chỉ toàn query READ 👌👌

src/Eccube/EventListener/TransactionListener.php

 /** * Kernel request listener callback. * * @param GetResponseEvent $event */ public function onKernelRequest(GetResponseEvent $event) { if (!$this->isEnabled) { log_debug('Transaction Listener is disabled.'); return; } if (!$event->isMasterRequest()) { return; } /** @var Connection $Connection */ $Connection = $this->em->getConnection(); if (!$Connection->isConnected()) { $Connection->connect(); } $Connection->setAutoCommit(false); $Connection->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED); $this->em->beginTransaction(); log_debug('Begin Transaction.'); } 

Và rồi câu chuyện lại đi xa hơn 🥲🥲🥲 , đối với doctrine2 (thư viện query được dùng trong Symfony ECCUBE, một ORM library tương tự Eloquent của Laravel), các query được viết trong 1 transaction default sẽ được chuyển sang node WRITE (vì nó coi đây là 1 query sắp có ghi). TOANG !!!!

/** * Primary-Replica Connection * * Connection can be used with primary-replica setups. * * Important for the understanding of this connection should be how and when * it picks the replica or primary. * * 1. Replica if primary was never picked before and ONLY if 'getWrappedConnection' * or 'executeQuery' is used. * 2. Primary picked when 'exec', 'executeUpdate', 'executeStatement', 'insert', 'delete', 'update', 'createSavepoint', * 'releaseSavepoint', 'beginTransaction', 'rollback', 'commit', 'query' or * 'prepare' is called. * 3. If Primary was picked once during the lifetime of the connection it will always get picked afterwards. * 4. One replica connection is randomly picked ONCE during a request. * * ATTENTION: You can write to the replica with this connection if you execute a write query without * opening up a transaction. For example: * * $conn = DriverManager::getConnection(...); * $conn->executeQuery("DELETE FROM table"); * * Be aware that Connection#executeQuery is a method specifically for READ * operations only. * * Use Connection#executeStatement for any SQL statement that changes/updates * state in the database (UPDATE, INSERT, DELETE or DDL statements). *

Giải pháp

Ở đây ta cần custom lại class connection 1 chút, tạo 1 file CustomMasterSlaveConnection.php kế thừa MasterSlaveConnection, điểm quan trọng ở đây là method connect(). Chúng được override method connect chọn node WRITE READ phù hợp, implement thêm 1 cờ để lock, trong TH này ta có thể force cho câu query đó chạy trên NODE nào luôn cũng dc.

<?php
namespace Customize\Doctrine; use Doctrine\DBAL\Connections\MasterSlaveConnection;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\PDOConnection;
use InvalidArgumentException; class CustomMasterSlaveConnection extends MasterSlaveConnection implements Connection
{ private $currentConnectionName = null; protected $lock = false; /** * Check is slave node. */ public function isSlave() { return $this->currentConnectionName == 'replica'; } public function getCurrentConnectionName() { return $this->currentConnectionName; } /** * Lock change connection. */ public function lock() { $this->lock = true; return $this; } /** * Unlock change connection. */ public function unlock() { $this->lock = false; return $this; } /** * @param string|null $connectionName * * @return bool */ public function forceConnect($connectionName = null) { if ($connectionName !== 'master' && $connectionName !== 'slave') { throw new InvalidArgumentException('Invalid option to connect(), only master or slave allowed.'); } if ($connectionName === 'master') { $connectionName = 'primary'; } if ($connectionName === 'slave') { $connectionName = 'replica'; } if (isset($this->connections[$connectionName])) { $this->_conn = $this->connections[$connectionName]; $this->currentConnectionName = $connectionName; return false; } $this->connections[$connectionName] = $this->_conn = $this->connectTo($connectionName); $this->currentConnectionName = $connectionName; return true; } /** * @param string|null $connectionName * * @return bool */ public function connect($connectionName = null) { if ($connectionName === 'master') { $connectionName = 'primary'; } if ($connectionName === 'slave') { $connectionName = 'replica'; } if ($this->lock) { return false; } return $this->performConnect($connectionName); }
} 

Cách dùng thì khá dễ, chỉ cần lock() ở đầu phân đoạn bạn muốn dùng node READ, sau khi xong dùng hàm unlock() là dc

$conn = $this->entityManager->getConnection(); $conn->lock()->forceConnect('slave');
// do something query SELECT
// ...
$conn->unlock();

Kết

Hy vọng trên đây là 1 giải pháp giúp bạn có thể custom framework ECCUBE lựa chọn node READ WRITE phù hợp để đáp ứng khả năng chịu tải của hệ thống 😙😙😙.

Tks for reading !!! 😉😉😉

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tạo console với Symfony

Giới thiệu. Tương tự như command artisan Laravel trong Symfony chúng ta có thể tạo ra các command để thực hiện các nghiệp vụ mà chúng ta mong muốn, ví dụ như chúng ta cần update nhiều records hay export csv ... mà không cần đến request của client thay vào đó chúng ta sẽ run CLI (commant line). . Upd

0 0 16

- vừa được xem lúc

[Symfony 4] Ẩn một số log không cần thiết với custom handler

Bối cảnh. Symfony phát sinh khá nhiều log như, như process init, begin transaction, ini, .

0 0 27

- vừa được xem lúc

[Symfony4] Giải thích cơ chế hoạt động của worker

Phạm vi sử dụng. Symfony là framework gạo cội trong làng PHP, với khá nhiều project xử dụng và custom.

0 0 20

- vừa được xem lúc

Một số lỗi thường gặp về perfomance trong dự án ECCUBE + php

1.Lỗi không index làm delete query bị slow. Chức năng login có lưu table lock tạm, để xác định số lần nhập sai. . .

0 0 24

- vừa được xem lúc

So Sánh Laravel và Symfony: Chọn Khung PHP Phù Hợp Cho Dự Án Của Bạn

Trong phát triển PHP, việc chọn khung phù hợp là rất quan trọng để xây dựng các ứng dụng hiệu quả, có thể mở rộng và dễ bảo trì. Laravel và Symfony là hai khung PHP phổ biến nhất, mỗi khung đều có nhữ

0 0 8

- vừa được xem lúc

Tổng hợp tài nguyên PHP mất 5 ngày biên dịch, các bạn like nhé

Đây là một bộ sưu tập tài nguyên PHP mà tôi đã tổng hợp để giúp mọi người dễ dàng tìm thấy những gì họ cần. Tôi sẽ cập nhật danh sách này hàng tuần, vì vậy nếu bạn thấy hữu ích, hãy cho tôi một sao ❤️

0 0 3