3

その後のAWSラムダ関数呼び出しでCassandraクラスタセッションを再利用しようとしています。私は正常にJavaで実装しましたが、Pythonでセッションを再利用すると、ラムダ呼び出しがタイムアウトになります(実際に初期化を実行する最初の呼び出しはOKです)。AWS LambdaでのCassandraデータベースセッションの再利用

CloudWatchログからは、Heartbeat failed for connectionが表示されます。セッションがアイドル状態では通信できず、接続を再開できない矛盾した状態になることがわかります。関数のタイムアウトより長いか短いかを試してみても、結果には何の影響もありません。ここで

は、私のラムダ関数(簡潔にするためにいくつかのコードを省略)の構造である:

import logging 
from cassandra_client import CassandraClient 

logger = logging.getLogger() 
logger.setLevel(logging.INFO) 

# State of the initialization phase 
flag = False 

# Cassandra instance 
cassandra = None 

def handle_request(event, context): 

    global flag, logger, cassandra 

    logger.info('Function started. Flag: %s' % (str(flag),)) 

    if not flag: 
     logger.info('Initialization...') 
     try: 
      cassandra = CassandraClient() 

      # ... 

      flag = True 

     except Exception as e: 
      logger.error('Cannot perform initialization: '+e.message) 
      exit(-1) 

    # Process the request ... 
    return 'OK' 

ただ、完全を期すために、それは私がクラスタとの接続を作成する方法は次のとおりです。

def _connect(self, seed_nodes=default_seed_nodes, port=default_port): 
    self.cluster = Cluster(seed_nodes, port=port) 
    self.metadata = self.cluster.metadata 
    self.session = self.cluster.connect() 
    # ... 

がありますいくつかのドライバの設定の詳細、私はそれが再利用されるセッションを防ぐことができないのpythonのラムダの動作?

私はAWS Lambdaは本当に素晴らしいツールだと思いますが、実行を制御していないと、何らかの形で混乱することがあります。どんな提案もありがとうございます。

+1

することを忘れないでください。それを制御するために '' flag''を使う必要はありません。しかし、それは単なるスタイルのポイントです、私はそれが問題を引き起こしているとは思わない。あなたのログは何を言いますか? – garnaat

+0

チップをありがとう、それは確かにもっと明らかになるでしょう。私はCloudWatchのログを調べ、各要求は「300.00秒後にタスクがタイムアウトしました」と終了します。私が試したクライアントの設定にもよりますが、私は 'Client request timeout 'も持っています。 Session.execute [_async](タイムアウト) 'と前述の' Heartbeat failed for connection'を参照してください。結果が常に一貫しているとは限りません。 – riccamini

+0

VPCでラムダ機能ですか?もしそうなら、カッサンドラクラスターは同じVPCに入っていますか? – garnaat

答えて

1

私は、この問題が、Python実行環境w.r.tを使用しているときのラムダの動作が違うことが原因であると考えることができます。 Java。

私は、単純なラムダ関数を設定する時間があり、両方ともJavaのPythonで実装されています。関数は現在の時刻をwhileループで出力するスレッドを生成します。問題は、ラムダ関数が返ってもJava実装のスレッドが印刷を続行し、逆にPythonスレッドが代わりに停止するかどうかです。答えはどちらの場合もyesです:Javaスレッドはタイムアウトが設定されるまで印刷を続けますが、ラムダ関数が返ってくるとすぐにPythonは停止します。

JavaバージョンのためのCloudWatchのログがあることを確認し:

09:55:21 START RequestId: b70e732b-e476-11e6-b2bb-e11a0dd9b311 Version: $LATEST 
09:55:21 Function started: 1485510921351 
09:55:21 Pre function call: 1485510921351 
09:55:21 Background function: 1485510921352 
09:55:21 Background function: 1485510921452 
09:55:21 Background function: 1485510921552 
09:55:21 Background function: 1485510921652 
09:55:21 Background function: 1485510921752 
09:55:21 Post function call: 1485510921852 
09:55:21 Background function: 1485510921853 
09:55:21 END RequestId: b70e732b-e476-11e6-b2bb-e11a0dd9b311 
09:55:21 REPORT RequestId: b70e732b-e476-11e6-b2bb-e11a0dd9b311 Duration: 523.74 ms Billed Duration: 600 ms Memory Size: 256 MB Max Memory Used: 31 MB 
09:55:21 Background function: 1485510921953 
09:55:22 Background function: 1485510922053 
... 

は、Pythonのバージョンにしながら:

09:01:04 START RequestId: 21ccc71e-e46f-11e6-926b-6b46f85c9c69 Version: $LATEST 
09:01:04 Function started: 2017-01-27 09:01:04.189819 
09:01:04 Pre function call: 2017-01-27 09:01:04.189849 
09:01:04 background_call function: 2017-01-27 09:01:04.194368 
09:01:04 background_call function: 2017-01-27 09:01:04.294617 
09:01:04 background_call function: 2017-01-27 09:01:04.394843 
09:01:04 background_call function: 2017-01-27 09:01:04.495100 
09:01:04 background_call function: 2017-01-27 09:01:04.595349 
09:01:04 Post function call: 2017-01-27 09:01:04.690483 
09:01:04 END RequestId: 21ccc71e-e46f-11e6-926b-6b46f85c9c69 
09:01:04 REPORT RequestId: 21ccc71e-e46f-11e6-926b-6b46f85c9c69 Duration: 500.99 ms Billed Duration: 600 ms Memory Size: 128 MB Max Memory Used: 8 MB 

ここでは2つの関数のコードがあります:

パイソン

import thread 
import datetime 
import time 


def background_call(): 
    while True: 
     print 'background_call function: %s' % (datetime.datetime.now(),) 
     time.sleep(0.1) 

def lambda_handler(event, context): 
    print 'Function started: %s' % (datetime.datetime.now(),) 

    print 'Pre function call: %s' % (datetime.datetime.now(),) 
    thread.start_new_thread(background_call,()) 
    time.sleep(0.5) 
    print 'Post function call: %s' % (datetime.datetime.now(),) 

    return 'Needs more cowbell!' 

のJava

import com.amazonaws.services.lambda.runtime.*; 


public class BackgroundTest implements RequestHandler<RequestClass, ResponseClass> { 

    public static void main(String[] args) 
    { 
     System.out.println("Hello World!"); 
    } 

    public ResponseClass handleRequest(RequestClass requestClass, Context context) { 
     System.out.println("Function started: "+System.currentTimeMillis()); 
     System.out.println("Pre function call: "+System.currentTimeMillis()); 
     Runnable r = new Runnable() { 
      public void run() { 
       while(true){ 
        try { 
         System.out.println("Background function: "+System.currentTimeMillis()); 
         Thread.sleep(100); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
     }; 
     Thread t = new Thread(r); 
     t.start(); 
     try { 
      Thread.sleep(500); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("Post function call: "+System.currentTimeMillis()); 
     return new ResponseClass("Needs more cowbell!"); 
    } 
} 
+0

これ以降、Pythonドライバのトラブルシューティングに時間を費やしたことがありますか? – Geotob

+0

@Geotob残念ながら私はしませんでした。私はこれについてAWSからフィードバックを得ることに失敗し、そのアイデアをあきらめました。 – riccamini

+0

@riccaminiありがとう、私は昨日一緒に遊んで、私はそれが働いていると思う:) – Geotob

0

同様の問題がWSGIアプリケーションは、グローバル接続プールでは動作しませんcassandra-driverのFAQにあります:それはかもしれない、あなたのアプリケーションプロセスのモデルによって

ドライバセッションが作成された後にフォークしてください。ほとんどのIOリアクタはこれを処理せず、問題はタイムアウトとして現れます。[ここ] [1]

これは、少なくとも利用可能な接続クラスを確認するために右のトラックに私を得た:それはcassandra.io.twistedreactor.TwistedConnectionはAWSラムダにかなりうまく機能していることが判明しました。あなたはしかし、あなたのvenvでtwistedをインストールする必要があります

from cassandra.cluster import Cluster 
from cassandra.io.twistedreactor import TwistedConnection 
import time 


SESSION = Cluster([...], connection_class=TwistedConnection).connect() 


def run(event, context): 
    t0 = time.time() 
    x = list(SESSION.execute('SELECT * FROM keyspace.table')) # Ensure query actually evaluated 
    print('took', time.time() - t0) 

:すべてのコードで

すべては次のようになります。

これを1分間のcrontabで実行したところ、接続エラーはわずか2回(1時間に最大2回)しか発生しませんでした。私は自分のアプリケーションにパッチを当て、それらのサルを持つことができないので

はまた、私は、eventletgevent基づいて接続をテストしていない、と私はまた、ラムダで使用するlibevをコンパイルするように感じることはありませんでした。他の人が試してみたいかもしれません。

は、あなただけのモジュールレベルでクラスタを初期化して、あなたのハンドラでそれを使用することができます http://datastax.github.io/python-driver/faq.html#why-do-connections-or-io-operations-timeout-in-my-wsgi-application