程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

暂无数据

GAE数据存储-写入次数多于读取次数的最佳实践

发布于2020-02-25 19:53     阅读(779)     评论(0)     点赞(21)     收藏(3)


我正在尝试对GAE数据存储进行一些练习,以对查询和计费机制有所了解。

我已经阅读了有关GAE的Oreilly书,并观看了有关数据存储区的Google视频。我的问题是,最佳实践方法通常涉及的是读取而不是写入数据存储区。

我构建了一个超级简单的应用程序:

  • 有两个网页-一个用于选择链接,一个用于查看链接
  • 每个用户都可以选择将网址链接添加到其“链接供稿”
  • 用户可以随时选择任意数量的链接。
  • 在另一个网页上,我想向用户显示他选择的最新10个链接。
  • 每个用户都有自己的“链接供稿”网页。
  • 在每个“链接”上,我要保存并显示一些元数据-例如:url链接本身;当它被选中时;它已经在Feed上出现了多少次;等等

在这种情况下,由于用户可以选择任意数量的链接,因此我的应用程序随时可以向数据存储写入数据,而读取次数远远大于读取次数(写-用户选择另一个链接时读-用户打开链接时读-网页上查看他的“链接供稿”)

问题1: 我可以想到(至少)两个选项如何处理此应用程序的数据:

选项A: -使用用户详细信息,注册等信息维护每个用户的实体-维护拥有他最近选择的10个链接的每个用户的另一个实体,该实体将在用户要求后呈现到用户的网页

选项B: -维护每个URL链接的实体-这意味着所有用户的所有URL都将存储为相同的对象-维护每个用户的实体的详细信息(与选项A中的相同),但在大处添加对用户URL的引用网址表

有什么更好的方法?

问题2: 如果我要计算直到今天为止选择的URL总数,或者用户选择的每日URL数量,或进行其他计数-我应该将其与我的SDK工具一起使用,还是应该在实体中插入计数器?如上所述?(我想尽可能减少数据存储的写入量)

编辑(回答@Elad的评论):假设我只想为每个用户保存10个最后一个URL。我想摆脱它们的其余部分(以免不必要的数据过多填充我的数据库)。

编辑2:添加代码后, 所以我尝试使用以下代码(尝试第一个Elad的方法):

这是我的课:

class UserChannel(db.Model):
currentUser = db.UserProperty()
userCount = db.IntegerProperty(default=0)
currentList = db.StringListProperty() #holds the last 20-30 urls

然后我将url和元数据序列化为JSON字符串,用户从第一页开始发布。POST的处理方式如下:

def post(self):
    user = users.get_current_user()
    if user:  
        logging messages for debugging
        self.response.headers['Content-Type'] = 'text/html'
        #self.response.out.write('<p>the user_id is: %s</p>' % user.user_id())            
        updating the new item that user adds
        current_user = UserChannel.get_by_key_name(user.nickname())
        dataJson = self.request.get('dataJson')
        #self.response.out.write('<p>the dataJson is: %s</p>' % dataJson) 
        current_user.currentPlaylist.append(dataJson)
        sizePlaylist= len(current_user.currentPlaylist)
        self.response.out.write('<p>size of currentplaylist is: %s</p>' % sizePlaylist)
        #whenever the list gets to 30 I cut it to be 20 long
        if sizePlaylist > 30:
            for i in range (0,9):
                current_user.currentPlaylist.pop(i)
        current_user.userCount +=1
        current_user.put()
        Updater().send_update(dataJson) 
    else:
        self.response.headers['Content-Type'] = 'text/html'
        self.response.out.write('user_not_logged_in')

其中Updater是我使用Channel-API更新包含提要的网页的方法。

现在,一切正常,我可以看到每个用户都有一个具有20-30个链接的ListProperty(当它达到30时,我使用pop()将其缩减为20),但是!价格非常高...每个POST都需要200毫秒,121 cpu_ms,cpm_usd = 0.003588。考虑到我要做的就是将一个字符串保存到列表中,因此这是非常昂贵的……我认为问题可能在于该实体随着大型ListProperty而变大了?


解决方案


首先,您不必担心会大量写入GAE数据存储-我自己的经验是,与读取相比,它们非常昂贵。例如,我的一个仅在单个模型表中插入记录就什么都没做的应用程序已经耗尽了免费配额,每天只有几十万次写入。因此,有效地处理写入将直接转化为您的底线。

第一个问题

我不会将链接存储为单独的实体。数据存储区不是RDBMS,因此标准规范化实践不一定适用。对于每个用户实体,使用ListProperty来存储最新的URL及其元数据(您可以将所有内容序列化为字符串)。

  • 由于您仅更新单个记录,因此这对写入非常有效-每当用户添加链接时,所有链接记录都不会更新。请记住,要保持滚动列表(FIFO)以及将引用URL存储为单独的模型,每个新URL都意味着两个写操作-一个新URL的插入,一个删除以删除最旧的URL。
  • 由于对用户记录的单次读取可以为您提供呈现用户供稿所需的所有数据,因此它的读取效率也很高。
  • 从存储的角度来看,世界上URL的总数远远超过了您的用户数(即使您成为下一个Facebook),用户选择的URL的变化也是如此,因此,平均URL可能具有一个用户-在RDBMS样式的数据规范化中没有真正的收获。

另一个优化思路:如果您的用户通常在短时间内添加多个链接,则可以尝试成批编写而不是分别编写。使用内存缓存来存储新添加的用户URL,并使用任务队列将该临时数据定期写入持久性数据存储中。我不确定使用Tasks的资源成本是多少-您​​必须检查一下。 这是一篇有关该主题的好文章

第二个问题

使用计数器。请记住,它们在分布式环境中并非无关紧要,因此请仔细阅读-有关该主题的许多GAE文章,食谱和博客文章-只是Google Appengine计数器同样在这里,使用memcache应该是一个不错的选择,以减少数据存储写入的总数。



所属网站分类: 技术文章 > 问答

作者:黑洞官方问答小能手

链接:https://www.pythonheidong.com/blog/article/233617/eee5b3cec5d94ce15eca/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

21 0
收藏该文
已收藏

评论内容:(最多支持255个字符)