将 Magento 与 Cloud Spanner 集成

1. 简介

424db48d9db91638.png

将 Magento 与 Cloud Spanner 后端集成

Magento 是一个广受欢迎的基于 PHP 的开源电子商务平台,可将数据存储在 MySQL 中。

本 Codelab 是一个概念验证,旨在证明为目录模块使用 Cloud Spanner 而不是 MySQL。这对有兴趣将 Magento 或其他 PHP 应用与 Spanner 集成、测试和部署的任何人来说都很有用。

Spanner 是 Google Cloud 的全代管式企业级分布式一致数据库,它结合了关系型数据库模型与非关系型数据库横向扩缩能力的优势。它旨在支持全球范围的联机事务处理部署、SQL 语义、高可用性的横向扩缩和事务一致性。Spanner 能够处理大量数据。它不仅适用于大型应用,还允许为需要 RDBMS 的所有工作负载标准化单个数据库引擎。Spanner 为计划内维护或区域故障提供零停机时间,其可用性服务等级协议 (SLA) 为 99.999%。它提供高可用性和可伸缩性,支持现代应用。

学习内容

  • 如何在 GCE 上安装 Magento
  • 如何设置 Spanner 模拟器
  • 如何使用 HarbourBridge 将现有 MySQL 架构迁移到 Spanner
  • 为了集成 Magento 等将 MySQL 用于数据库后端的 PHP 应用,以便与 Spanner 搭配使用,您需要更改的内容

构建内容

此 Codelab 重点介绍如何将 Magento 与 Spanner 集成。我们会提供代码块和设置说明供您复制和粘贴,但不会详细讨论。

在此 Codelab 中,您将开始将 Magento 与 Spanner 集成。您将学习以下内容:

所需条件

  • 与结算账号关联的 Google Cloud 项目。
  • 熟悉 PHP、Linux 和 Apache 配置会加分。
  • 具备 Magento 使用经验会有帮助,但这不是硬性要求。

2. 准备 GCE 实例

创建 GCE 实例

按照此处所述的步骤,在 Google Cloud Platform 中创建 Compute Engine 实例。

创建 GCE 实例时,将实例类型更改为 e2-standard-2,并将启动磁盘大小更改为 20GB。您可以将所有内容保留为默认设置,但请务必选中“允许 HTTP 流量”和“允许 HTTPS 流量”,因为我们将使用 Magento 的网络界面。

这会产生机器类型 e2-standard-2,它不是共享核心实例,具有 2 个 vCPU、8GB RAM 和 20GB 磁盘空间。

操作系统为 Debian 10。创建实例可能需要一到两分钟。

创建完成后,请点击 Cloud 控制台中的“SSH”登录:

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 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. 验证您的本地工作区 要验证服务器是否由本地环境托管,请使用您在 install 命令中传递的基准网址访问商店。在本例中,您可以使用以下网址格式访问本地 Magento 商店:
  • http://<GCEexternalIP>/
  • http://<GCEexternalIP>/<adminuri>

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

3947f1164e1d5409

如需更改管理控制台的 URI,请使用以下命令找到它:

php bin/magento info:adminuri
  1. 停用整页缓存 出于开发目的,您可以停用 Magento2 的整页缓存。这样,您就可以修改 Spanner 中的数据,并使其反映在网站上,而不会受到缓存值的影响。
php bin/magento cache:disable full_page

设置 Spanner

安装 Spanner 模拟器

Cloud SDK 提供了一个本地内存模拟器,您可以使用该模拟器免费开发和测试应用,而无需创建 GCP 项目或结算账号。由于模拟器仅将数据存储在内存中,因此所有状态(包括数据、架构和配置)都会在重启时丢失。模拟器提供与 Spanner 生产服务相同的 API,旨在用于本地开发和测试,而不是用于生产部署。

请使用以下链接进一步了解模拟器的安装、使用和部署:

使用 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 填充 Catalog 详情

克隆 Magento 项目的分支

从下方提到的 Git 网址克隆 Magento 的 PHP 应用代码,其中包含对目录、愿望清单和购物车模块的修改。

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

您的主目录应如下所示:

$ ls
go  harbourbridge  magento-spanner-port  magento2

其中 magento2 是我们将使用 magento-spanner-port 中的代码修改的代码库。

更改与 Spanner 的连接

如需检查代码修改是否反映在界面中,我们可以按以下步骤操作:

如需查看示例实现,请参阅 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 填充 Catalog 详情

大功告成!现在,您可以在浏览器中前往 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!这并非完全集成,但您现在已经知道使 PHP 应用(如 Magento)连接到 Spanner 实例所需的要素。

清理

完成 POC 设置和验证后,您可能需要删除在此过程中创建的 GCP 资源。这包括 Compute Engine 虚拟机,以及 Cloud Spanner 实例(如果您决定使用该实例而非模拟器)。

后续操作

这只是一个 Spanner POC 的原型模型。

如果您想详细了解如何使用 Spanner 以及我们在此 Codelab 中利用的技术,请参阅下面列出的其他资源: