Tích hợp Magento với Cloud Spanner

1. Giới thiệu

424db48d9db91638.pngS

Tích hợp Magento với phần phụ trợ Cloud Spanner

Magento là một nền tảng thương mại điện tử nguồn mở dựa trên PHP phổ biến rộng rãi, giúp lưu trữ dữ liệu trong MySQL.

Lớp học lập trình này là một minh chứng về khái niệm để tận dụng Cloud Spanner thay vì MySQL cho mô-đun Danh mục. Điều này rất hữu ích cho những ai quan tâm đến việc tích hợp, thử nghiệm và triển khai Magento hoặc các ứng dụng PHP khác bằng Spanner.

Spanner là cơ sở dữ liệu được Google Cloud quản lý hoàn toàn, cấp doanh nghiệp, được phân phối và nhất quán, kết hợp lợi ích của mô hình cơ sở dữ liệu quan hệ với khả năng mở rộng theo chiều ngang không quan hệ. Room được thiết kế để hỗ trợ các hoạt động triển khai xử lý giao dịch trực tuyến trên toàn cầu, ngữ nghĩa SQL, khả năng mở rộng theo chiều ngang có độ sẵn sàng cao và tính nhất quán của giao dịch. Spanner có thể xử lý lượng lớn dữ liệu. Việc sử dụng API này không chỉ giới hạn ở các ứng dụng có kích thước lớn mà cho phép tiêu chuẩn hoá một công cụ cơ sở dữ liệu duy nhất cho tất cả các tải công việc đòi hỏi R DBM. Spanner cung cấp thời gian ngừng hoạt động bằng 0 cho các sự cố bảo trì theo kế hoạch hoặc lỗi khu vực, với SLA khả dụng là 99,999%. Công cụ này hỗ trợ các ứng dụng hiện đại bằng cách cung cấp khả năng mở rộng và khả năng hoạt động cao.

Kiến thức bạn sẽ học được

  • Cách cài đặt Magento trên GCE
  • Cách thiết lập Trình mô phỏng Spanner
  • Cách di chuyển giản đồ MySQL hiện có sang Spanner bằng HarbourBridge
  • Những gì bạn cần thay đổi để tích hợp các ứng dụng PHP như Magento sử dụng MySQL cho phần phụ trợ cơ sở dữ liệu để hoạt động với Spanner

Sản phẩm bạn sẽ tạo ra

Lớp học lập trình này tập trung vào việc tích hợp Magento với Spanner. Chúng tôi cung cấp các khối mã và hướng dẫn thiết lập để bạn sao chép và dán, nhưng không thảo luận chi tiết.

Trong lớp học lập trình này, bạn sẽ bắt đầu tích hợp Magento với Spanner. Bạn sẽ:

Bạn cần có

  • Một dự án Google Cloud được kết nối với một tài khoản thanh toán.
  • Có kiến thức về cấu hình PHP, Linux và Apache là một lợi thế.
  • Kinh nghiệm về Magento sẽ hữu ích nhưng không bắt buộc.

2. Đang chuẩn bị thực thể GCE

Tạo phiên bản GCE

Tạo một phiên bản Compute Engine trong Google Cloud Platform bằng cách làm theo các bước được đề cập tại đây.

Khi tạo phiên bản GCE, hãy thay đổi loại phiên bản thành e2-standard-2 và khởi động dung lượng ổ đĩa thành 20GB. Bạn có thể để mọi thứ theo mặc định, nhưng hãy nhớ chọn "Cho phép lưu lượng truy cập HTTP" và "Cho phép lưu lượng truy cập HTTP", vì chúng tôi sẽ tận dụng giao diện web của Magento.

Điều này dẫn đến loại máy e2-standard-2 không phải là phiên bản lõi dùng chung và có 2vCPU, RAM 8GB và dung lượng ổ đĩa 20GB.

Hệ điều hành là Debian 10. Quá trình tạo thực thể có thể mất vài phút.

Sau khi tạo gói này, hãy tiếp tục và đăng nhập bằng cách nhấp vào "SSH" trong Cloud Console:

4bf915ef8d37c942.pngS

Thao tác này sẽ mở một cửa sổ trình duyệt mới và đưa bạn đến một thiết bị đầu cuối.

Cài đặt phần mềm cần thiết

Magento sẽ cần cài đặt một số phần mềm tiên quyết trước khi chúng tôi có thể chạy Magento. Cụ thể, bạn sẽ cài đặt PHP, Elastic, MySQL và Apache như trình bày chi tiết bên dưới.

  1. Cài đặt một số gói bắt buộc.
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. Cài đặt các mô-đun PHP cần thiết cho Magento.
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. Cài đặt Elasticsearch và bắt đầu dịch vụ
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. Cài đặt MySQL

Bạn đang cài đặt MySQL để cài đặt giản đồ Magento mặc định. Sau đó, bạn sẽ di chuyển giản đồ sang Spanner bằng HarbourBridge.

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

sudo dpkg -i mysql-apt-config*

Lệnh dpkg ở trên sẽ hiển thị lời nhắc tương tác để cài đặt Máy chủ MySQL 5.7. Chọn các tuỳ chọn:

  • Cụm &Máy chủ MySQL
  • mysql-5.7
  • OK

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. Cài đặt Apache2
sudo apt -y install apache2

sudo a2enmod proxy_fcgi rewrite

Cài đặt và định cấu hình Magento2

Dự án Magento Commerce Cloud có một giản đồ cơ sở dữ liệu và các dịch vụ để truy cập đầy đủ vào trang web và cửa hàng của Magento.

Cách dễ nhất để cài đặt và chạy ứng dụng này là làm theo các hướng dẫn của Magento để cài đặt bằng trình soạn thảo:

  1. Cài đặt Magento phiên bản 2.4.2 bằng Compose. Magento 2 yêu cầu phiên bản composer 1.x. Bạn có thể thấy một số cảnh báo về việc ngừng hỗ trợ phiên bản này.
composer create-project --repository-url=https://repo.magento.com/ magento/project-community-edition=2.4.2 magento2
  1. Đặt quyền cho thư mục
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. Định cấu hình máy chủ ảo Magento bằng cách tạo /etc/apache2/sites-available/magento.conf với nội dung bên dưới.
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. Tạo đường liên kết tượng trưng và khởi động lại 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. Tạo cơ sở dữ liệu và người dùng cho Magento trong MySQL
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. Xác minh không gian làm việc cục bộ Để xác minh môi trường cục bộ đang lưu trữ máy chủ, hãy truy cập vào cửa hàng bằng URL cơ sở mà bạn đã truyền trong lệnh cài đặt. Trong ví dụ này, bạn có thể truy cập vào cửa hàng Magento cục bộ bằng cách sử dụng các định dạng URL sau:
  • http://<GCEexternalIP>/
  • http://<GCEexternalIP>/<adminuri>

Bạn có thể tìm thấy GCEexternalIP trong Cloud Console:

3947f1164e1d5409.png

Để thay đổi URI cho Bảng điều khiển quản trị, hãy sử dụng lệnh sau để tìm URI đó:

php bin/magento info:adminuri
  1. Tắt bộ nhớ đệm toàn trang Đối với mục đích phát triển, bạn có thể tắt bộ nhớ đệm toàn trang của Magento2. Việc này sẽ cho phép bạn sửa đổi dữ liệu trong Spanner và phản ánh dữ liệu trên trang web mà không bị ảnh hưởng bởi các giá trị đã lưu vào bộ nhớ đệm.
php bin/magento cache:disable full_page

Thiết lập Spanner

Cài đặt Trình mô phỏng Spanner

Cloud SDK cung cấp một trình mô phỏng cục bộ trong bộ nhớ. Bạn có thể sử dụng trình mô phỏng này trong bộ nhớ để phát triển và kiểm thử miễn phí các ứng dụng của mình mà không cần tạo Dự án GCP hoặc tài khoản thanh toán. Vì trình mô phỏng chỉ lưu trữ dữ liệu trong bộ nhớ, nên tất cả trạng thái, bao gồm cả dữ liệu, giản đồ và cấu hình, sẽ bị mất khi khởi động lại. Trình mô phỏng cung cấp các API giống như dịch vụ Spanner chính thức và dành cho việc phát triển và kiểm thử cục bộ, chứ không phải để triển khai chính thức.

Vui lòng sử dụng đường liên kết dưới đây để tham khảo thêm về cách cài đặt, sử dụng và triển khai Trình mô phỏng:

Sử dụng Trình mô phỏng 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

Di chuyển Magento MySQL sang Spanner

Trước khi đi sâu vào việc tích hợp Spanner, chúng ta sẽ sử dụng một công cụ có tên là HarbourBridge để chuyển đổi cơ sở dữ liệu MySQL được tạo trong quá trình cài đặt Magento ở trên thành Spanner.

Về cơ bản, HarbourBridge cung cấp quy trình công việc tự động để tải nội dung của cơ sở dữ liệu MySQL hoặc PostgreSQL hiện có vào Spanner. Phương thức này không yêu cầu cấu hình nào – không có tệp kê khai hoặc bản đồ dữ liệu nào cần ghi. Thay vào đó, lớp này sẽ nhập cơ sở dữ liệu nguồn, xây dựng giản đồ Spanner, tạo cơ sở dữ liệu Spanner mới có dữ liệu từ cơ sở dữ liệu nguồn và tạo báo cáo đánh giá chi tiết. BarrowBbridge dùng để tải cơ sở dữ liệu có kích thước lên đến vài chục GB cho mục đích đánh giá, chứ không phải để di chuyển trên quy mô đầy đủ.

Để nhanh chóng thiết lập và chạy trên Spanner, đơn vị khai thác của giúp khai thác những gì quý vị có thể thực hiện trong giai đoạn đầu của quá trình di chuyển sang Spanner bằng cách sử dụng cơ sở dữ liệu nguồn MySQL hoặc PostgreSQL hiện có. Công cụ này tạo một báo cáo đánh giá có điểm số tổng thể về khả năng di chuyển cho Spanner, một bản phân tích theo bảng về các mối liên kết kiểu và danh sách các tính năng được sử dụng trong cơ sở dữ liệu nguồn mà Spanner không hỗ trợ.

Bạn có thể sử dụng LayoutBrack với Trình mô phỏng Spanner hoặc sử dụng trực tiếp với phiên bản Spanner.

Tệp README của HarbourBridge chứa hướng dẫn bắt đầu nhanh từng bước để sử dụng công cụ này với một thực thể Spanner.

Cài đặt BarrowBrch

Tải công cụ xuống máy và cài đặt. Bạn phải cài đặt golang để tính năng này hoạt động. Có thể mất chút thời gian để cài đặt tất cả các mô-đun bắt buộc trên một thực thể mới mà không cần thiết lập Go trước đó.

# 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

Di chuyển dữ liệu

Sử dụng lệnh sau để di chuyển cơ sở dữ liệu Magento sang Spanner:

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

Thiết lập công cụ spanner-cli

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

3. Chuyển đổi Magento để hoạt động với Spanner

Hiện tại, chúng ta đã chạy Magento và phiên bản Spanner được tạo bằng cơ sở dữ liệu Magento đã di chuyển, chúng ta sẽ nghiên cứu việc sửa đổi Magento để làm việc với dữ liệu được lưu trữ trong Spanner.

Các bước sau đây sẽ được thực hiện để chuyển đổi bản cài đặt Magento:

  • Sao chép dự án magento-spanner-port
  • Thay đổi kết nối với Spanner
  • Xác thực rằng thông tin chi tiết về Danh mục nhạc được điền từ Spanner

Nhân bản nhánh của dự án Magento

Sao chép mã ứng dụng PHP cho Magento, trong đó chứa nội dung sửa đổi cho các mô-đun Danh mục, Danh sách yêu thích và Giỏ hàng từ URL Git được đề cập bên dưới.

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

Thư mục gốc của bạn sẽ có dạng như sau:

$ ls
go  harbourbridge  magento-spanner-port  magento2

Trong đó, magento2 là cơ sở mã mà chúng ta sẽ sửa đổi, sử dụng mã từ magento-spanner-port.

Thay đổi kết nối với Spanner

Để kiểm tra xem nội dung sửa đổi mã có được phản ánh trong giao diện người dùng hay không, chúng ta có thể làm theo các bước dưới đây:

Tham khảo đường liên kết GitHub https://github.com/searceinc/magento-spanner-port để triển khai mẫu.

  • Yêu cầu thư viện ứng dụng PHP google/cloud-spanner
  • Thêm Spanner Adapter để tạo kết nối với Spanner.
  • Định cấu hình thông tin máy chủ và thực thể Spanner.
  • Thêm SpannerInterface và Spanner vào Trình chuyển đổi để triển khai kết nối với Spanner.

Trước tiên, chúng ta cần cài đặt thư viện PHP cloud-spanner bằng trình soạn nhạc. Trong thư mục magento2, hãy chạy lệnh sau:

cd ~/magento2
composer require google/cloud-spanner

Sau đó, chúng ta thêm các tệp Bộ chuyển đổi Spanner từ magento-spanner-port vào cơ sở mã 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

Bây giờ, hãy sửa đổi tệp DB/Adapter/Spanner/Spanner.php để nhập thông tin kết nối Spanner cho $project_id, $instance$database:

$ 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();
    }

Sửa đổi lớp AbstractDB trong Magento để kết nối với Spanner bằng hàm Connection (Kết nối) mới tạo trong Spanner Adapter. Thêm các đường màu xanh lục sau các đường màu trắng trong tệp. Tham khảo 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;
    }
...

Sau khi thiết lập kết nối, chúng ta cần sửa đổi phương thức tìm nạp dữ liệu từ bộ chuyển đổi MySQL thành bộ chuyển đổi Spanner . Sửa đổi phương thức _loadAttributes trong AbstractCollection để kết nối với Spanner và tìm nạp dữ liệu từ Spanner. Thay thế dòng màu đỏ bằng các dòng màu xanh lục.

Tham khảo /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);

...

Xác thực rằng thông tin chi tiết về Danh mục nhạc được điền từ Spanner

Vậy là xong! Bây giờ, bạn có thể chuyển đến phần cài đặt Magento trong trình duyệt và kiểm tra để đảm bảo dữ liệu đang tải.

Ví dụ: đây là các mục trong danh mục cho đồng hồ:

13b54ba4482408fc.png.

Sửa đổi dữ liệu Spanner thông qua thiết bị đầu cuối cho một trong các sản phẩm và truy vấn dữ liệu thông qua thiết bị đầu cuối để xác nhận nội dung sửa đổi trong 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)

Lúc này, hãy tải lại màn hình để xác nhận rằng tên của đồng hồ hiện đã được đổi thành "Aim Analog Spanner" khi được cập nhật thông qua thiết bị đầu cuối Spanner.

63a9c7b065c7051f.png

4. Xin chúc mừng

Xin chúc mừng, bạn đã kết nối thành công mô-đun Catalog của Magento để hoạt động với Spanner! Đây chưa phải là một quá trình tích hợp đầy đủ, nhưng giờ đây bạn đã biết các yếu tố để tải một ứng dụng PHP như Magento kết nối với một phiên bản Spanner.

Dọn dẹp

Khi quá trình thiết lập và xác thực đầu mối liên hệ (POC) hoàn tất, bạn nên xoá các tài nguyên GCP đã tạo trong quá trình này. Điều này sẽ bao gồm Máy ảo Compute Engine cũng như một phiên bản Cloud Spanner nếu bạn quyết định sử dụng phiên bản này thay vì Trình mô phỏng.

Tiếp theo là gì?

Đây chỉ là mô hình nguyên mẫu cho POC Spanner.

Nếu bạn muốn tìm hiểu thêm về cách làm việc với Spanner và các công nghệ mà chúng tôi đã sử dụng trong lớp học lập trình này, hãy tham khảo thêm một số tài nguyên sau đây: