Những vấn đề phải xử lý khi move hệ thống từ server độc lập lên Load Balancer trên Cloud

Ở thời điểm hiện tại, khi Cloud Computing đã phát triển rộng rãi, thì trong quá trình phát triển hệ thống, đôi khi bạn thường gặp hai trường hợp sau:

  1. Hệ thống hiện tại có 1 Server Onpremis, giờ mong muốn chuyển lên Cloud với 2 Server, access thông qua Load Balancer.
  2. Hệ thống hiện tại đang là một Server (môi trường phát triển DEV or Staging hoặc thậm chí là Product) đặt trên Cloud, giờ muốn triển khai môi trường Product với 2 Server, access thông qua Load Balancer.

Giả sử ta làm việc với môi trường AWS, thì sẽ có hai loại Load Balancer phổ biến hay dùng là ELB (Elastic Load Blancer) và ALB (Application Load Balancer). Với bài toán trên ta phải xử lý các vấn đề như thế nào, trong bài viết này tôi sẽ cùng trao đổi chi tiết với các bạn.

Vấn đề về Session

Nếu cái hệ thống thần thánh của bạn không sử dụng Session hoặc lưu Session ở một nơi thứ 3 như DB hay Cache trung gian thì sẽ không vấn đề gì. Tuy nhiên nếu có xử lý Session và lưu ở chính Server thì khi chuyển lên ALB hay ELB cần phải chú ý đến vấn đề này đầu tiên. Lý do là vì Load Balancer sẽ điều hướng access đến các server dựa trên lưu lượng truy cập nên có thể có trường hợp đang làm việc với Session ở Server A nhưng lại điều hướng sang Server B, như vậy sẽ phát sinh việc mất Session và hiện tượng phổ biến là hệ thống sẽ Logout về màn hình Login.

Rất may phía AWS đã tính toán đến phần này giúp chúng ta rồi. Ở ELB hay ALB của AWS có cơ chế Sticky Session.

Khi enable Sticky Session ở trên Load Balancer, thì truy cập của Load Balancer sẽ được duy trì trên một Server cho đến khi tắt hẳn tab trên Browser hoặc close Browser.

Truy cập qua HTTP/HTTPS

Nếu hệ thống của bạn đơn thuần chỉ truy cập bằng HTTP thì chỗ này có thể bỏ qua, nhưng nếu hệ thống mà truy cập qua HTTPS, hoặc hỗn hợp có trang HTTP, có trang HTTPS thì khi chuyển sang Load Balancer đây sẽ là vẫn đề luôn phải xử lý.

Lý do chính là ở cái hình trên. Khi dùng Load Balancer thì thông thường từ phía người dùng có thể truy cập vào bằng HTTP hoặc HTTPS nhưng từ Load Balancer đi đến các Server thường là HTTP.

  1. Thông thường khi không qua Loadbalancer: Người dùng truy cập bằng HTTP/HTTPS, phía Server sẽ xử lý check nếu là HTTPS thì redirect sang HTTPS để đảm bảo luôn vào hệ thống bằng HTTPS.
  2. Khi dùng Load Balancer: Người dùng truy cập bằn HTTP/HTTPS, đi qua Load Balancer đến Server lại là HTTP. Nếu phía Server vẫn xử lý check HTTP như ở trường hợp 1 thì sẽ xảy ra tình trạng Loop (Trình duyệt sẽ trả về lỗi:  ERR_TOO_MANY_REDIRECTS), do từ Load Balancer đến Server luôn là HTTP.

Để giải quyết vấn đề này, Load Balancer của AWS có add thêm vào Header của Request từ Load Balancer đến Server một thuộc tính có tên là X-Forwarded-Proto để giúp Server phân biệt được Request từ phía người dùng là HTTP hay HTTPS. Dựa trên Header này phía Server có thể xử lý để Redirect trong Source Code tuy nhiên cách đơn giản nhất là thực hiện setting Rewrite URL ở trên Web Server.

Ví dụ với Web Server trên EC2 instance của AWS thì thực hiện các bước như sau:

  • STEP1:  Sửa file config /etc/httpd/conf.d/virtual.conf
  sudo vi /etc/httpd/conf.d/virtual.conf
  • STEP2: Add nội dung sau vào file :
<VirtualHost *:80>							
    ServerName Your_System_Domain_Name							
    RewriteEngine On							
    RewriteCond %{HTTPS} !=on				
    RewriteCond %{HTTP:X-Forwarded-Proto} !=https
    RewriteRule .* https://%{HTTP:Host}%{REQUEST_URI} [L,NE,R=permanent]		
</VirtualHost>
  • STEP3: Save file và khởi động lại Web Server:
 sudo systemctl stop httpd.service
 sudo systemctl start httpd.service

Link tham khảo: https://aws.amazon.com/premiumsupport/knowledge-center/redirect-http-https-elb/?nc1=h_ls

Xử lý Upload File lên Server

Thông thường khi upload file lên Server, thì file được lưu trên Server đó, Server còn lại thì lại không tồn tại file đó, nên cần có việc đồng bộ file giữa hai Server với nhau.

Giải pháp cho vấn đề này có hai cách:

  1. Lưu file Upload vào một nơi khác. Phổ biến là dùng AWS S3 hoặc AWS EFS, hoặc nếu ít file và dung lượng bé thì có thể lưu trực tiếp vào DB.
  2. Thực hiện copy file đồng bộ giữa hai Server mỗi khi thực hiện Upload.

Cách thứ nhất thì khá rõ ràng và đơn giản rồi. Với cách thứ hai thì cách thực hiện sẽ như sau:

  • STEP1: tạo một file Shell Script để thực hiện Copy file:
#!/bin/bash
##Copy file form local server to other server in the same Loadbalancer
##    $1: Server 1 IP
##    $2: Server 2 IP
##    $3: Server 2 Folder path
##    $4: Server 1 file path

LOCAL_IP=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1')

if [ "$1" == "$LOCAL_IP" ]; then
    if ssh server_login_user@$2 -p 10022 "test -e $4" ; then
        scp -P 10022 $4 server_login_user@$2:$3
    else
        scp -P 10022 $4 server_login_user@$2:$3
        ssh server_login_user@$2 -p 10022 "chmod 0777 $4"
    fi
elif [ "$2" == "$LOCAL_IP" ]; then
    if ssh server_login_user@$1 -p 10022 "test -e $4" ; then
        scp -P 10022 $4 server_login_user@$1:$3
    else
        scp -P 10022 $4 server_login_user@$1:$3
        ssh server_login_user@$1 -p 10022 "chmod 0777 $4"
    fi
fi

Ở file Script trên sẽ dùng lệnh scp (copy thông qua SSH) để copy file giữa hai server. Các bạn lưu ý địa chỉ của các Server sẽ là dùng Private IP, và trên AWS cần mở cổng SSH cho 2 Server thông được với nhau, ngoài ra cần setting để có thể thực hiện SSH giữa hai Server mà không cần phải dùng file PEM để authenticate.

Các bạn lưu ý “server_login_user” là user login vào thao tác được với Server.

  • STEP2:  Đặt file Script trên ở một thư mục giống nhau trên cả hai Server, Setting quyền có thể thực hiện cho file Shell Script này.
 sudo chmod +x /home/path_to_file/scp_file_to_other_server.sh
  • STEP3:  Trong source code của Server, sau khi thực hiện upload xong thì thực hiện chạy file Shell Script để copy file đến Server còn lại. Source PHP thực hiện sẽ kiểu như sau:
    /**
     * Secure copy file from [server 1] to [server 2]
     *
     * @param string $folderSave
     * @param string $fileName
     * @return type
     */
    private function scpFileToOtherServer($privateIpSer1, $privateIpSer2, $folderSave, $fileName) {
        $shellScript = Configure::read('path_of_script_copy_file');
        $pemFile = Configure::read('path_of_pem_file');
        $filePath = $folderSave . $fileName;

        // remove char [/]
        $folderSave = (mb_substr($folderSave, -1) == DS) ?
            mb_substr($folderSave, 0, mb_strlen($folderSave) - 1) : $folderSave;
        $command = "sudo -u server_login_user -S {$shellScript} {$privateIpSer1} {$privateIpSer2} {$folderSave} {$filePath} 2>&1";
        $output = shell_exec($command);
        if (!empty($output)) {
            $this->log(__FILE__ . '(' . __LINE__ . '): Copy fail, command: ' . $command);
            $this->log($output);
        }

        return $output;
    }

Trong quá trình thực hiện nội dung trên có thể sẽ gặp vấn đề liên quan đến việc setting quyền của user thực hiện. Các bạn cần phải setting quyền để cho user apache của Server có thể thực hiện được Shell script đó.

  • Edit file setting quyền cho user:
 sudo visudo
  • Thêm nội dung sau vào file:
Defaults!/home/path_to_file/scp_file_to_other_server.sh !requiretty
apache         ALL=(ALL)       NOPASSWD: /home/path_to_file/scp_file_to_other_server.sh *

Như thế là việc thực hiện copy file sẽ thực hiện được.

Một số vấn đề khác

Khi đưa Server độc lập lên Load Balancer bạn còn cần chú ý thêm một số vấn đề nhỏ nữa, ví dụ:

  1. Setting Session timeout cho Load Balancer: Dựa trên Session Timeout của hệ thống của bạn để setting phù hợp cho Load Balancer. Session Timeout của Load Balancer phải lớn hơn hoặc bằng giá trị time out của hệ thống.
  2. Setting Timeout cho Load Balancer. Default timeout của Load Balancer (AWS) thường là 60 giây. Nên nếu hệ thống Performance ko tốt, mất nhiều time trả lời Request thì sẽ dễ phát sinh lỗi [504 Gateway Time-out]. Cần tăng thời gian Timeout của Load Balancer lên để tránh lỗi này (Ví dụ sửa lên thành 180 giây).
  3. Hệ thống của bạn có thể sử dụng một số API của bên thứ ba và có trả phí. Có một số API sẽ giới hạn truy cập theo IP Global của Server. Do đó nếu bạn đưa thêm Server vào thì sẽ phải cần đăng ký địa chỉ IP Global của Server được thêm để có thể sử dụng được các API đó. Việc này có thể sẽ bị lack nên cần xử lý trước khi bạn chính thức chạy hệ thống với kiến trúc mới.

Kết luận

Các vấn đề xử lý trên không phải đơn giản, nhất là việc test đảm bảo hệ thống chạy đúng khi đã xử lý xong.  

Việc các hệ thống web chạy với Load Balancer là một điều rất phổ biến, nên ngay từ lúc thiết kế/ phát triển hệ thống các bạn nên chú ý đến vấn đề này để xử lý luôn thì đến lúc đưa các Server hệ thống lên Load Balancer trên Cloud sẽ rất đơn giản và không tốn nhiều công sức nữa.

Leave a Reply

Your email address will not be published. Required fields are marked *