即使事情在内部起作用,为什么我仍会从AWS API Gateway收到禁止消息?

时间:2019-05-17 21:17:03

标签: python websocket aws-lambda aws-api-gateway locust

我为没有身份验证的公共端点设置了AWS API网关。它连接到触发Lambda的网络套接字。

我正在与https://pypi.org/project/websocket_client/处的Python websocket-client库建立连接。

我注意到连接将在大约10%的时间内失败,并且随着负载的增加而变得更糟。我的通用API网关设置说Your current account level throttling rate is 10000 requests per second with a burst of 5000 requests.,我找不到任何让我感到烦恼的地方。除此之外,每秒只有2-3个请求经常会触发问题。

与此同时,失败响应类似于{u'message': u'Forbidden', u'connectionId': u'Z2Jp-dR5vHcCJkg=', u'requestId': u'Z2JqAEJRvHcFzvg='}

我进入了CloudWatch日志洞察,并搜索了连接ID和请求ID。 API网关的日志组将找不到任何一个ID的结果。但是,在我的Lambda上进行搜索(在websocket connect上触发)时,将带有该连接ID的日志。日志显示一切正常运行。 lambda只是运行一个将触发的MySQL查询。

尽管lambda可以按预期工作,但为什么我会得到禁止的回复?

getting message: forbidden reply from AWS API gateway处的现有问题似乎可以解决某些私有端点是否始终返回的问题。没有什么与我的用例一致。

更新

我认为这可能与我每秒用来连接的locust.io或python有关。我在机器上安装了https://www.npmjs.com/package/wscat,并且正在反复尽可能快地连接和关闭。我没有收到Forbidden消息。由于我不确定我的连接方式会随机地在一段时间内{em> 吐出一条Forbidden消息,这更加令人困惑。

class SocketClient(object):
    def __init__(self, host):
        self.host = host
        self.session_id = uuid4().hex

    def connect(self):
        self.ws = websocket.WebSocket()
        self.ws.settimeout(10)
        self.ws.connect(self.host)

        events.quitting += self.on_close

        data = self.attach_session({})
        return data

    def attach_session(self, payload):
        message_id = uuid4().hex
        start_time = time.time()
        e = None
        try:
            print("Sending payload {}".format(payload))
            data = self.send_with_response(payload)
            assert data['mykey']

        except AssertionError as exp:
            e = exp
        except Exception as exp:
            e = exp
            self.ws.close()
            self.connect()
        elapsed = int((time.time() - start_time) * 1000)
        if e:
            events.request_failure.fire(request_type='sockjs', name='send',
                                        response_time=elapsed, exception=e)
        else:
            events.request_success.fire(request_type='sockjs', name='send',
                                        response_time=elapsed,
                                        response_length=0)
        return data

    def send_with_response(self, payload):
        json_data = json.dumps(payload)

        g = gevent.spawn(self.ws.send, json_data)
        g.get(block=True, timeout=2)
        g = gevent.spawn(self.ws.recv)
        result = g.get(block=True, timeout=10)

        json_data = json.loads(result)
        return json_data
    def on_close(self):
        self.ws.close()

class ActionsTaskSet(TaskSet):
    @task
    def streams(self):
        response = self.client.connect()
        logger.info("Connect Response: {}".format(response))

class WSUser(Locust):
    task_set = ActionsTaskSet
    min_wait = 1000
    max_wait = 3000

    def __init__(self, *args, **kwargs):
        super(WSUser, self).__init__(*args, **kwargs)
        self.client = SocketClient('wss://mydomain.amazonaws.com/endpoint')

enter image description here

更新2

我已启用访问日志,这是以前不存在的一种日志。现在,我可以看到我的lambda总是得到200,没有问题。 403来自某些MESSAGE eventType,但没有达到实际的routeKey。不知道它来自哪里,但是很确定找到答案会解决这个问题。

我也能够确认没有ENI问题。

enter image description here

2 个答案:

答案 0 :(得分:4)

您可能会遇到一些与VPC相关的限制。参见https://winterwindsoftware.com/scaling-lambdas-inside-vpc/。听起来您可能已经用完了ENI。您可以尝试将功能移至其他VPC。 lambda的每次调用需要运行多长时间?而您的lambda用什么语言书写?

答案 1 :(得分:0)

在我的示例中,有效负载为空。 API已配置为使用$request.body.action来知道routeKey。连接使默认$connect路由起作用。

在我的体内添加适当的action使403s消失了。这是解决方案。从连接和断开连接的行为中我实际上得到了200条响应,但是每当没有有效负载的消息通过时,我都得到403。