我正试图使用python从Lambda函数更新Redshift。为此,我尝试将两个代码片段组合在一起。当我分别运行这两个片段时,它们都是有效的。
-
从PyDev为Eclipse 更新Redshift
import psycopg2 conn_string = "dbname='name' port='0000' user='name' password='pwd' host='url'" conn = psycopg2.connect(conn_string) cursor = conn.cursor() cursor.execute("UPDATE table SET attribute='new'") conn.commit() cursor.close()
-
接收上传到S3 Bucket的内容(Lambda上提供的预制模板)
from __future__ import print_function import json import urllib import boto3 print('Loading function') s3 = boto3.client('s3') def lambda_handler(event, context): #print("Received event: " + json.dumps(event, indent=2)) # Get the object from the event and show its content type bucket = event['Records'][0]['s3']['bucket']['name'] key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8') try: response = s3.get_object(Bucket=bucket, Key=key) print("CONTENT TYPE: " + response['ContentType']) return response['ContentType'] except Exception as e: print(e) print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket)) raise e
由于这两个部分都有效,我尝试将它们组合起来,以便在上传文件到s3:时更新Redshift
from __future__ import print_function
import json
import urllib
import boto3
import psycopg2
print('Loading function')
s3 = boto3.client('s3')
def lambda_handler(event, context):
#print("Received event: " + json.dumps(event, indent=2))
# Get the object from the event and show its content type
bucket = event['Records'][0]['s3']['bucket']['name']
key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')
conn_string = "dbname='name' port='0000' user='name' password='pwd' host='url'"
conn = psycopg2.connect(conn_string)
cursor = conn.cursor()
cursor.execute("UPDATE table SET attribute='new'")
conn.commit()
cursor.close()
try:
response = s3.get_object(Bucket=bucket, Key=key)
print("CONTENT TYPE: " + response['Body'].read())
return response['Body'].read()
except Exception as e:
print(e)
print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
raise e
由于我使用的是外部库,所以我需要创建一个部署包。我创建了一个新文件夹(lambda_function1),并将.py文件(lambda_function1.py)移动到该文件夹中。我运行以下命令在该文件夹中安装psycopg2:
pip install psycopg2 -t lambda_function1
我收到以下反馈:
Collecting psycopg2
Using cached psycopg2-2.6.1-cp34-none-win_amd64.whl
Installing collected packages: psycopg2
Successfully installed psycopg2-2.6.1
然后我压缩了目录的内容。并将该zip上传到我的lambda函数中。当我将文档上传到函数监视的bucket时,我在cloudwatch日志中收到以下错误:
Unable to import module 'lambda_function1': No module named _psycopg
当我在库中查找时,唯一名为"_psycopg"的是"_psycpg.pyd"。
是什么导致了这个问题?当我使用3.4时,Lambda使用Python 2.7有关系吗?我在Windows机器上压缩文件内容有关系吗?有人能够从lambda成功连接到Redshift吗?
为了实现这一点,您需要使用静态链接的libpq.so
库构建psycopg2
。查看此回购https://github.com/jkehler/awslambda-psycopg2.它已经构建了psycopg2包以及如何自己构建它的说明。
回到你的问题:
是什么导致了这个问题
psycopg2
需要使用Linux的静态链接库来构建和编译。
当我使用3.4时,Lambda使用Python 2.7有关系吗
是的,lambda只支持2.7版本。只需创建虚拟环境并在其中安装所有必要的软件包。
我在Windows机器上压缩文件内容有关系吗
只要你压缩的所有库都可以在Linux上运行,它就不会
有人能够从lambda成功连接到Redshift吗
是的。
我刚刚遇到了同样的问题。我偶然发现了另一个答案中提到的同一个github项目,该项目对问题的解释如下:
由于AWS Lambda在AMI映像中缺少所需的PostgreSQL库,我们需要使用PostgreSQL libpq.so库静态链接的libpq库而不是默认的动态链接来编译psycopg2
在前面的回答中已经注意到了这一点,我开始按照说明为自己构建一个带有静态链接的PostgreSQL库的psycopg2版本。不过我找到了一个更容易的选择。我在psycopg2 github页面上注意到以下内容:
您还可以通过从PyPI:安装psycopg2二进制包来获得一个独立的包,而不需要编译器或外部库
$ pip install psycopg2-binary
二进制包是开发和测试的实用选择,但在生产中,建议使用从源代码构建的包
当我pip安装psycopg2二进制包并将其包含在requirements.txt文件中时,我能够从lambda函数完美地连接到postgresql数据库。我正在使用我强烈推荐的圣杯。我意识到psycopg2建议不要在生产中使用二进制版本,但我认为使用二进制版本与自己编译和静态链接没有太大区别。如果我错了,请有人纠正我。
若要将psycopg2与aws lambda一起使用,请使用import-aws-psycopg2
由于aws支持psycopg2,但导入psycopg1的方式有点不同,因为aws本身有一个已编译的psycopg2库,所以我们需要导入的是使用aws-psycopg2
哦,天哪!而其中一些答案可能真的很棒,而且很有效!只是偶然发现了这个https://pypi.org/project/aws-psycopg2/它对我来说就像一种魅力。步骤:
mkdir aws-psycopg2
cd aws-psycopg2
vi get_layer_packages.sh
export PKG_DIR="python"
rm -rf ${PKG_DIR} && mkdir -p ${PKG_DIR}
docker run --rm -v $(pwd):/foo -w /foo lambci/lambda:build-python3.6
pip install -r requirements.txt --no-deps -t ${PKG_DIR}
vi要求.txt
aws-psycopg2
然后执行:chmod+x get_layer_packages.sh
/get_layer_packages.sh
zip-r aws-psycopg2.zip.
将此zip上传到AWS Lambda Layer!
这是我在尝试的所有方法中找到的最简单的方法:
我在需要psycopg2的lambda函数中添加了一个lamdba层。以下是可用Lambda层的列表:https://github.com/jetbridge/psycopg2-lambda-layer
我使用的是无服务器框架,这就是我的Lambda函数的样子:
functions:
example:
handler: handler.example
layers:
- arn:aws:lambda:us-east-1:898466741470:layer:psycopg2-py37:3
events:
- http:
path: example
method: post
authorizer: aws_iam
cors: true
在lambda上使用psycopg2的另一种方法(如果您在windows上编程,并在lambda中使用python 3.6)
- 在您的机器中创建一个名为python的目录
- 不要从加载库psycopg2https://pypi.org/project/psycopg2-binary/,搜索正确的包(amazon-linux为86_64):psycopg2_binary-2.8.4-cp36-cp36m-manylinux1_x86_64.whl
- 将其解压缩到您创建的directorie python中,您可以使用7-zip作为.whl
- 压缩导演巨蟒
- 现在在AWS lambda面板中,使用python.zip创建一个层
- 最后将层添加到lambda函数中
假设您的打包是正确的,no module named psycopg2
错误通常表示psycopg2部署的二进制文件对于您的目标操作系统或Python版本是不正确的。
对于Lambdas,我们发现psycopg2二进制文件可以工作(使用manylinux_x8_64)。据报道,由于存在相互竞争的libssl二进制文件,存在segfault的风险,尽管我们还没有这样做。(这基本上是上面jshammon回答的+1)
"正确的解决方案"可能是jkehlers专门为只缺少lib_pq.so
的Lambda重新编译,但它目前不支持ssl+py3.7,而且我们太Windows了,无法自己重新编译。
有这么多答案,但对我来说不起作用!请注意,AWS Lambda没有预装大多数与DB相关的库,因此您需要添加一个包含代码和库的zip
文件才能使其正常工作。请按照这里的步骤操作:链接
我已经阅读了一些解决方案,包括用户在Github上定制psychopg2模块的解决方案,但问题仍然存在。
我最近在Macbook上卸载了当前的psychopg2,然后去pip网站安装了它。
- 请尝试在您的终端上安装
pip install psycopg2
- pip-freeze(在包装目录之前重新打包目录中的模块)
- 上传到Lambda上。它对我很有效。尽管我不得不说这个模块只是一个创可贴解决方案