2011-11-16 27 views
8

Cassandraで行キーに一意の制約を指定することが可能なときはいつでも知りたいと思います。 SQL ServerのようなものADD CONSTRAINT myConstrain UNIQUE (ROW_PK)Cassandra - 行キーのユニーク制約

既存の行キーを挿入すると、既存のデータは上書きされませんが、制約違反のために更新が実行できないような例外または応答が表示されます。

たぶん、この問題の回避策がある - カサンドラが書き込み上の任意のチェックを実行していないため、いや、

おかげで、

マチェイ残念ながら

答えて

7

アトミックである縫い目を更新カウンタがあります。このようなことを実現するためには、書き込みが許可されているかどうかを確認するために、すべての書き込みの前にCassandraが読み取りを行う必要があります。これにより、書き込みが大幅に遅くなります。 (全体の要点は、ディスクのシークを行うことなく書き込みが順次ストリームされるということです。このパターンを中断してシークを強制します)

カウンタが役立つとは思いません。カウンタは、アトミックなテストセットを使用して実装されていません。代わりに、基本的に多くのデルタが保存されます。これらのデルタは、カウンタ値を読み込むと同時に加算されます。

+0

ありがとう - これは私がそれを期待してきた方法です。他の誰かがそれを確認することもできますか?私は101%確信しています:) –

+0

あなたはもちろん、書き込みの束をして、あなたの制約に違反していないかどうかを確認することができます。しかし、それがあなたに役立つかどうかはわかりません。 –

+0

セオドアは正しいです。通常、一意性が必要な場合は、一意性を保証するUUIDまたは詳細の組み合わせを使用する必要があります。 –

2

明らかに、カサンドラでは、すべての書き込みは万人が&耐久性私たちはあなたのケースを考えると

を書き込みスケールする

  • Memtable
  • コミットログ

    1. には反映されません することができます。このカサンドラを行う前に

      1. Memtable
      2. すべてのケース2では
      3. すべてsstablesで存在するかどうかを確認[あなたのキーがMemtableからフラッシュされた場合]

      で存在するかどうかを確認する必要があるけれども、カサンドラはあり実装されたブルームフィルタはオーバーヘッドになります。すべての書き込みは読み取りになります&書き込み

      しかし、いつでもキーが1つのsstableに存在するため、要求によって、cassandraのマージオーバーヘッドが削減されます。しかし、カッサンドラのアーキテクチャを変える必要があります。

      Jusこのビデオhttp://blip.tv/datastax/counters-in-cassandra-5497678をチェックするか、このプレゼンテーションhttp://www.datastax.com/wp-content/uploads/2011/07/cassandra_sf_counters.pdfをダウンロードして、カスケードラの存在にカウンターがどのように入ってきたかを確認してください。

    4

    今日は良い感じ、私はそれだけでロックを作成するためにも、リモートで可能ではないことを言って他のすべてのポスターをdownvoteはありませんカッサンドラのクラスターだけです。私はLamportのベーカリーアルゴリズム¹を実装しましたが、うまく動作します。動物園、ケージ、メモ帳などの他の奇妙なものは必要ありません。

    代わりに、少なくともQUORUMの一貫性で読み書きを取得できる限り、貧しい人のマルチプロセス/マルチコンピュータロックメカニズムを実装できます。これは、このアルゴリズムを適切に実装するためには本当に必要なものです。 (QUORUMレベルは、必要なロックのタイプによって異なります:ローカル、ラック、フルネットワーク)

    私の実装はlibQtCassandra(C++)のバージョン0.4.7になります。私はすでにテストしており、完全にロックしています。私がテストしたいものがいくつかあります。今ではハードコーディングされている一連のパラメータを定義させることができます。しかし、このメカニズムは完全に機能します。

    このスレッドを見つけたら、何かが間違っていると思っていました。私はさらにいくつかを検索し、以下に述べるApacheのページを見つけました。ページはそれほど先進的ではありませんが、彼らのMoinMoinはディスカッション・ページを提供していません...とにかく、言及する価値があったと思います。うまくいけば、人々はPHP、Ruby、Javaなどのあらゆる種類の言語でそのロック機構を実装し始めるでしょう。

    出典:http://wiki.apache.org/cassandra/Locking

    以下は、私は私のバージョンを実装し、多かれ少なかれ方法ですhttp://en.wikipedia.org/wiki/Lamport%27s_bakery_algorithm

    を¹しました。これは単純な概要です。結果のコードをテストしながら(実際のコードではRAIIを使用し、TTLの上にタイムアウト機能を追加しています)、いくつかの機能拡張を行ったので、もう少し更新する必要があります。最終バージョンはlibQtCassandra libraryにあります。

    // lock "object_name" 
    void lock(QString object_name) 
    { 
        QString locks = context->lockTableName(); 
        QString hosts_key = context->lockHostsKey(); 
        QString host_name = context->lockHostName(); 
        int host = table[locks][hosts_key][host_name]; 
        pid_t pid = getpid(); 
    
        // get the next available ticket 
        table[locks]["entering::" + object_name][host + "/" + pid] = true; 
        int my_ticket(0); 
        QCassandraCells tickets(table[locks]["tickets::" + object_name]); 
        foreach(tickets as t) 
        { 
         // we assume that t.name is the column name 
         // and t.value is its value 
         if(t.value > my_ticket) 
         { 
          my_ticket = t.value; 
         } 
        } 
        ++my_ticket; // add 1, since we want the next ticket 
        table[locks]["tickets::" + object_name][my_ticket + "/" + host + "/" + pid] = 1; 
        // not entering anymore, by deleting the cell we also release the row 
        // once all the processes are done with that object_name 
        table[locks]["entering::" + object_name].dropCell(host + "/" + pid); 
    
        // here we wait on all the other processes still entering at this 
        // point; if entering more or less at the same time we cannot 
        // guarantee that their ticket number will be larger, it may instead 
        // be equal; however, anyone entering later will always have a larger 
        // ticket number so we won't have to wait for them they will have to wait 
        // on us instead; note that we load the list of "entering" once; 
        // then we just check whether the column still exists; it is enough 
        QCassandraCells entering(table[locks]["entering::" + object_name]); 
        foreach(entering as e) 
        { 
         while(table[locks]["entering::" + object_name].exists(e)) 
         { 
          sleep(); 
         } 
        } 
    
        // now check whether any other process was there before us, if 
        // so sleep a bit and try again; in our case we only need to check 
        // for the processes registered for that one lock and not all the 
        // processes (which could be 1 million on a large system!); 
        // like with the entering vector we really only need to read the 
        // list of tickets once and then check when they get deleted 
        // (unfortunately we can only do a poll on this one too...); 
        // we exit the foreach() loop once our ticket is proved to be the 
        // smallest or no more tickets needs to be checked; when ticket 
        // numbers are equal, then we use our host numbers, the smaller 
        // is picked; when host numbers are equal (two processes on the 
        // same host fighting for the lock), then we use the processes 
        // pid since these are unique on a system, again the smallest wins. 
        tickets = table[locks]["tickets::" + object_name]; 
        foreach(tickets as t) 
        { 
         // do we have a smaller ticket? 
         // note: the t.host and t.pid come from the column key 
         if(t.value > my_ticket 
         || (t.value == my_ticket && t.host > host) 
         || (t.value == my_ticket && t.host == host && t.pid >= pid)) 
         { 
          // do not wait on larger tickets, just ignore them 
          continue; 
         } 
         // not smaller, wait for the ticket to go away 
         while(table[locks]["tickets::" + object_name].exists(t.name)) 
         { 
          sleep(); 
         } 
         // that ticket was released, we may have priority now 
         // check the next ticket 
        } 
    } 
    
    // unlock "object_name" 
    void unlock(QString object_name) 
    { 
        // release our ticket 
        QString locks = context->lockTableName(); 
        QString hosts_key = context->lockHostsKey(); 
        QString host_name = context->lockHostName(); 
        int host = table[locks][hosts_key][host_name]; 
        pid_t pid = getpid(); 
        table[locks]["tickets::" + object_name].dropCell(host + "/" + pid); 
    } 
    
    // sample process using the lock/unlock 
    void SomeProcess(QString object_name) 
    { 
        while(true) 
        { 
         [...] 
         // non-critical section... 
         lock(object_name); 
         // The critical section code goes here... 
         unlock(object_name); 
         // non-critical section... 
         [...] 
        } 
    }