将psycopg2与Lambda一起使用来更新Redshift(Python)



我正试图使用python从Lambda函数更新Redshift。为此,我尝试将两个代码片段组合在一起。当我分别运行这两个片段时,它们都是有效的。

  1. 从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()
    
  2. 接收上传到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)

  1. 在您的机器中创建一个名为python的目录
  2. 不要从加载库psycopg2https://pypi.org/project/psycopg2-binary/,搜索正确的包(amazon-linux为86_64):psycopg2_binary-2.8.4-cp36-cp36m-manylinux1_x86_64.whl
  3. 将其解压缩到您创建的directorie python中,您可以使用7-zip作为.whl
  4. 压缩导演巨蟒
  5. 现在在AWS lambda面板中,使用python.zip创建一个层
  6. 最后将层添加到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网站安装了它。

  1. 请尝试在您的终端上安装pip install psycopg2
  2. pip-freeze(在包装目录之前重新打包目录中的模块)
  3. 上传到Lambda上。它对我很有效。尽管我不得不说这个模块只是一个创可贴解决方案

最新更新