2014-11-12 7 views
0

Новичок здесь (и кажется, что это может быть вопрос новичков). Использование Ubuntu 14.04 со свежей установкой Cassandra 2.1.1, CQL 3.2.0 (говорится). Запись базы данных для сайта CherryPy, изначально в качестве базы данных сеансов.Cassandra CQL UPDATE с IF

Я придумал схему для своего рода «блокировка строк» ​​ в качестве блокировки сеанса, но, похоже, она не висит вместе, поэтому я уменьшил ее до простой тестовой программы против местного Cassandra экземпляр. Чтобы запустить этот тест, я открываю два окна терминала, чтобы одновременно запускать два экземпляра python, каждый с разными номерами экземпляров («1» и «2»).

import time, sys, os, cassandra 
from cassandra.cluster  import Cluster 
from cassandra.auth   import PlainTextAuthProvider 
instance = sys.argv[1] 
cluster = Cluster(auth_provider=PlainTextAuthProvider(username='cassandra', password='cassandra')) 
cdb = cluster.connect() 
cdb.execute("CREATE KEYSPACE IF NOT EXISTS test WITH replication = {'class':'SimpleStrategy', 'replication_factor' : 1}") 
cdb.execute("CREATE TABLE IF NOT EXISTS test.test (id text primary key, val int, lock text)") 
cdb.execute("INSERT INTO test.test (id, val, lock) VALUES ('session_id1', 0, '') ") 
raw_input('<Enter> to start ... ') 

i = 0 
while i < 10000: 
    i += 1 
    # set lock 
    while True: 
     r = cdb.execute("UPDATE test.test SET lock = '%s' WHERE id = 'session_id1' IF lock = '' " % instance) 
     if r[0].applied == True: 
      break 
    # check lock and increment val 
    s0 = cdb.execute("SELECT val,lock FROM test.test WHERE id = 'session_id1' ")[0] 
    if s0.lock != instance: 
     print 'error: instance [%s] %s %s' % (instance, s0, r[0]) 
    cdb.execute("UPDATE test.test SET val = %s WHERE id = 'session_id1'", (s0.val + 1,))   
    # clear lock 
    cdb.execute("UPDATE test.test SET lock = '' WHERE id = 'session_id1' ")   
    time.sleep(.01) 

Так что, если я правильно понимаю, UPDATE..IF должен быть «прикладной» (и разрыв принято), только если текущее значение блокировки является «» (пустая строка), так что это должен дать эффективная эксклюзивная блокировка строки.

Проблема заключается в том, что тест 's1.lock != instance' довольно часто срабатывает, показывая, что, несмотря на UPDATE применяется значение замка впоследствии по-разному до сих пор «» или что в другом случае ...

Я знаю, что когда Я перехожу к кластеру, мне придется решать проблемы согласованности, но это противоречит единому локальному экземпляру Cass. Конечно, последовательность не должна быть проблемой здесь?

Я не могу представить, что эта форма CQL сломана (tm), так что это должен быть я. Что я делаю неправильно, или что я не понимаю? ТИА.

ОБНОВЛЕНИЕ: Хорошо, я много поработал над этим, прежде чем я разместил здесь, и теперь провел день с тех пор, как он сделал то же самое.

В частности, StackOverflow размещения Cassandra Optimistic Locking решает подобную проблему (по другой причине), и его решение было:

"update table1 set version_num = 5 where name = 'abc' if version_num = 4" 

, которые он говорит, работает для него - но на самом деле именно то, что я делаю , но который не работает для меня.

Так что я считаю, что мой подход звучит, но, очевидно, у меня проблема.

Есть ли какие-либо экологические проблемы, которые могут повлиять на меня? (Монтаж, вещий, независимо от ...)

ответ

0

Неудовлетворительно обходным найдено *

Перепробовав много вариаций тестового кода (выше), я пришел к мнению, что заявление:

"UPDATE test.test SET lock = '%s' WHERE id = 'session_id1' IF lock = '' " 

около 5% от времени он находит замок является «» (пустая строка), то на самом деле терпит неудачу, чтобы записать значение для блокировки, но тем не менее, возвращает «прикладной = True».

По пути дальнейшего тестирования, я изменил этот тестовый код следующим образом:

# set lock 
    while True: 
     r = cdb.execute("UPDATE test.test SET lock = '%s' WHERE id = 'session_id1' IF lock = '' " % instance) 
     if r[0].applied == True: 
      s = cdb.execute("SELECT lock FROM test.test WHERE id = 'session_id1' ") 
      if s[0].lock == instance: 
       break 
    # check lock and increment val 
    (etc) 

...так что этот код в настоящее время подтверждает, что замок был применен, и если нет, то возвращается попробовать еще раз ...

Так что это:

1) Horrible 
2) Kludgy 
3) Inefficient 
4) Totally reliable (the only thing that really matters to me) 

Я испытал это на «одного местного Cassandra instance ", и главное, что приращение столбца 'val', которое блокировка должна защищать, достигает соответствующего конечного значения (20000 с кодом, как указано выше).

Я также тестировал его на кластере из 2 узлов с коэффициентом репликации 2, причем один экземпляр тестового кода работает на каждом узле, и это тоже работает (хотя инструкция «UPDATE ... IF» , теперь с консистенцией Кворум иногда возвращает:

exception - code=1100 [Coordinator node timed out waiting for replica nodes' responses]\ 
    message="Operation timed out - received only 1 responses." \ 
    info={'received_responses': 1, 'required_responses': 2, 'write_type': 5, 'consistency': 8} 

... что требует тщательной обработки, как это кажется, что замок имеет всегда был установлен, несмотря на не получив все ответы ... и он не может быть повторен, поскольку операция не является идемпотентной ...)

Таким образом, я, очевидно, не исправил основные проблема, и хотя я исправил этот симптом, я по-прежнему ценю более глубокое понимание того, что происходит ...

Я был бы признателен за любую обратную связь (но, по крайней мере, я могу добиться прогресса еще раз). ТИА

+0

Я знаю, что это очень старое сообщение, и я, к сожалению, не проверил это сам, но простота в том, что с таким механизмом, когда ваше обновление гарантируется атомарностью с определенным синтаксисом - вам нужно сделать это с КАЖДОЙ вы выполняете. Вы не можете сделать «UPDATE .. SET ... IF ...», а затем запустить инструкцию сразу после нее без части «... IF ...», потому что что-то еще может изменить ее с тех пор. Снова я не тестировал, но из того, что я могу сказать, это источник проблем, которые вы описываете. –

0

Так что я имел некоторую связь с Тайлер Хоббс (Datastax), и в двух словах:

«Правильное функционирование механизма, который обеспечивает атомный тест-и-набор объекта (с помощью Lightweight сделок) зависит от использования того же механизма для очистки блокировки ».

... так что мне нужно использовать подобный «IF» построить, чтобы очистить его, хотя я уже знаю, содержимое ...

# clear lock 
cdb.execute("UPDATE test.test SET lock = '' WHERE id = 'session_id1' IF lock = '%s'" % instance) 

... и это работает.

Смежные вопросы