memcached是一款优秀的分布式key-value缓存框架。使用,集成简单方便。
但是对于如何优化数据库查询中,具体的使用方法网上相关的资源非常少。这里我给出自己摸索的经验方法与大家共享一下。
这里主要讲 如何给所有的表添加一种统一的使用缓存的办法,以及使用缓存使用中会为出现的问题,及统一的解决策略。
(以下是代码是基于python+Django,但其原理不限于此,但python语言的灵活强大在这里也可以得到很好的体现,试想要是在C++上实现这一切,就不是那么简单的一些事情)
首先我们假设创建了一个表User, 有id,name,password等荐,其中id为primary key,name为key.
1,基本的memcached使用方法
那么最简单的使用memcached的方法即为
cache.get('user_id_123')
cache.set('user_id_123', user )
2,何种查询使用memcached
这里只针对返回单条数据的查询做memcached,如果是返回集合的做cache,对于何时失效,如何失效的策略非常复杂,其开销也非常大,所以目前还没寻找到一个好的方法。所以这里只针对特定key的查询进行cache.
比如user这张表,可以定义按id进行查询,也可以按name进行查询。 又如有Item这张表,其构成为id,character_id,type,number. id为primary key, (character_id,type)为key.那么可以按id进行查询,也可以按(character_id,type)进行查询。像(character_id,type)这样的,我们可以称做侯选key。这种查询更接近于我们数据库的使用情况,做缓存的意义更大一些,也更加复杂,我们主要就是对其进行讨论。
后面我再详细说如何以统一的接口来定义侯选key.
3,如何为查询生成key
def makeKey( classA,*args,**kwargs):
endword = ""
keys = kwargs.keys()
keys.sort()
for key in keys:
endword +=
"_"+key
endword +=
"%s"%(kwargs[key])
return classA.__name__+endword
如MakeKey( User,name='123')返回 User_name_123
如MakeKey( Item,character_id=1,type=3)或( Item,type=3,character_id=1)都返回Item_character_id_1_type_3
4,统一的get方法
def getFromDBWithId( className,*args, **kwargs ):
key = makeKey(className,*args,
**kwargs )
value = cache.get(key )
if( not value ):
try:
value =
className.objects.get(*args,**kwargs )
except:
value = None
cache.set( key, value )
return value
5,何时添加缓存
get不命中时
insert时
6,何时缓存失效
在任何对缓存进行操作时,缓存失效:delete, update
7,update的注意事项
首先这里会有一个前提假设,即数据库的主健id不会发生变化。
即不能user = User(id=123)
user.id = 124
user.save()
一般我们在使用数据库时,都不会修改主健ID。对于侯选健我们一般也不会这样做。
如果侯选健不发生变化,那么update时的操作非常简单:cache.set(key,newValue),重新赋值即可。
如果侯选健发生变化,那上面的办法就行不通了。
试想user
= getFromDBWithId(User,name='xxx')
user.name ='ddd'
user.save()
如果用上面的方法,在查询 getFromDBWithId(User,name='xxx')时还会返回数据,而不是返回空
但即侯选健发生了变化,但主健id不会发生变化,我们也可以通过以下的方法来解决上面这个问题:
数据内容仅由id为key的来进行存储,侯选key存储的是与id的一个双向索引。
比如user = User( name='xxx'),其实在内存中有三部分构成:
1,cache.set('User_id_111',user)
2,cache.set('User_id_to_name_111','xxx')
3,cache.set('User_name_to_id_xxx',111)
这样我们再来看上面的情况
user = getFromDBWithId(User,name='xxx')
user.name ='ddd'
user.save()
在save时,我们这样处理,就不会有问题了:
1,oldName = cache.get('User_id_to_name_%s'%user.id) #
(oldName='xxx')
2,cache.invalide('User_name_to_id_%s'%oldName)
3,cache.set('User_id_to_name_%s'user.id,user.name)
4,cache.set('User_name_to_id_%s'%user.name,user.id)
5,cache.set('User_id_%s'%user.id,user)
8,统一加入缓存
上面我们给出了在User表上加入缓存的方法,当然我们不希望每个表都需要这样写一遍,高举DRY( do not reapeat yourself)的程序员肯定能想到更高明的办法。
切面编程?如果只需要写一个save()函数,然后注册的类,在更新表项时,都会被其改写,你只需要在外面配置哪些表需要加入cache,而完全不用从内部对其进行任务改写,这样会不会听上去很酷?
python切面编程的库有很多,我这里使用的aspects
1,这里我们需要每个表下定义一个CACHE_KEY(即我们的侯选key)
如
class User( models.Model ):
name = models.CharField( max_length=20 )
password = models.CharField( max_length=32 )
CACHE_KEY = ["name"]
我们来定义我们想重用的delete
def newDelete(self):
className = self.__class__.__name__
key = className
for subKey
in self.__class__.CACHE_KEY :
key
+= "_%s_"%subKey+str(getattr( self,subKey ))
cache.delete(key) #选移除缓存,再从数据库中移出
retval = yield aspects.proceed(self)
yield aspects.return_stop(retval)
定义新的Save(如果侯选key内容会变,可以参照第7点进行改动)
def newSave(self):
etval = yield aspects.proceed(self) #数据库执行update
className = self.__class__.__name__
key = className
for subKey in self.__class__.CACHE_KEY
:
key +=
"_%s_"%subKey+str(getattr( self,subKey ))
cache.set(key,self)
yield aspects.return_stop(retval)
搜索所有的表项,添加上hook
import aspects
allClasses = dir()
def registerHook():
global allClasses
for elem in allClasses:
if( globals().has_key(elem) ):
if(
"<class 'django.db.models.base.ModelBase'>" ==
str(type(globals()[elem]))):
aspects.with_wrap(newSave, getattr(globals()[elem],"save"))
aspects.with_wrap(newDelete, getattr(globals()[elem],"delete"))
(当然你也可以手动定义好,给固定的类加上cache )
9,加起来不到100行代码,你已经给你所有的数据库表项添加上了缓存。现在你可以去敲你老板的门了:我刚给数据库讲了一个笑话,它现在冷静了很多
分享到:
相关推荐
分布式数据库在现代互联网行业中...通过深入研究这三个分布式数据库系统,你可以为面试做好充分准备,同时也能在实际工作中更好地应对各种挑战。无论是开发、运维还是DBA,掌握这些知识都将使你在IT行业中更具竞争力。
Memcached是一种基于内存的键值存储系统,设计的目标是快速、简单地存储和检索数据。它通过将数据保存在内存中,避免了硬盘I/O操作,从而实现了极高的读取速度。由于内存的限制,Memcached不适合长期存储大量数据,...
它主要用于减轻数据库的负载,通过将数据暂存到内存中,实现快速读取。Memcached的特点包括轻量级、无持久化、单线程模型。在面试中,你可能需要了解其数据结构(如哈希表)、内存管理机制(如 slab allocator)以及...
在这个面试专题系列中,我们将聚焦于三个广受欢迎的分布式数据库技术:Memcached、Redis和MongoDB。 1. **Memcached**: - **简介**:Memcached是一款高性能、分布式内存对象缓存系统,用于减轻数据库负载,提升...
《深入理解memcached分布式缓存数据库部署》 memcached,作为一款高性能的分布式缓存服务器,它的主要任务是缓存数据库查询结果,从而减少对数据库的访问,进而提升动态Web应用的响应速度。这一技术的广泛应用,...
**memcached缓存数据库jar包** `memcached`是一种高性能、分布式内存对象缓存系统,它广泛用于减轻数据库负载,提高Web应用的响应速度。它通过在内存中存储数据,提供快速的数据访问,从而减少了对数据库的直接访问...
它减轻了数据库的压力,提供了快速的数据访问,同时在session管理方面提供了安全且高效的解决方案。企业可以根据自身需求选择合适的应用场景,结合其他技术如Redis,实现更灵活、更强大的数据缓存策略。在使用...
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的...
它设计用于通过网络在不同应用之间快速共享小块数据,如数据库查询结果。Memcached的工作原理是将数据存储在内存中,避免了频繁读写硬盘导致的I/O延迟,从而提高了数据访问速度。由于其简单的设计和高效的性能,...
Memcached是一款高性能、分布式内存对象缓存系统,常用于减轻数据库负载,提高Web应用的性能。它通过在内存中存储数据来快速...通过合理地利用memcached,开发者可以优化Web应用性能,减少数据库压力,提高用户体验。
是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。 以下是 memcached 在 Windows 系统下的 x86/x64 版本的安装方法。 命令提示符下运行 安装: memcached -d install memcached -d ...
Memcached是一款高性能、分布式内存对象缓存系统,广泛应用于Web应用中,用于减轻数据库的负载。它通过在内存中存储数据来提供快速的数据访问,从而提高应用的性能。本篇文章将详细讲解如何安装和配置memcached,...
总之,这个解决方案展示了如何巧妙地利用Java作为桥梁,使Oracle数据库能够与Memcached缓存服务协同工作,优化数据访问效率。这种集成技术是现代企业级应用中常见的实践,有助于构建更加高效和可扩展的系统。
通过学习这些资源,开发者能够更好地掌握如何在实际项目中应用Memcached和Hibernate的整合,提升系统的响应速度和并发处理能力。 此外,了解如何整合Memcached和Hibernate也是提升系统架构设计能力的重要一步。在高...
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的...
C#使用memCached实现缓存 Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来...Memcached将数据库负载大幅度降低,更好的分配资源,更快速访问。