Magento와 Cloud Spanner 통합

1. 소개

424db48d9db91638.png

Magento를 Cloud Spanner 백엔드와 통합

Magento는 MySQL에 데이터를 저장하는 널리 사용되는 PHP 기반 오픈소스 전자상거래 플랫폼입니다.

이 Codelab은 카탈로그 모듈에 MySQL 대신 Cloud Spanner를 활용하는 개념 증명입니다. Magento 또는 기타 PHP 애플리케이션을 Spanner와 통합, 테스트, 배포하는 데 관심이 있는 모든 사용자에게 유용합니다.

Spanner는 Google Cloud에서 완전히 관리되고, 일관되고, 분산된 형태의 엔터프라이즈급 데이터베이스이며, 관계형 데이터베이스 모델의 이점과 비관계형 수평적 확장성을 결합할 수 있게 해줍니다. 전역 온라인 트랜잭션 처리 배포, SQL 의미 체계, 가용성이 높은 수평 확장, 트랜잭션 일관성을 지원하도록 설계되었습니다. Spanner는 대량의 데이터를 처리할 수 있습니다. 사용은 대규모 애플리케이션으로 제한되지 않지만 RDBMS가 필요한 모든 워크로드에 단일 데이터베이스 엔진을 표준화할 수 있습니다. Spanner는 계획된 유지보수 또는 리전 오류에 대해 99.999%SLA 가용성과 함께 제로 다운타임을 제공합니다. 고가용성과 확장성을 제공하여 최신 애플리케이션을 지원합니다.

학습할 내용

  • GCE에 Magento를 설치하는 방법
  • Spanner 에뮬레이터를 설정하는 방법
  • HarbourBridge를 사용하여 기존 MySQL 스키마를 Spanner로 마이그레이션하는 방법
  • 데이터베이스 백엔드에 MySQL을 사용하는 Magento와 같은 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로 변경합니다. 모든 항목을 기본값으로 둘 수 있지만 Magento의 웹 인터페이스를 활용하므로 'HTTP 트래픽 허용' 및 'HTTPS 트래픽 허용'을 선택해야 합니다.

이렇게 하면 공유 코어 인스턴스가 아니고 2vCPU, 8GB RAM, 20GB 디스크 공간이 있는 e2-standard-2 머신 유형이 생성됩니다.

운영체제는 Debian 10입니다. 인스턴스를 만드는 데 1~2분 정도 걸릴 수 있습니다.

생성되면 Cloud Console에서 'SSH'를 클릭하여 로그인합니다.

4bf915ef8d37c942.png

그러면 새 브라우저 창이 열리고 터미널에 배치됩니다.

기본 소프트웨어 설치

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을 설치합니다.

기본 Magento 스키마를 설치하기 위해 MySQL을 설치합니다. 나중에 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. 로컬 작업공간 확인 로컬 환경에서 서버를 호스팅하는지 확인하려면 설치 명령어에 전달한 기본 URL을 사용하여 스토어에 액세스합니다. 이 예시에서는 다음 URL 형식을 사용하여 로컬 Magento 스토어에 액세스할 수 있습니다.
  • http://<GCEexternalIP>/
  • http://<GCEexternalIP>/<adminuri>

GCEexternalIP는 Cloud Console에서 확인할 수 있습니다.

3947f1164e1d5409.png

관리자 패널의 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. Spanner와 연동되도록 Magento 변환

이제 Magento가 실행되고 Magento 데이터베이스가 마이그레이션된 Spanner 인스턴스가 생성되었으므로 Spanner에 저장된 데이터와 연동되도록 Magento를 수정하는 작업을 진행합니다.

Magento 설치를 변환하기 위해 다음 단계가 실행됩니다.

  • magento-spanner-port 프로젝트 클론
  • Spanner 연결 변경
  • 카탈로그 세부정보가 Spanner에서 채워지는지 확인

Magento 프로젝트의 포크 클론

아래에 언급된 Git URL에서 카탈로그, 위시리스트, 장바구니 모듈의 수정사항이 포함된 Magento용 PHP 애플리케이션 코드를 클론합니다.

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

홈 디렉터리는 다음과 같이 표시됩니다.

$ ls
go  harbourbridge  magento-spanner-port  magento2

여기서 magento2magento-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 에서 magento2 코드베이스로 Spanner 어댑터 파일을 추가합니다.

~/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 어댑터 내에서 새로 만든 연결 함수를 사용하여 Spanner에 연결합니다. 파일의 흰색 선 뒤에 녹색 선을 추가합니다. Refer to 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에서 데이터를 가져옵니다. 빨간색 선을 녹색 선으로 바꿉니다.

Refer to /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)

이제 화면을 새로고침하여 시계 이름이 Spanner 터미널을 통해 업데이트된 대로 'Aim Analog Spanner'로 변경되었는지 확인합니다.

63a9c7b065c7051f.png

4. 축하합니다

축하합니다. Magento의 카탈로그 모듈을 Spanner와 연동하도록 연결했습니다. 완전한 통합은 아니지만 이제 Magento와 같은 PHP 애플리케이션을 Spanner 인스턴스에 연결하는 요소를 알게 되었습니다.

삭제

POC 설정 및 유효성 검사가 완료되면 프로세스 중에 생성된 GCP 리소스를 삭제할 수 있습니다. 여기에는 Compute Engine 가상 머신과 에뮬레이터 대신 사용하기로 결정한 경우 Cloud Spanner 인스턴스가 포함됩니다.

다음 단계

이것은 Spanner POC의 프로토타입 모델일 뿐입니다.

Spanner 및 이 Codelab에서 활용한 기술에 관해 자세히 알아보려면 다음과 같은 추가 리소스를 참고하세요.