1

Sharding Counters의 this artice에서 가져온 다음 함수는 임의의 샤드가 증가되기 전에 선택되는 방법을 보여줍니다. 이것은 트랜잭션 내에서 발생합니다.트랜잭션 내의 샤드 된 카운터

def increment(): 
    """Increment the value for a given sharded counter.""" 
    def txn(): 
     index = random.randint(0, NUM_SHARDS - 1) 
     shard_name = "shard" + str(index) 
     counter = SimpleCounterShard.get_by_key_name(shard_name) 
     if counter is None: 
      counter = SimpleCounterShard(key_name=shard_name) 
     counter.count += 1 
     counter.put() 
    db.run_in_transaction(txn) 

은 하나의 트랜잭션이 한 번에 일어날 수있는 동시에 업데이트 할 수있는 다른 (임의) 분산됩니다 카운터를 방지하지 않을 것이라고? 그렇다면 한 번에 하나의 샤드 카운터 만 업데이트 할 수있는 경우 샤딩 카운터의 목적은 무엇입니까?

감사합니다.

답변

5

트랜잭션은 트랜잭션과 관련된 모든 엔티티를 잠급니다. 동일한 엔티티를 건드리지 않는 한 여러 트랜잭션을 진행할 수 있습니다.

각 샤드는 별도의 항목입니다. 이렇게하면 여러 샤드를 동시에 업데이트 할 수 있습니다.

트랜잭션이 이미 트랜잭션에있는 샤드 (임의 번호 생성기로 인해)에 도달하려고하면 트랜잭션이 실패합니다.

+0

트랜잭션이 실패하면, 좋지 않은 경우 실패하기 전에 몇 번 재 시도를 시도합니다 (이 경우 5 번). 결국이 경우 잠기지 않은 샤드를 성공적으로 선택해야합니다. –

+0

잘못된 : GAE의 트랜잭션은 잠금을 수행하지 않습니다. 즉, 트랜잭션이 커밋 될 때 내부 버전 필드를 확인하고 변경된 경우 (다른 사람이 동시에 값을 변경 한 경우) 예외를 throw하는 낙관적 동시성 제어를 사용합니다. https ://developers.google.com/appengine/docs/java/datastore/transactions#What_Can_Be_Done_In_a_Transaction –

+0

파이썬 API는 db.run_in_transaction을 통해 3 번 시도합니다. – Greg

3

아니요, 이것은 서로를 차단하지 않으며 쓰기 제한은 각 엔티티에만 별도로 적용됩니다.

이유 : SimpleCounterShard 엔티티에는 부모가 없습니다. 즉, 각 엔티티는 자체 엔티티 그룹의 루트입니다. 트랜잭션의 범위는 엔티티 그룹이며 동시 쓰기 제한이 엔티티 그룹에 적용됩니다.

+0

질문 : 분할 수 (해시)를 사용하여 GAE 엔터티의 고유 한 문자열 키로 사용할 수 있습니까? 특정 유형에 대해 생성 된 개수가 충돌하지 않습니다. \ – xybrek

+0

@xybrek 확실하지 않음 나는 이것을 이해하지만, 물론 충돌 할 것입니다. 동일한 카운트 값은 동일한 해시 값과 동일한 키를 생성합니다. 동일한 카운트 값을 가진 다른 카운터는 동일한 키를 생성하고 서로를 덮어 씁니다. 또한 충돌 없이도 어떻게 작동할까요? 카운터 값이 변경 될 때마다 새 엔터티를 만들 수 있습니까? –

+0

엔티티 ID가 1 (또는 적어도 아주 작은 긴 값)으로 시작해야하므로 카운터 값을 카운터 값으로 사용하지 말고 각 카운터 변경에 대해 새 엔티티를 생성하지 마십시오. GAE 매우 긴 값을 내 애플 리케이션의 목적을 패배 것입니다 생성 – xybrek