Google App Engine Datastore在Go语言中的分片

huangapple go评论91阅读模式
英文:

Google App Engine Datastore sharding in Go

问题

我在GAE中创建了一个分片,但有时候运行分片代码后会得到以下错误信息:

(datastore_v3: BAD_REQUEST): Key path element must not be incomplete: [ResumeShard: ]

代码如下:

//分片
//获取分片ID
rand.Seed(time.Now().UnixNano())
shardId := rand.Int63n(5)
resumeShardKey := datastore.NewKey(*pC, "ResumeShard", "", accountKey.IntID()+shardId, nil)

var resumeShard param.ResumeShard

if err = datastore.Get(*pC, resumeShardKey, &resumeShard); err != nil {

if err == datastore.ErrNoSuchEntity {
    resumeShard = param.ResumeShard{}
    resumeShard.Counter = 1
} else {
    log.Println(err.Error())
}

} else {
resumeShard.Counter += 1
}

*pC是指向来自appengine的上下文的指针。

accountKey是每个用户唯一的数据存储Key

这个错误是随机出现的,比如在10个请求中会出现3次。我想知道,因为我必须使用datastore.NewKey(..)为分片创建键,那么在调用Put(..)后我如何获取完整的键呢?因为这是分片,GAE文档中的示例也使用了datastore.NewKey(..)

请给予建议。

英文:

I have made a shard in GAE and only sometimes, not always got this message after running the sharding code.

(datastore_v3: BAD_REQUEST): Key path element must not be incomplete: [ResumeShard: ]

The code:

//Sharding
//Getting shard ID
rand.Seed(time.Now().UnixNano())
shardId := rand.Int63n(5)
resumeShardKey := datastore.NewKey(*pC, "ResumeShard", "", accountKey.IntID()+shardId, nil)

var resumeShard param.ResumeShard

if err = datastore.Get(*pC, resumeShardKey, &resumeShard); err != nil {

	if err == datastore.ErrNoSuchEntity {
		resumeShard = param.ResumeShard{}
		resumeShard.Counter = 1
	} else {
		log.Println(err.Error())
	}

} else {
	resumeShard.Counter += 1
}

*pC is a pointer to the context from appengine.

accountKey is a datastore Key unique to each user.

This error shows up randomly, like 3 times in 10 requests. I am wondering because I have to use datastore.NewKey(..) to create keys for shards, how can I get the complete key that I will receive after calling Put(..) since this is sharding and the example on GAE doc uses datastore.NewKey(..) as well.

Please suggest.

答案1

得分: 4

您收到一个错误,指出您提供的键是不完整的。这是因为您指定了一个空的键名("")(stringID),以及accountKey.IntID()加上一个随机数(范围为0..4,包括两个边界)作为数字键ID(intID)。请注意,如果您的accountKey.IntID()未初始化,它将为0,而随机数也可能为0,在这种情况下将使用0作为intID

引用自datastore.Key的文档:

stringIDintID中的一个或两个必须为零。如果两者都为零,则返回的键是不完整的。

获得intID0的机会是5分之1,即20%(这接近您报告的10分之3)。

intID的值为0是无效的,它必须是一个非零值,就像空字符串""一样,用于表示其他属性用于标识实体;或者 - 如果两者都是零值 - 表示键是不完整的键(因此希望系统分配随机的intID)。

请注意,这种解决方案不好,因为您使用具有_相对_数字ID(intID)的键,相对于帐户键(accountKey.IntID())的数字ID。系统分配的键将随机分布,但存在两个帐户键可能彼此接近的可能性(例如,一个是另一个的+1)。在这种情况下,您的分片键将重叠!

如果您使用datastore.Put()保存实体,系统分配的随机键是Put()的返回值:

func Put(c context.Context, key *Key, src interface{}) (*Key, error)
英文:

You get an error stating that the key you provide is incomplete. This is because you specify an empty key name ("") (stringID), and accountKey.IntID() plus a random number (from the range 0..4 - both inclusive) as the numeric key ID (intID). Note that if your accountKey.IntID() is not initialized, it will be 0 and the random number may also be 0 in which case a 0 is used as the intID.

And quoting from the doc of datastore.Key:

> Either one or both of stringID and intID must be zero. If both are zero, the key returned is incomplete.

The chance of getting 0 for the intID is 1 out of 5 which is 20% (this is close to your reported 3 out of 10).

A value of 0 for intID is invalid, it has to be a non-zero value as 0 is a special value just like the empty string "" for the stringID, both which are used to indicate that the other property is used to identify the entity; or - if both are the zero value - to indicate that the key is an incomplete key (and so system assigned random intID is wanted).

Please note that this solution is bad as you use keys with relative numeric ID (intID), relative compared to the numeric ID of the account key (accountKey.IntID()). System-assigned keys will be randomly distributed, but there is a chance that 2 account keys may be close to each other (e.g. one is the other +1). In such case your shard keys would overlap!

If you use datastore.Put() to save an entity, the system assigned random key is the return value of Put():

func Put(c context.Context, key *Key, src interface{}) (*Key, error)

huangapple
  • 本文由 发表于 2015年12月14日 19:25:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/34265862.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定