我正在编写一个服务器应用程序,它必须每秒执行大量由连接客户端触发的MySQL查询,我想知道除了良好的结构化数据库之外,提高性能的最佳方法是什么。
我的想法是缓存一些数据,只发送缓存数据而不是执行新查询。就像数据库具有不同的表一样,缓存必须处理这些不同的“结构”(对象)。由于连接到服务器的客户端间接能够更改数据,因此我必须能够编辑缓存的数据(并且在某些时候能够更新我的数据库,但这不应该太困难)。这里列出了我需要做的事情:
我认为向量或队列/ priority_queue都是个好主意。这样我就可以为我想要缓存的每个表/对象创建一个队列或向量(没有执行任何测试,因为我想在我浪费时间之前获得更多意见)。存储在这些缓存结构中的最大对象大约为1千字节(最可能较小),最小可能为96字节。
每个缓存结构我不需要存储超过50,000个对象,我想我可以使用10种不同的结构(每个人都有不同的对象类型)。
最重要的部分是速度,否则我只能执行查询。这不仅仅是我必须进行查询,而是在之后创建一个新对象,而不是仅仅重用或重新发送旧对象。
所以这是我的问题:
编辑:哦,当我的意思是结构我不是指结构我只是不知道我应该如何引用矢量队列图等同时也许容器会更好:)
答案 0 :(得分:1)
有很多事情需要考虑,但总的来说,我会在Row Data Gateway模式(RDG)的基础上建立关系映射。如果没有太多不同的对象类型,这种架构方法应该足够好。如果您将缓存簿记限制在Finder类中,RDG应该可以促进您的缓存实现。
如果您有时间和意愿,请查看Patterns of Enterprise Application Architecture from Martin Fowler。这是一个很好的信息。
现在详细说明......
通常,您会在数据库中使用一些自动递增的整数列。您可以使用unordered_map快速从缓存中提取这些对象。由于缓存中包含所有对象,因此为了优化,您还可以实现一些find*
函数来首先搜索缓存。如果您的搜索时间受到严格限制,您可以使用unordered_map / unordered_multimap来“索引”某些数据,或者只是坚持使用旧的地图/多图。但是,这使工作量增加了一倍,并且您已经在数据库中免费获得了这些类型的查询。
在您实际将数据写入数据库之前,系统的其他部分不应看到脏数据。一旦你完成更新,如果一切按预期进行,你可以用你用于更新的缓存中的对象替换缓存中的对象,或者只是删除缓存中的对象,让其他读者从数据库中取出它(这将导致再次缓存对象)。您可以通过克隆原始的Gateway对象来实现这一点,但最重要的是您应该实现一些锁定策略。
在这里,您只需从缓存中删除对象,并尝试从数据库中删除。如果数据库中的删除失败,其他读者将缓存它。只需确保在删除过程中没有客户端可以访问相同的记录。添加新记录时,只需实例化Gateway对象,将其传递给域级对象,完成更改后,在Gateway对象上调用insert。您可以将新的Gateway对象放入缓存中,也可以让第一个读取器将其放入缓存中。
This is a matter of selecting the best caching algorithm.这不是一个容易回答的问题,但LRU应该可以正常工作。没有实际指标,没有正确的答案,但LRU很容易实现,如果它不符合您的要求,只需执行指标并确定新算法。确保通过良好的缓存接口可以无缝地完成此操作。另外要记住的是,您的域级别对象永远不应该依赖于缓存的限制。如果你需要100k的对象,但你只有50k的缓存,你仍然拥有内存中的所有100k对象,但其中有50k在缓存中。换句话说,你的对象不应该依赖于缓存的状态,也不应该关心你是否有缓存。
接下来,如果您仍然想到RDG的想法,那么您只是在缓存中缓存Gateway对象。您可以通过shared_ptr将Gateway对象的实例保留在缓存中,但如果您想避免脏写,还应该考虑锁定策略(乐观与悲观)。此外,所有网关(每个表一个)都可以继承相同的接口,因此您可以概括保存/加载策略,而且,您可以在保持简单的同时使用单个池。 (Check out boost::pool.也许它可以帮助你实现缓存。)
最后一点:
蛋糕是谎言! :D无论您决定做什么,请确保它基于相当数量的性能指标。如果你将性能提高了20%,而且你花了2个月的时间来做这件事,那么考虑为你的硬件添加更多的RAM可能是值得的。做一些简单的可验证的概念证明,这将为您提供足够的信息,无论是实现您的缓存付费,如果没有,请尝试一些现成的经过测试和可靠的解决方案(memcached等,如@Layne已经评论过)。