在 Python 中将 MySQL 与 AWS Lambda 结合使用时出现问题

新手上路,请多包涵

我正在尝试启动并运行 AWS Lambda Python(顺便说一句,Python 初学者),但在包含 MySQL 依赖项时遇到了一些问题。我正在尝试在我的 Mac 上按照 此处 的说明进行操作。

对于第 3 步,我在项目的根目录下执行命令时遇到了一些问题

sudo pip install MySQL-python -t /

错误:

异常:回溯(最近一次调用最后一次):文件“/Library/Python/2.7/site-packages/pip-1.5.6-py2.7.egg/pip/basecommand.py”,第 122 行,主状态 = self .run(options, args) 文件“/Library/Python/2.7/site-packages/pip-1.5.6-py2.7.egg/pip/commands/install.py”,第 311 行,运行 os.path。 join(options.target_dir, item) 文件“/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/shutil.py”,第 292 行,移动引发错误,“目标路径 ‘%s ’ 已经存在” % real_dst 错误:目标路径 ‘/MySQL_python-1.2.5-py2.7.egg-info/MySQL_python-1.2.5-py2.7.egg-info’ 已经存在

我最终编写了以下 lambda 函数(在我的 Mac 上运行良好),它是:

 import MySQLdb

def lambda_handler(event, context):
   # Open database connection
   db = MySQLdb.connect(...)

   # prepare a cursor object using cursor() method
   cursor = db.cursor()

   sql = "SELECT * FROM Users"

   try:
      # Execute the SQL command
      cursor.execute(sql)
      # Fetch all the rows in a list of lists.
      results = cursor.fetchall()
      for row in results:
         fname = row[0]
         lname = row[1]
         age = row[2]
         sex = row[3]
         income = row[4]
         # Now print fetched result
         print ("lname=%s" %(lname))
   except:
      print "Error: unable to fecth data"

   # disconnect from server
   db.close()

我接下来要做的是转到 /Library/Python/2.7/site-packages 并复制我执行 sudo pip install MySQL-python(没有 -t /)时下载的 MySQLdb 文件夹/文件(我是确定我在这里做错了什么)到我的 lambda 项目,然后将内容与 lambda_function.py 一起压缩并上传到 AWS Lambda。

然后我得到:

无法导入模块“lambda_function”:没有名为 MySQLdb 的模块

感谢您的帮助和建议!

编辑

能够做到 make sudo pip install MySQL-python -t /pathToProject 工作(感谢评论中的帮助)但现在我在运行 lambda 函数时得到了这个:

无法导入模块“lambda_function”:/var/task/_mysql.so:无效的 ELF 标头

我知道如果我在 Linux 机器上工作,那么它应该可以正常工作(正如一些人所建议的),但我想知道我是否可以让它在 OS X 机器上工作。

原文由 Guy Daher 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 838
2 个回答

对于像 Lambda 这样的用例,使用像 PyMySQL 这样的纯 python 实现会更快乐。

它是遵循 Python 数据库 API 规范的 MySQLdb 的替代品。对于大多数事情,比如触发的 Lambda 事件,它会一样快。

我在生产中经常使用它并且效果很好。

原文由 systemjack 发布,翻译遵循 CC BY-SA 3.0 许可协议

TLDR:是的,您可以在 AWS Lambda Python 函数中使用 mysqlclient

这是一种方法 - 通过为 mysqlclient 创建您自己的 AWS Lambda 层(即 MySQLdb )。

然后我得到 Unable to import module 'lambda_function': No module named MySQLdb

我知道如果我在 Linux 机器上工作,那么它应该可以正常工作(正如一些人所建议的),但我想知道我是否可以让它在 OS X 机器上工作。

在我的 AWS Lambda Python 函数中尝试 import MySQLdb 时,我也遇到了完全相同的错误。

经过大量搜索解决方案并且不满意使用 pymysql 作为替代品(出于性能和兼容性原因),我最终为 mysqlclient 构建了自己的 AWS Lambda 层。我找不到 mysqlclient 的“现成”层 - 即使在很棒的 KLayers 项目 中也找不到。我很高兴分享一个 GitHub 存储库,其中包含一个“现成”层示例和一个简单的解决方案,可以根据您的要求使用 AWS 推荐的程序构建您自己的自定义层。

mysqlclient (MySQLdb) 是围绕 MySQL API 的高性能 C 实现的 Python 包装器。这使得它通常比纯 python 实现快得多,例如 pymysql 在大多数情况下(请参阅 此列表 以获取一些示例),但它也会带来一些问题,例如您面临的问题。

Since it is compiled against the mysql-devel package (eg a .rpm or .deb file provided by MySQL), mysqlclient is linked to a platform -特定的二进制文件,例如 libmysqlclient.so 才能工作。换句话说,Mac OS 笔记本电脑(作为示例)中的 libmysqlclient.so 在撰写本文时使用某种形式的 Amazon Linux 2 的 AWS Lambda 环境中将无法工作。您需要一个 libmysqlclient.so 在 AWS Lambda 环境(或尽可能接近它)中编译并为它在您的 AWS Lambda 函数中工作。

lambci 以 Docker 镜像 的形式提供了一个严密模拟的 AWS-Lambda 环境。

因此,要打包一个 AWS-Lambda 兼容的 mysqlclient 你可以:

  • 拉一个合适的 docker 容器,例如 lambci/lambda:build-python3.8
  • 导入 MySQL 存储库 GPG 密钥
  • 安装 MySQL repo setup RPM 以便 yum 可以找到并下载其他 MySQL repo 包
  • yum install 必要的依赖关系,例如适当的 mysql-devel rpm 适用于您的用例
  • 在容器中运行 pip install mysqlclient
  • 压缩必要的 libmysqlclient.so 文件和mysqlclient的python lib目录

这或多或少是 AWS 官方推荐的程序:请参阅 如何使用带有 Docker 的模拟 Lambda 环境创建 Lambda 层? .

这样创建的 zip 可用于为 mysqlclient 创建一个新的 AWS Lambda 层。您可以使用该层轻松使用 mysqlclient 而不会在您的 Lambda 函数中出现任何错误。

经过大量的努力,我终于得到了完整的工作程序,并将其自动化到 这个 GitHub 项目 中的单个脚本 ( build.sh ) 中。该代码构建了一个 layer.zip 文件,您可以将其作为新的 AWS Lambda 层直接上传。该项目目前为 Python3.8 和 MySQL 服务器 8.0.x 构建,但可以使用提供的说明和工具轻松适应不同的 Python 版本和目标 MySQL 版本。回购中还有一个随时可用的 layer.zip 如果你想使用 mysqlclient 针对MySQL v8.0.x和Python 3.8(均经过测试) AWS Lambda 函数。我们的生产环境使用 SqlAlchemy,它使用这个 MySqlClient Lambda 层,它对我们来说效果很好。

在您将 Lambda 函数配置为使用按描述构建的层后(例如,使用上述存储库中的工具),您可以像往常一样在 Lambda 函数中使用 import MySQLdb 并继续编写您的真实代码:

 import MySQLdb

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': 'MySQLdb was successfully imported'
    }

希望这可以帮助。

原文由 nonbeing 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题