全部產品
Search
文件中心

Function Compute:訪問RDS MySQL最佳實務

更新時間:Apr 19, 2025

Function Compute中,不同的執行環境執行個體之間的狀態是不共用的,通過資料庫可以將結構化的資料持久化以實現狀態共用。通過Function Compute訪問雲上資料庫,您可以進行資料查詢和資料插入等操作。本文以Python函數為例,介紹如何同VPC或跨VPC跨地區訪問ApsaraDB RDS for MySQL

前提條件

操作步驟

步驟一:設定資料庫白名單

情境一:訪問同VPC內的RDS資料庫

如果您選擇訪問同VPC內資料庫的情境,請確保資料庫執行個體與函數處於同一地區。建議您在Function Compute支援的可用性區域建立資料庫執行個體。更多資訊,請參見Function Compute支援的可用性區域。如果您的資料庫執行個體不在Function Compute支援的可用性區域內,可以通過在您的VPC環境中建立一個與Function Compute相同可用性區域的vSwitch,並在函數的VPC配置中設定此vSwitch ID。由於同一VPC內不同vSwitch之間私網互連,因此Function Compute可以通過該vSwitch訪問在其他可用性區域的VPC內的資源。具體步驟,請參見遇到vSwitch is in unsupported zone的錯誤怎麼辦?

  1. 登入Function Compute控制台建立Python Web函數,為函數開通VPC訪問能力,並配置目標VPC資源。

    說明

    請確保為函數配置的VPC與資料庫執行個體綁定的VPC相同。

    image

  2. 在函數詳情頁,依次選擇配置 > 網路,然後在網路頁面擷取函數配置中的交換器網段。

    image

  3. 將上一步擷取的函數配置中交換器的網段添加到資料庫訪問白名單。

    重要

    請使用設定IP地址白名單方式授權函數訪問資料庫,請勿使用安全性群組方式。否則,可能導致函數偶爾串連不上資料庫的情況,影響業務正常運行。

    1. 訪問RDS執行個體列表,在上方選擇地區,然後單擊目標執行個體ID。

    2. 在左側導覽列,單擊白名單與安全性群組

      白名單設定頁面,可查看當前的IP白名單模式。

      說明

      較早建立的執行個體可能採用高安全模式。新建立的執行個體都採用通用白名單模式。

    3. 單擊default分組右側的修改,在彈出的修改白名單分組對話方塊中,將步驟2擷取的交換器IPv4網段配置在白名單中,然後單擊確定

      image

    完成配置後,函數可以通過資料庫內網地址訪問RDS資料庫。

情境二:跨VPC或跨地區訪問RDS資料庫

不同VPC和不同地區之間屬於完全的邏輯隔離,常規情況下不能跨VPC和跨地區訪問資料庫。如果需要跨VPC或跨地區訪問資料庫,可以通過為函數配置固定公網IP的方式,此時系統會在函數綁定的Virtual Private Cloud內建立公網NAT Gateway,通過公網網關即可實現通過公網IP訪問資料庫。

  1. 登入Function Compute控制台,在左側導覽列,選擇函數,選擇地區,然後根據介面提示建立函數

  2. 在函數詳情頁,依次選擇配置 > 網路,在網路面板,為函數配置固定公網IP,然後單擊部署

    image

  3. 在彈出的固定公網IP配置對話方塊,勾選提示框,然後單擊確定。配置完成後,將參數允許函數預設網卡訪問公網設定為,使配置的固定公網IP生效。

  4. 在函數詳情頁,依次選擇配置 > 網路,然後在網路頁面擷取函數配置的固定公網IP地址。

    image

  5. 將上一步擷取的函數固定公網IP地址添加到資料庫訪問白名單。

    重要

    請使用設定IP地址白名單方式授權函數訪問資料庫,請勿使用安全性群組方式。否則,可能導致函數偶爾串連不上資料庫的情況,影響業務正常運行。

    1. 訪問RDS執行個體列表,在上方選擇地區,然後單擊目標執行個體ID。

    2. 在左側導覽列,單擊白名單與安全性群組

      白名單設定頁面,可查看當前的IP白名單模式。

      說明

      較早建立的執行個體可能採用高安全模式。新建立的執行個體都採用通用白名單模式。

    3. 單擊default分組右側的修改,在彈出的修改白名單分組對話方塊中,將步驟2擷取的交換器IPv4網段配置在白名單中,然後單擊確定

      image

    完成配置後,函數可以通過資料庫公網地址訪問RDS資料庫。

步驟二:在函數中訪問RDS

  1. 登入Function Compute控制台,在函數列表找到目標函數,在函數詳情頁,單擊代碼頁簽,在代碼編輯器編寫如下範例程式碼。

    from flask import Flask, jsonify
    import pymysql
    import os
    from datetime import datetime
    import logging
    
    app = Flask(__name__)
    
    # 全域變數用於儲存 MySQL 單例串連
    _mysql_connection = None
    
    # 建立資料庫連接(單例模式)
    def getConnection():
        global _mysql_connection
        try:
            # 如果串連已經存在且未斷開,直接返回
            if _mysql_connection is not None:
                try:
                    # 測試連接是否有效(簡單命令測試)
                    with _mysql_connection.cursor() as cursor:
                        cursor.execute("SELECT 1")  # 簡單查詢測試連接狀態
                        result = cursor.fetchone()
                        if result and result[0] == 1:
                            return _mysql_connection
                except pymysql.OperationalError:
                    # 如果串連斷開,重設串連
                    _mysql_connection = None
    
            # 如果串連不存在或已斷開,重新建立串連
            _mysql_connection = pymysql.connect(
                host=os.environ['MYSQL_HOST'],
                port=int(os.environ['MYSQL_PORT']),
                user=os.environ['MYSQL_USER'],
                password=os.environ['MYSQL_PASSWORD'],
                db=os.environ['MYSQL_DBNAME']
            )
            return _mysql_connection
        except Exception as e:
            logging.error(f"Error occurred during database connection: {e}")
            raise
    
    
    @app.route('/', defaults={'path': ''})
    @app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
    def hello_world(path):
        conn = getConnection()
        try:
            with conn.cursor() as cursor:
                # 查詢 users 表的所有記錄,users 表需要根據實際表名進行修改
                sql = "SELECT * FROM users"
                cursor.execute(sql)
                result = cursor.fetchall()
                
                columns = [desc[0] for desc in cursor.description]  # 擷取欄位名列表
    
                # 將查詢結果轉換為字典列表
                users = []
                for row in result:
                    user = {}
                    for idx, column_name in enumerate(columns):
                        value = row[idx]
                        if isinstance(value, datetime):  # 處理日期類型欄位
                            user[column_name] = value.strftime('%Y-%m-%d %H:%M:%S')
                        else:
                            user[column_name] = value
                    users.append(user)
                    
                if users:
                    # 返回所有使用者的 JSON 響應
                    return jsonify(users), 200
                else:
                    # 如果沒有找到使用者,返回 404 錯誤
                    return jsonify({'error': 'No users found'}), 404
    
        except Exception as e:
            logging.error(f"Error occurred during database operation: {e}")
            return jsonify({'error': 'Database error'}), 500
    
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=9000)
    
    
  2. 在函數詳情頁,依次選擇配置 > 環境變數,單擊編輯,在環境變數面板配置以下環境變數。

    環境變數名稱

    環境變數值

    說明

    MYSQL_HOST

    rm-bp19u8e76ae****.mysql.rds.aliyuncs.com

    資料庫執行個體的訪問地址。

    • 如果您選擇同VPC內的RDS資料庫的情境,請將此環境變數值設定為資料庫的內網地址。

    • 如果您選擇跨VPC或跨地區訪問RDS資料庫的情境,請將此環境變數值設定為資料庫的外網地址。

    RDS執行個體列表,單擊目標RDS執行個體ID,然後在左側導覽列,選擇資料庫連接,在資料庫連接頁面擷取資料庫的內網地址或外網地址。

    MYSQL_DBNAME

    db_test

    RDS執行個體中建立的資料庫名稱。

    MYSQL_PASSWORD

    *****

    資料庫密碼。

    MYSQL_PORT

    3306

    資料庫執行個體的私網連接埠。

    MYSQL_USER

    dms_user_****

    RDS執行個體中建立的帳號名稱。

  3. 在函數詳情頁,選擇字碼頁簽,單擊測試函數,執行成功後查看返回結果,已成功完成查詢表格操作。

    image

更多資訊

  • 更多訪問RDS MySQL資料庫的樣本,請參見Function ComputePython訪問MySQL資料庫

  • 如果您的資料庫訪問失敗,需要根據問題現象進行排查,詳情請參見資料庫訪問失敗的常見原因

  • RDS支援MySQL、SQL Server、PostgreSQL和MariaDB引擎。更多資訊,請參見雲資料庫RDS簡介

  • 如果您希望使用Serverless Devs命令列工具建立函數並訪問RDS MySQL資料庫,請參見以下步驟。

    單擊此處查看Serverless Devs操作步驟

    1. 安裝Serverless Devs和Docker,並添加密鑰資訊。具體操作,請參見快速入門

    2. 建立代碼目錄mycode,準備s.yaml檔案和代碼檔案app.pys.yaml檔案樣本如下,範例程式碼請參見步驟二:在函數中訪問RDS提供的範例程式碼。

      以下s.yaml樣本適用於同VPC內訪問RDS資料庫的情境,如果需要跨VPC跨地區訪問資料庫,請參見情境二:跨VPC或跨地區訪問RDS資料庫

      # ------------------------------------
      #   官方手冊: https://manual.serverless-devs.com/user-guide/aliyun/#fc3
      #   常見小貼士: https://manual.serverless-devs.com/user-guide/tips/
      #   有問題快來DingTalk群問一下吧:33947367
      # ------------------------------------
      edition: 3.0.0
      name: hello-world-app
      access: "default"
      
      vars: # 全域變數
        region: "cn-hangzhou"  # 如果您選擇同VPC內訪問RDS資料庫的情境,請確保函數部署在與RDS資料庫相同的地區
      
      resources:
        hello_world:
          component: fc3 
          actions:       
            pre-${regex('deploy|local')}: 
              - component: fc3 build 
          props:
            region: ${vars.region}              
            functionName: "start-python-0t1m"
            runtime: custom.debian10
            description: 'hello world by serverless devs'
            timeout: 10
            memorySize: 512
            cpu: 0.5
            diskSize: 512
            code: ./code
            customRuntimeConfig:
              port: 9000
              command:
                - python3
                - app.py
            internetAccess: true
            vpcConfig:
             vpcId: vpc-bp1dxqii29fpkc8pw**** # 資料庫執行個體所在的VPC ID
             securityGroupId: sg-bp12ly2ie92ixrfc**** # 安全性群組ID
             vSwitchIds: 
              - vsw-bp1ty76ijntee9z83**** # 請確保該vSwitch對應的網段已配置到資料庫執行個體訪問白名單中
            environmentVariables:
              PYTHONPATH: /code/python
              PATH: /code/python/bin:/var/fc/lang/python3.10/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin
              MYSQL_HOST: rm-bp1j1y7657640z5****.mysql.rds.aliyuncs.com  # 資料庫執行個體的私網地址
              MYSQL_PORT: "3306"  # 資料庫執行個體的私網連接埠
              MYSQL_USER: dms_user_****  # 資料庫執行個體中建立的資料庫
              MYSQL_PASSWORD: ****   # 資料庫執行個體的密碼
              MYSQL_DBNAME: db_test  # 資料庫執行個體中建立的資料庫名稱
    3. 執行以下命令構建專案。

      sudo s build --use-docker
    4. 執行以下命令部署專案。

      sudo s deploy -y
    5. 執行以下命令調用函數。

      說明

      請確保您為函數配置的交換器網段或固定公網IP地址已添加到資料庫執行個體訪問白名單中。具體操作,請參見步驟3

      sudo s invoke -e "{}"