1

概括

我们的团队继承了这个使用 Cassandra 实现的序列生成器;

桌子

CREATE TABLE IF NOT EXISTS sequences (
  id_name varchar,
  next_id bigint,
  instance_name varchar,
  PRIMARY KEY (id_name)
)WITH COMPRESSION = { ... };

GET_LOCK("UPDATE sequences USING TTL 10 set instance_name = ?  where id_name = ? IF instance_name = null", ConsistencyLevel.LOCAL_QUORUM), 

SELECT_SEQUENCE("SELECT next_id from sequences where id_name = ?",
            ConsistencyLevel.LOCAL_QUORUM)

UPDATE_SEQUENCE("UPDATE sequences SET next_id= ? where id_name= ? IF next_id= ?",ConsistencyLevel.LOCAL_QUORUM), 

REMOVE_LOCK("UPDATE sequences set instance_name = null where id_name = ? IF instance_name = ?", ConsistencyLevel.LOCAL_QUORUM);

(note: ConsistencyLevel was set to LOCAL_SERIAL in Java)

它运行良好,直到昨天,我们发现两个不同的 java App 节点具有相同的序列号

发生这种情况的时间戳

AppNode 1

getlock:           4:25:14.480 
UpdateSequence:    4:25:14.486 

AppNode 2

getlock:           4:25:14,489
UpdateSequence:    4:25:14,496

这怎么可能发生?我们怎样才能知道到底发生了什么?

4

1 回答 1

1

一个可能的场景

  • next_idinstance_name如果由于到期而过期,任何实例都可以读取TTL
   SELECT_SEQUENCE("SELECT next_id from sequences where id_name = ?",
                   ConsistencyLevel.LOCAL_QUORUM)
  • 现在假设以下操作序列

    1. instanceOne设置锁---->instance_name=instanceOne
    2. instanceOne读取next_id值---->next_id=value1
    3. instanceOne有一些问题,它没有调用UPDATE_SEQUENCE10s
    4. 10秒过去了---->instance_name=null
    5. instanceTwo设置锁->instance_name=instanceTwo
    6. instanceOne读取相同的next_id值->next_id=value1
    7. 两个实例都尝试next_id使用相同的下一个值更新。但是根据此时的值instanceTwo成功,这是一个没有操作instanceOne
    8. 两个实例都尝试通过删除 .But 来解锁instance_name。但基于此时的值instanceTwo成功,这是一个无操作instanceOne
  • 不确定操作的时间戳。
    1. 一个问题是它们如何成功地与相同的值读取相关联
    2. 如果日志来自应用程序,它可以代表query attempted time而不是query execution time in Cassandra
于 2020-06-27T19:57:42.873 回答