为什么即使内部运作正常,我在AWS API Gateway中会收到“Forbidden”消息?

14
我已经设置了一个没有认证的公共端点的AWS API网关,它连接到一个触发Lambda的websocket。
我使用Python的websocket-client库https://pypi.org/project/websocket_client/创建连接。我注意到,连接会在10%的时间内失败,并且随着负载的增加而变得更糟。我找不到任何会限制我的地方,因为我的API网关通用设置显示“您当前的帐户级别限流率为每秒10000个请求,突发请求为5000个请求。”。即使每秒只有2-3个请求,也会经常触发问题。
与此同时,故障响应将类似于“{u'message': u'Forbidden', u'connectionId': u'Z2Jp-dR5vHcCJkg=', u'requestId': u'Z2JqAEJRvHcFzvg='}”。
我进入我的CloudWatch日志洞察并搜索连接ID和请求ID。API网关的日志组找不到任何具有任一ID的结果。然而,在我的Lambda上搜索websocket连接时,会有一个具有该连接ID的日志。日志显示我们这边一切都按预期运行。Lambda仅运行触发MySQL查询的操作。
尽管Lambda按预期工作,为什么会收到被禁止的响应?
现有的问题getting message: forbidden reply from AWS API gateway似乎是在讨论私有端点是否总是返回禁止。没有任何与我的使用情况相符的内容。
更新
我认为这可能与我正在使用的locust.io或Python有关。我在我的计算机上安装了https://www.npmjs.com/package/wscat并重复尽可能快地连接和关闭。我没有收到Forbidden消息。这仅令人困惑,因为我不确定我连接的方式如何会随机返回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来自于某些未命中实际routeKeyMESSAGE eventType。不确定它来自哪里,但很确定找到答案就能解决这个问题。

我还确认了没有ENI问题。

enter image description here

2个回答

4
你可能会遇到一些与VPC相关的限制。请参阅https://winterwindsoftware.com/scaling-lambdas-inside-vpc/。听起来你可能已经没有足够的ENIs了。您可以尝试将函数移动到另一个VPC中。每次Lambda调用运行多长时间?并且您的Lambda是使用哪种语言编写的?

我的超时时间设置为6秒。平均持续时间为70毫秒。由于我的测试每秒运行1-3次并遇到此问题,我可能会用尽ENI吗? - Dave Stein
我的当前限制是每个弹性网络接口的网络接口为350,VPC安全组为5。我的Lambda未保留帐户并发数为1000。 - Dave Stein
此外,我在启动过程中会从网关收到“Forbidden”错误,但这并不能解释为什么在成功后不到6秒内运行2次时会频繁出现“Forbidden”错误。 - Dave Stein
我看到这个有4个赞,但我没有达到任何限制。 AWS支持已经确认,肯定不是ENIs的问题。 我的最后更新显示routeKey问题,应该证实了这不是问题所在。 - Dave Stein

0

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

在我的正文中添加适当的 action 使得 403 错误消失了。这就是解决方案。本质上,我在连接和断开连接时得到了 200 响应,但是当没有有效载荷的消息通过时,我会得到 403 错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接