整合 Magento 與 Cloud Spanner

整合 Magento 與 Cloud Spanner

程式碼研究室簡介

subject上次更新時間:1月 5, 2022
account_circle作者:Derek Downey

1. 簡介

424db48d9db91638.png

整合 Magento 與 Cloud Spanner 後端

Magento 是廣受歡迎的 PHP 開放原始碼電子商務平台,可將資料儲存在 MySQL 中。

本程式碼研究室是概念驗證,可協助您在 Catalog 模組中運用 Cloud Spanner,而非 MySQL。這對想使用 Spanner 整合、測試及部署 Magento 或其他 PHP 應用程式的使用者來說非常實用。

Spanner 是 Google Cloud 的全代管企業級分散式型資料庫,具備關聯資料庫模型和非關聯水平擴充性的優點,其設計支援全球線上交易處理部署、SQL 語意、高可用性的水平資源調度和交易一致性。Spanner 可處理大量資料,使用時不僅不受大型應用程式的影響,也允許單一資料庫引擎標準化,以便處理所有需要 RDBMS 的工作負載。Spanner 提供 99.999%的可用性服務水準協議,可進行預定的維護作業或區域故障,完全不必停機。可提供高可用性和擴充性,支援現代化應用程式。

課程內容

  • 如何在 GCE 上安裝 Magento
  • 如何設定 Spanner 模擬器
  • 如何使用 HarbourBridge 將現有的 MySQL 結構定義遷移至 Spanner
  • 您需要變更哪些項目,才能整合使用 MySQL 的 PHP 應用程式 (例如 Magento),以便資料庫後端與 Spanner 搭配使用

建構項目

本程式碼研究室著重於整合 Magento 與 Spanner。我們提供程式碼區塊和設定操作說明,您可自行複製及貼上,但無須詳細討論。

在這個程式碼研究室中,您將開始整合 Magento 與 Spanner。您將學會以下內容:

軟硬體需求

  • 連結至帳單帳戶的 Google Cloud 專案。
  • 深入瞭解 PHP、Linux 和 Apache 設定。
  • Magento 體驗會有幫助,但這並非硬性規定。

2. 準備 GCE 執行個體

建立 GCE 執行個體

按照這裡所述步驟,在 Google Cloud Platform 中建立 Compute Engine 執行個體。

建立 GCE 執行個體時,請將執行個體類型變更為 e2-standard-2,並將開機磁碟大小變更為 20 GB。請保留預設值,但務必選取 [允許 HTTP 流量]和 [允許 HTTPS 流量],因為我們將使用 Magento 網頁介面。

這會導致 e2-standard-2 機器類型,不屬於共用核心執行個體,並且具備 2 個 vCPU、8 GB RAM 和 20 GB 的磁碟空間。

作業系統為 Debian 10。執行個體建立作業可能需要一至兩分鐘才能完成。

建立完畢後,請點選「SSH」登入在 Cloud 控制台中執行下列操作:

4bf915ef8d37c942.png

系統會開啟新的瀏覽器視窗,並將您帶往終端機。

安裝必備軟體

Magento 需要先安裝一些必要的軟體,才能執行 Magento。具體來說,您將按照下列說明安裝 PHP、Elastic、MySQL 和 Apache。

  1. 安裝某些必要套件。
sudo apt update

sudo apt -y install lsb-release apt-transport-https ca-certificates wget git screen composer google-cloud-sdk-spanner-emulator gcc
  1. 安裝 Magento 需要的 PHP 模組。
sudo wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg

echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/php.list

sudo apt update

sudo apt -y install php7.4-fpm php7.4-common php7.4-mysql php7.4-gmp php7.4-curl php7.4-intl php7.4-mbstring php7.4-xmlrpc php7.4-gd php7.4-xml php7.4-cli php7.4-zip php7.4-bcmath php7.4-soap php7.4-grpc
  1. 安裝 Elasticsearch 並啟動服務
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -

echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-7.x.list

sudo apt update && sudo apt -y install elasticsearch

echo "-Xms1g
-Xmx1g" | sudo tee /etc/elasticsearch/jvm.options.d/jvm.options

sudo systemctl start elasticsearch.service
  1. 安裝 MySQL

您正在安裝 MySQL,以便安裝預設的 Magento 結構定義。稍後,您會使用 HarbourBridge 將結構定義遷移至 Spanner。

wget https://dev.mysql.com/get/mysql-apt-config_0.8.13-1_all.deb

sudo dpkg -i mysql-apt-config*

上述 dpkg 指令會顯示互動式提示,讓您安裝 MySQL 5.7 伺服器。選取選項:

  • MySQL 伺服器與叢集
  • mysql-5.7
  • 確定

a018bfc2ee00bdf5.png 1a126e452ca7312e.png ae39c6f4bbe3be74.png

sudo apt update && sudo apt -y install mysql-server
# You will be prompted to enter a root password
  1. 安裝 Apache2
sudo apt -y install apache2

sudo a2enmod proxy_fcgi rewrite

安裝及設定 Magento2

Magento Commerce Cloud 專案提供資料庫結構定義和服務,可用於完整存取 Magento 網站和儲存庫。

如要安裝並執行這個程式,最簡單的方法就是按照 Magento 操作說明,使用 Composer 進行安裝:

  1. 使用 Composer 安裝 Magento 2.4.2 版。Magento 2 需要使用 Composer 1.x 版本。您可能會看到一些警告,說明這個版本的支援即將淘汰。
composer create-project --repository-url=https://repo.magento.com/ magento/project-community-edition=2.4.2 magento2
  1. 設定資料夾權限
cd magento2

find var generated vendor pub/static pub/media app/etc -type f -exec chmod g+w {} +

find var generated vendor pub/static pub/media app/etc -type d -exec chmod g+ws {} +
  1. 建立含有以下內容的 /etc/apache2/sites-available/magento.conf 以設定 Magento 虛擬主機。
sudo nano /etc/apache2/sites-available/magento.conf

<VirtualHost *:80>
        ServerAdmin admin@local-magento.com
        DocumentRoot /var/www/html/magento/

        <Directory /var/www/html/magento/>
                Options Indexes FollowSymlinks MultiViews
                AllowOverride All
                Order allow,deny
                allow from all
        </Directory>

        <FilesMatch \.php$>
               SetHandler "proxy:unix:/run/php/php7.4-fpm.sock|fcgi://localhost"
        </FilesMatch>

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
  1. 建立符號連結,然後重新啟動 apache2。
cd ~/magento2
sudo ln -s $(pwd) /var/www/html/magento 
sudo ln -s /etc/apache2/sites-available/magento.conf  /etc/apache2/sites-enabled/magento.conf
sudo rm /etc/apache2/sites-enabled/000-default.conf

sudo systemctl restart apache2
  1. 在 MySQL 建立 Magento 的資料庫和使用者
export ROOT_PASSWORD="<root password from installation>"
export GCE_INSTANCE_IP="<GCE instance IP>"
mysql -uroot -p$ROOT_PASSWORD -e "create database magento"

bin/magento sampledata:deploy

bin/magento setup:install --base-url=http://$GCE_INSTANCE_IP/ --db-host=localhost \
--db-name=magento --db-user=root --db-password=$ROOT_PASSWORD --admin-firstname=admin \
--admin-lastname=demo --admin-email=good@example.com --admin-user=admin \
--admin-password=magento123 --language=en_US --currency=USD --timezone=America/Chicago \
--use-rewrites=1

sudo chown -R :www-data ~/magento2/. 
  1. 驗證本機工作區 如要驗證本機環境是否代管伺服器,請使用您在安裝指令中傳遞的基準網址存取商店。在本例中,您可以使用以下網址格式存取本機 Magento 商店:
  • http://&lt;GCEexternalIP&gt;/
  • http://&lt;GCEexternalIP&gt;/&lt;adminuri&gt;

您可以在 Cloud 控制台中找到 GCEexternalIP:

3947f1164e1d5409.png

如要變更管理控制台的 URI,請使用下列指令找出面板:

php bin/magento info:adminuri
  1. 停用完整頁面快取 進行開發作業時,您可以停用 Magento2 的完整頁面快取。這樣就能修改 Spanner 中的資料,讓資料反映在網站上,而不會受到快取值的影響。
php bin/magento cache:disable full_page

設定 Spanner

安裝 Spanner 模擬器

Cloud SDK 提供本機記憶體內模擬器,可讓您免費開發及測試應用程式,不必建立 GCP 專案或帳單帳戶。由於模擬器僅將資料儲存在記憶體中,重新啟動時所有狀態 (包括資料、結構定義和設定) 都會遺失。模擬器提供的 API 與 Spanner 實際工作環境服務相同,適用於本機開發和測試,而非用於實際工作環境的部署作業。

請使用以下連結,進一步瞭解如何安裝、使用及部署模擬器:

使用 Spanner 模擬器

# Set up a new configuration to use the emulator
gcloud config configurations create emulator
gcloud config set auth/disable_credentials true
gcloud config set project magento
gcloud config set api_endpoint_overrides/spanner http://localhost:9020/

# Start emulator in a screen session
screen -S magento
gcloud emulators spanner start &
gcloud spanner instances create magento-instance --config=emulator-config --description='Magento Instance' --nodes=1

# Detach from screen 
ctrl+a+d

export SPANNER_EMULATOR_HOST=localhost:9010

將 Magento MySQL 遷移至 Spanner

在深入探討 Spanner 之前,我們會使用名為 HarbourBridge 的工具,將上方 Magento 安裝過程中建立的 MySQL 資料庫轉換為 Spanner。

本質上,HarbourBridge 提供自動化的工作流程,可將現有 MySQL 或 PostgreSQL 資料庫的內容載入 Spanner。而且無須設定,不必寫入資訊清單或資料對應。而是匯入來源資料庫、建構 Spanner 結構定義、建立新的 Spanner 資料庫 (填入來源資料庫的資料),並產生詳細評估報表。HarbourBridge 旨在載入高達數十 GB 的資料庫以供評估,而非完整遷移。

HarbourBridge 使用現有的 MySQL 或 PostgreSQL 來源資料庫,迅速啟動遷移至 Spanner 的早期階段,讓您迅速熟悉 Spanner 環境。這項工具會產生評估報告,內含 Spanner 的整體遷移健身狀況分數、以表格呈現的類型對應分析,以及 Spanner 不支援的來源資料庫中所用功能的清單。

HarbourBridge 可以與 Spanner 模擬器搭配使用,或直接搭配 Spanner 執行個體使用。

HarbourBridge README 內含逐步操作快速入門指南,可協助您搭配 Spanner 執行個體使用這項工具。

安裝 HarbourBridge

將該工具下載至您的電腦中,然後安裝。必須安裝 golang 才能運作。在未設定 Go 的情況下,可能需要一些時間才能在新的執行個體上安裝所有必要模組。

# Install golang
cd ~
wget https://golang.org/dl/go1.17.2.linux-amd64.tar.gz
sudo tar -zxvf go1.17.2.linux-amd64.tar.gz -C /usr/local
rm go1.17.2.linux-amd64.tar.gz

echo 'export GOROOT=/usr/local/go' | sudo tee -a /etc/profile
echo 'export PATH=/usr/local/go/bin:$HOME/go/bin:$PATH' | sudo tee -a /etc/profile
source /etc/profile

# Install harbourbridge
git clone https://github.com/cloudspannerecosystem/harbourbridge
cd harbourbridge
go run github.com/cloudspannerecosystem/harbourbridge help

遷移資料

使用下列指令,將 Magento 資料庫遷移至 Spanner:

mysqldump --user='root' --password=$ROOT_PASSWORD magento | go run github.com/cloudspannerecosystem/harbourbridge -driver=mysqldump -dbname=magento

設定 spanner-cli 工具

go install github.com/cloudspannerecosystem/spanner-cli@latest

3. 轉換 Magento 以搭配 Spanner 使用

現在 Magento 已開始運作,並遷移了透過 Magento 資料庫建立的 Spanner 執行個體,之後我們會設法修改 Magento,以處理 Spanner 中儲存的資料。

系統會執行下列步驟來轉換 Magento 安裝項目:

  • 複製 magento-spanner-port 專案
  • 變更 Spanner 的連線
  • 驗證目錄詳細資料是否已從 Spanner 填入

複製 Magento 專案的分支

複製 Magento 的 PHP 應用程式程式碼,其中包含了下列 Git 網址中目錄、願望清單和購物車模組的修改內容。

cd ~
git clone https://github.com/searceinc/magento-spanner-port

主目錄應如下所示:

$ ls
go  harbourbridge  magento-spanner-port  magento2

其中 magento2 是要修改的程式碼集,使用 magento-spanner-port 的程式碼。

變更 Spanner 的連線

如要檢查程式碼修改內容是否已反映在 UI 中,請按照下列步驟操作:

如需實作範例,請參閱 GitHub 連結 https://github.com/searceinc/magento-spanner-port

  • 需要 google/cloud-spanner PHP 用戶端程式庫
  • 新增 Spanner 轉接器,以連線至 Spanner。
  • 設定 Spanner 執行個體和伺服器資訊。
  • 在轉接程式中新增 SpannerInterface 和 Spanner,實作與 Spanner 的連線。

首先,我們需要使用 Composer 安裝 cloud-spanner PHP 程式庫。在 magento2 目錄中執行下列指令:

cd ~/magento2
composer require google/cloud-spanner

接著,我們會將 magento-spanner-port 中的 Spanner Adapter 檔案新增至 magento2 程式碼集:

~/magento2$ cp -r ../magento-spanner-port/lib/internal/Magento/Framework/DB/Adapter/Spanner vendor/magento/framework/DB/Adapter/.
~/magento2$ ls -l vendor/magento/framework/DB/Adapter/Spanner
total 16
-rw-r--r-- 1 derekdowney derekdowney 10378 Nov  9 21:03 Spanner.php
-rw-r--r-- 1 derekdowney derekdowney  2948 Nov  9 21:03 SpannerInterface.php

接著,請修改 DB/Adapter/Spanner/Spanner.php 檔案,為 $project_id、$instance$database 輸入 Spanner 連線資訊:

$ nano vendor/magento/framework/DB/Adapter/Spanner/Spanner.php

class Spanner implements SpannerInterface
{
    /**
     * Google cloud project id
     * @var string
     */
    private $project_id = 'magento';

    /**
     * Google cloud instance name
     * @var string
     */
    private $instance  = 'magento-instance';

    /**
     * Cloud Spanner database name
     * @var string
     */
    private $database  = 'magento';

    /**
     * Is Cloud Spanner emulator
     * @var bool
     */
    private $is_emulator = true;
...
   /**
    * Set database connection adapter
    *
    * @param \Magento\Framework\DB\Adapter\AdapterInterface $conn
    * @return $this
    * @throws \Magento\Framework\Exception\LocalizedException
    */
   public function setConnection(\Magento\Framework\DB\Adapter\AdapterInterface $conn)
   {
       $this->_conn = $conn;
       $this->_select = $this->_conn->select();
       $this->_isOrdersRendered = false;
       return $this;
   }


   /**
     * Set Cloud Spanner database connection adapter
     *
     * @return void
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    private function setSpannerConnection()
    {
        $this->_spanner_conn = new Spanner();
    }

現在可修改 Magento 中的 AbstractDB 類別,以便使用 Spanner 轉接器中新建立的 Connection 函式連線至 Spanner。在檔案的白線之後加入綠色線條。請參閱 vendor/magento/framework/Data/Collection/AbstractDb.php

$ nano vendor/magento/framework/Data/Collection/AbstractDb.php
...
use Psr\Log\LoggerInterface as Logger;
use Magento\Framework\DB\Adapter\Spanner\Spanner;
...
    protected $_conn;

    /**
     * Cloud Spanner connection
     *
     * @var \Magento\Framework\DB\Adapter\Spanner\SpannerAdapterInterface
     */
    protected $_spanner_conn;
...
       if ($connection !== null) {
            $this->setConnection($connection);
        }
        $this->setSpannerConnection();
        $this->_logger = $logger;
...
   /**
     * Retrieve connection object
     *
     * @return AdapterInterface
     */
    public function getConnection()
    {
        return $this->_conn;
    }

   /**
     * Retrieve connection object
     *
     * @return SpannerAdapterInterface
     */
    public function getSpannerConnection()
    {
        return $this->_spanner_conn;
    }
...

建立連線後,我們必須修改 MySQL 轉接器至 Spanner 轉換器中的資料擷取方法。修改 AbstractCollection 中的 _loadAttributes 方法,以連線至 Spanner 並從 Spanner 擷取資料。將紅線替換為綠色線條。

詳情請參閱 /app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php

$ nano ./vendor/magento/module-eav/Model/Entity/Collection/AbstractCollection.php

use Magento\Framework\Exception\LocalizedException;
use Google\Cloud\Spanner\SpannerClient;

...
               try {
                    if (is_array($selects)) {
                        $select = implode(' UNION ALL ', $selects);
                    } else {
                        $select = $selects;
                    }
                   $values = $this->getConnection()->fetchAll($select);
                   $con = $this->getSpannerConnection();

                    /**
                     * Cloud Spanner follows strict type so cast the columns in common type
                     */
                    $select = $con->addCast($select, "`t_d`.`value`", 'string');
                    $select = $con->addCast($select, "`t_s`.`value`", 'string');
                    $select = $con->addCast($select, "IF(t_s.value_id IS NULL, t_d.value, t_s.value)", 'string');
                    
                    $values = $con->fetchAll($select);

...

驗證目錄詳細資料是否已從 Spanner 填入

大功告成!現在您可以在瀏覽器中前往 Magento 安裝頁面,檢查資料是否正在載入。

舉例來說,以下是手錶的目錄項目:

13b54ba4482408fc.png

透過終端機修改其中一項產品的 Spanner 資料,並透過終端機查詢資料,確認 Spanner 中的修改內容。

$ spanner-cli -pmagento -i magento-instance -d magento
spanner> SELECT * FROM catalog_product_entity_varchar WHERE value LIKE "Aim Analog%";
+----------+--------------+----------+-----------+--------------------+
| value_id | attribute_id | store_id | entity_id | value              |
+----------+--------------+----------+-----------+--------------------+
| 390      | 73           | 0        | 36        | Aim Analog Watch |
+----------+--------------+----------+-----------+--------------------+
1 rows in set (80.711542ms)

spanner> UPDATE catalog_product_entity_varchar SET value = "Aim Analog Spanner" WHERE value_id=390;
Query OK, 1 rows affected (0.19 sec)

spanner> SELECT * FROM catalog_product_entity_varchar WHERE value_id=390;
+----------+--------------+----------+-----------+--------------------+
| value_id | attribute_id | store_id | entity_id | value              |
+----------+--------------+----------+-----------+--------------------+
| 390      | 73           | 0        | 36        | Aim Analog Spanner |
+----------+--------------+----------+-----------+--------------------+
1 rows in set (80.711542ms)

現在請重新載入畫面,確認手錶名稱現已變更為「Aim Analog Spanner」透過 Spanner 終端機更新

63a9c7b065c7051f.png

4. 恭喜

恭喜!您已成功連結 Magento 的 Catalog 模組,以便使用 Spanner!雖然並非完全整合,但您現在已經知道讓 Magento 等 PHP 應用程式連線至 Spanner 執行個體的元素。

清除所用資源

完成 POC 設定和驗證後,您可能需要刪除在此過程中建立的 GCP 資源。如果您決定使用 Compute Engine 虛擬機器和 Cloud Spanner 執行個體,而非模擬器,這些執行個體會包含在節點中。

後續步驟

這只是 Spanner POC 的原型模型。

如要進一步瞭解如何使用 Spanner 和我們在本程式碼研究室中採用的技術,請參考以下其他資源: