使用hashmap做缓存MongoDB 有没有必要用 Memcached 做缓存

235被浏览37640分享邀请回答2添加评论分享收藏感谢收起查看: 10043|回复: 4
使用 MongoDB 有没有必要用 Memcached 做缓存?
论坛徽章:0
使用 MongoDB 有没有必要用 Memcached 做缓存?
论坛徽章:0
个人认为有必要。
mongodb和memcached(或redis)并不是竞争关系,更多的是一种协作共存的关系。mongodb本质上还是硬盘数据库,在复杂查询时仍然会有大量的资源消耗,而且在处理复杂逻辑时仍然要不可避免地进行多次查询。这时就需要memcached这样的内存数据库来作为中间层进行缓存和加速。
比如在某些复杂页面的场景中,整个页面的内容如果都从mongodb中查询,可能要几十个查询语句,耗时很长。如果需求允许,则可以把整个页面的对象缓存至memcached中,定期更新。这样mongodb和memcached就能很好地协作起来。
论坛徽章:0
有必要。
mongodb并非脱离了低级趣味(disk IO)的高尚(high speed)的key-value数据库,而是正统意义上的硬盘数据库,只是使用了Document这类非SQL,以及对内存做了一定程度的利用而已。
由于mongodb是一个很懒的数据库,除了存储数据基本上不做什么运算,所以一旦有一定程度(根本不用多大量)的运算,你一定能感受到它的袅袅婷婷(采用js进行脚本运算),官方推荐mongodb尽量设计成自取式(冗余避免计算)。
对于这类查询,不用缓存,就只能用咖啡(边喝边等)了。
论坛徽章:0
主要在于应用场景。如果规模比较小,完全没有必要用其它方案来补充。
MongoDB,数据查询命中主要走索引,如果索引设定恰当,这一块大部分内容会被放在内存中;这部分的效率不会低的。但另外一方面,MongoDB毕竟会大量占用磁盘的资源,包括读取本身产生的IO也会远高于纯内存的数据库。
Anyway,这些在规模比较小的情况下,比如百来万的数据,产生的影响不会太糟,完全可以接受。
Memecached作为cache的方案,本身都是需要对cache如何处理要有所规划。MongoDB虽然会把最近的查询放在内存中,但毕竟远不如Memecached这种专用的工具对cache控制的颗粒度。
或者可以尝试Redis。
各有好处,各有坏处;关键在于自己的取舍。
论坛徽章:0
1. 你需要了解,基于内存的数据库和基于磁盘的数据库的区别,这点适用于任何产品;
2. 你需要了解,适用缓存产品的前提,是数据库的读可能成为瓶颈,同样适用于任何产品。
itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有    
 北京市公安局海淀分局网监中心备案编号:10 广播电视节目制作经营许可证:编号(京)字第1149号问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
redis、memcache、mongoDB有哪些区别?例如:性能、可靠性、数据一致性等方面的区别。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
下面的内容来自同事的总结,贴出来分享:MemcachedMemcached的优点:
Memcached可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS(取决于key、value的字节大小以及服务器硬件性能,日常环境中QPS高峰大约在4-6w左右)。适用于最大程度扛量。
支持直接配置为session handle。
坑少。Memcached的局限性:
只支持简单的key/value数据结构,不像Redis可以支持丰富的数据类型。
无法进行持久化,数据不能备份,只能用于缓存使用,且重启后数据全部丢失。
无法进行数据同步,不能将MC中的数据迁移到其他MC实例中。
Memcached内存分配采用Slab Allocation机制管理内存,value大小分布差异较大时会造成内存利用率降低,并引发低利用率时依然出现踢出等问题。需要用户注重value设计。
RedisRedis的优点:
支持多种数据结构,如 string(字符串)、 list(双向链表)、dict(hash表)、set(集合)、zset(排序set)、hyperloglog(基数估算)
支持持久化操作,可以进行aof及rdb数据持久化到磁盘,从而进行数据备份或数据恢复等操作,较好的防止数据丢失的手段。
支持通过Replication进行数据复制,通过master-slave机制,可以实时进行数据的同步复制,支持多级复制和增量复制,master-slave机制是Redis进行HA的重要手段。
单线程请求,所有命令串行执行,并发情况下不需要考虑数据一致性问题。
支持pub/sub消息订阅机制,可以用来进行消息订阅与通知。
支持简单的事务需求,但业界使用场景很少,并不成熟。
Redis的局限性:
Redis只能使用单线程,性能受限于CPU性能,故单实例CPU最高才可能达到5-6wQPS每秒(取决于数据结构,数据大小以及服务器硬件性能,日常环境中QPS高峰大约在1-2w左右)。
支持简单的事务需求,但业界使用场景很少,并不成熟,既是优点也是缺点。
Redis在string类型上会消耗较多内存,可以使用dict(hash表)压缩存储以降低内存耗用。
:)以下是我个人的补充
Mc和Redis都是Key-Value类型,不适合在不同数据集之间建立关系,也不适合进行查询搜索。比如redis的keys pattern这种匹配操作,对redis的性能是灾难。
mogodb是一种文档性的数据库。先解释一下文档的数据库,即可以存放xml、json、bson类型系那个的数据。这些数据具备自述性(self-describing),呈现分层的树状数据结构。redis可以用hash存放简单关系型数据。
mogodb存放json格式数据。
适合场景:事件记录、内容管理或者博客平台,比如评论系统。
nosq的产品目前很多,架构师的选择导向主要有以下两个因素:
1)适合应用程序的使用场景,比如评论系统用比较适合使用mogodb,而mc也可以实现(应用程序把数据转化成json存入,但是部分数据更新不方便)
2)团队开发比较熟悉的技术,比如一个团队一直在使用mc,因而有限选择mc,而不是redis。
还有中严重的状况,开发团队一直使用mogodb,在适合kv nosq的场景下而继续选择mogodb。
推荐给大家的一本书籍:&NoSQL精粹&
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
redis和memcache是两种缓存机制,主要用来减少数据库压力提高访问速度。redis可以将缓存保存到硬盘,重启电脑可以继续调用,还有很多memcache所没有的功能,memcache只是单纯的缓存在内存中,功能单一,效率高。至于mongoDB,这尼玛就是一数据库
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
同步到新浪微博
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:先说我自己用的情况:
最先用的memcache ,用于键值对关系的服务器端缓存,用于存储一些常用的不是很大,但需要快速反应的数据,然后,在另一个地方,要用到redis,然后就去研究了下redis. 一看,显示自己安装了php扩展,因为有服务器上的redis服务端,自己本地就没有安装,其实用法和memcache基本一样,可能就是几个参数有所不同。当然 它们缓存的效果也不一样,具体的哪里不一样,一下就是一些资料,和自己的总结
1、 Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等。2、 数据类型--Memcache在添加数据时就要指定数据的字节长度,例如:set key3 0 0 8lxsymctoSTORED而redis不需要,如:redis 127.0.0.1:6379&set key2 "lxsymblog"OKredis 127.0.0.1:6379&get key2"lxsymblog"3、虚拟内存--Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘4、过期策略--memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定,例如expire name 105、分布式--设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从6、存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)7、灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复
从以下几个维度,对redis、memcache、mongoDB 做了对比,欢迎拍砖
都比较高,性能对我们来说应该都不是瓶颈
总体来讲,TPS方面redis和memcache差不多,要大于mongodb
2、操作的便利性
memcache数据结构单一
redis丰富一些,数据操作方面,redis更好一些,较少的网络IO次数
mongodb支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富
3、内存空间的大小和数据量的大小
redis在2.0版本后增加了自己的VM特性,突破物理内存的限制;可以对key value设置过期时间(类似memcache)
memcache可以修改最大可用内存,采用LRU算法
mongoDB适合大数据量的存储,依赖操作系统VM做内存管理,吃内存也比较厉害,服务不要和别的服务在一起
4、可用性(单点问题)
对于单点问题,
redis,依赖客户端来实现分布式读写;主从复制时,每次从节点重新连接主节点都要依赖整个快照,无增量复制,因性能和效率问题,
所以单点问题比较复杂;不支持自动sharding,需要依赖程序设定一致hash 机制。
一种替代方案是,不用redis本身的复制机制,采用自己做主动复制(多份存储),或者改成增量复制的方式(需要自己实现),一致性问题和性能的权衡
Memcache本身没有数据冗余机制,也没必要;对于故障预防,采用依赖成熟的hash或者环状的算法,解决单点故障引起的抖动问题。
mongoDB支持master-slave,replicaset(内部采用paxos选举算法,自动故障恢复),auto sharding机制,对客户端屏蔽了故障转移和切分机制。
5、可靠性(持久化)
对于数据持久化和数据恢复,
redis支持(快照、AOF):依赖快照进行持久化,aof增强了可靠性的同时,对性能有所影响
memcache不支持,通常用在做缓存,提升性能;
MongoDB从1.8版本开始采用binlog方式支持持久化的可靠性
6、数据一致性(事务支持)
Memcache 在并发场景下,用cas保证一致性
redis事务支持比较弱,只能保证事务中的每个操作连续执行
mongoDB不支持事务
7、数据分析
mongoDB内置了数据分析的功能(mapreduce),其他不支持
8、应用场景
redis:数据量较小的更性能操作和运算上
memcache:用于在动态系统中减少数据库负载,提升性能;做缓存,提高性能(适合读多写少,对于数据量比较大,可以采用sharding)
MongoDB:主要解决海量数据的访问效率问题
最近一直在研究key-value的存储,简单记一下感受。。一些memcache和redis的安装和使用就不赘述啦。只简单说说两种方案的差别。一些感想和测试结果未必足够能说明问题,有什么不妥请大家指正。因为这两天在学习的过程发现一直在更正自己认识的缺陷,每天都会否定前一天的想法。。好了,费话少说。
  经过对50万个数据存储的研究发现:
  每秒单条指令执行量    
memcache 约3万次
  redis 约1万次
而且,memcache的一大优点是可以通过一个函数直接设置过期时间,而redis需要两个函数才可以既设置了键值对又设置过期时间,也就是redis在这点上效率变成了原来的一半,即5千次,这对于大部分需求来说,有点太慢了。
  memcache的测试代码如下:
$mem = new M
$mem-&connect("127.0.0.1", 11211);
$time_start = microtime_float();
//保存数据
for($i = 0; $i & 100000; $i ++){
$mem-&set("key$i",$i,0,3);
$time_end = microtime_float();
$run_time = $time_end - $time_
echo "用时 $run_time 秒\n";
function microtime_float(){
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
redis的测试代码如下:redis1.php 此代码大概需要10秒左右
$redis = new Redis();
$redis-&connect('127.0.0.1', 6379);
$time_start = microtime_float();
//保存数据
for($i = 0; $i & 100000; $i ++){
$redis-&sadd("key$i",$i);
$time_end = microtime_float();
$run_time = $time_end - $time_
echo "用时 $run_time 秒\n";
//关闭连接
$redis-&close();
function microtime_float(){
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
  如果需要在设置键值的同时设置过期时间,大概执行需要20秒左右,测试代码如下:redis2.php
$redis = new Redis();
$redis-&connect('127.0.0.1', 6379);
$time_start = microtime_float();
//保存数据
for($i = 0; $i & 100000; $i ++){
$redis-&sadd("key$i",$i);
$redis-&expire("key$i",3);
$time_end = microtime_float();
$run_time = $time_end - $time_
echo "用时 $run_time 秒\n";
//关闭连接
$redis-&close();
function microtime_float(){
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
  后来在网上发现redis有一个神奇的功能叫事务,通过multi原子性的将一段代码块依次执行,从而达到一个完整功能模块的执行。不幸的是,通过测试发现,采用multi方式执行代码时并没有减少请求次数,相反在执行multi指令和exec指令时都要发送请求,从而将运行时间变成了原来的四倍,即四条指令的运行时间。测试代码如下:redis3.php
$redis = new Redis();
$redis-&connect('127.0.0.1', 6379);
$time_start = microtime_float();
//保存数据
for($i = 0; $i & 100000; $i ++){
$redis-&multi();
$redis-&sadd("key$i",$i);
$redis-&expire("key$i",3);
$redis-&exec();
$time_end = microtime_float();
$run_time = $time_end - $time_
echo "用时 $run_time 秒\n";
//关闭连接
$redis-&close();
function microtime_float(){
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
  问题出现了瓶颈,有好多公司需要海量数据处理,每秒5000次远不能满足需求,然后由于redis主从服务器上比memcache有更大的优势,为了将来数据的着想,不得不使用redis,这时候出现了一种新的方式,即phpredis提供的pipline功能,该功能能够真正的将几条代码封装成一次请求,从而大大提高了运行速度,50万次的数据执行只有了58秒。测试代码如下:redis4.php
$redis = new Redis();
$redis-&connect('127.0.0.1', 6379);
$time_start = microtime_float();
//保存数据
for($i = 0; $i & 100000; $i ++){
  $pipe=$redis-&pipeline();
$pipe-&sadd("key$i",$i);
$pipe-&expire("key$i",3);
$replies=$pipe-&execute();
$time_end = microtime_float();
$run_time = $time_end - $time_
echo "用时 $run_time 秒\n";
//关闭连接
$redis-&close();
function microtime_float()
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
  运用这个操作可以非常完美的将赋值操作和设置过期时间操作打包到一个请求去执行,大大提高了运行效率。
redis安装:http://mwt198668./blog/static//
memcache安装:http://blog.csdn.net/barrydiu/article/details/3936270
redis设置主从服务器:/fuwuqi/fuwuqijiqunyuanquan/-7117.html
memcache设置主从服务器:/yuanermen/archive//2051153.html
浏览: 272061 次
来自: 北京
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'mongodb高效的访问速度,用来快速存取数据再合适不过了,缓存神马的,可以用这个的 另外,有的时候,如果仅仅存储几条数据,单独去建立一张表代价太大,这个时候,不妨试试这个 & 先发一个mongodb数据访问帮助类 public class MongdbHelper : IDisposable
public MongoServer Server { }
public MongoDB.Driver.MongoDatabase Database { }
public MongoCollection DataSet { }
public MongdbHelper( string dbName, string tableName)
Server = MongoServer.Create("mongodb://localhost/?socketTimeoutMS=2400000");
Database = Server.GetDatabase(dbName);
DataSet = Database.GetCollection(tableName);
public MongdbHelper(string connectionString, string dbName, string tableName)
Server = MongoServer.Create(connectionString);
Database = Server.GetDatabase(dbName);
DataSet = Database.GetCollection(tableName);
public void Dispose()
Server.Disconnect();
public static List GetOnColumn(string dbName, string tableName, string column, Func convert)
using (MongdbHelper db = new MongdbHelper(dbName, tableName))
List results = new List();
var r = db.DataSet.FindAll();
r.SetFields(column);
foreach (var c in r)
results.Add(convert(c[column]));
public static bool IsExist(string dbName, string tableName, string column, object value)
using (MongdbHelper db = new MongdbHelper(dbName, tableName))
IMongoQuery query = new QueryDocument() { { column, value.ToString() } };
var results = db.DataSet.FindOne(query);
return results !=
再来看具体的实现:
原理:将对象通过序列化操作后以二进制的方式存储到mongodb中
/// 存储数据
public static void Set(string key, T value)
using (MongdbHelper db = new MongdbHelper(DefaultDbName, DefaultTableName))
IMongoQuery query = new QueryDocument()
{"Key",key}
var document = db.DataSet.FindOne(query);
if (document != null)
document["Value"] = SerializeHelper.BinarySerialize(value);
document["Type"] = value.GetType().N
document["Date"] = DateTime.Now.ToString();
IDictionary newDict = new Dictionary();
newDict.Add("Value", SerializeHelper.BinarySerialize(value));
newDict.Add("Key", key);
newDict.Add("Type", value.GetType().Name);
newDict.Add("Date", DateTime.Now.ToString());
document = new BsonDocument(newDict);
db.DataSet.Save(document);
catch (Exception ex)
throw new Exception("保存数据出错", ex);
/// 获取对象
public static T Get(string key)
using (MongdbHelper db = new MongdbHelper(DefaultDbName, DefaultTableName))
IDictionary dict = new Dictionary();
dict.Add("Key", key);
IMongoQuery query = new QueryDocument()
{"Key",key}
var document = db.DataSet.FindOne(query);
if (document != null)
byte[] bytes = ((MongoDB.Bson.BsonBinaryData)document["Value"]).B
#region 反序列化字节数组
if (string.Equals(document["Type"].ToString(), typeof(T).Name, StringComparison.InvariantCultureIgnoreCase))
return SerializeHelper.BinaryDeSerialize(bytes);
return default(T);
#endregion
return default(T);
return default(T);
另外,为了方便存储单个对象的数据,例如配置信息,增加下面两个方法:
/// 存储对象
/// 适用于只有单个对象或单条记录的数据,例如系统配置
public static void Set(T value)
Set(typeof(T).Name, value);
/// 获取对象
/// 适用于只有单个对象或单条记录的数据,例如系统配置
public static T Ge()
return Get(typeof(T).Name);
完整代码:
public class SerializeHelper
/// 反序列化
public static T BinaryDeSerialize(byte[] serializedObject)
MemoryStream serializationStream = new MemoryStream();
serializationStream.Write(serializedObject, 0, serializedObject.Length);
serializationStream.Seek(0L, SeekOrigin.Begin);
object obj2 = new BinaryFormatter().Deserialize(serializationStream);
serializationStream.Close();
serializationStream.Dispose();
return (T)obj2;
/// 序列化
public static byte[] BinarySerialize(object obj)
MemoryStream serializationStream = new MemoryStream();
new BinaryFormatter().Serialize(serializationStream, obj);
serializationStream.Seek(0L, SeekOrigin.Begin);
byte[] buffer = serializationStream.ToArray();
serializationStream.Close();
serializationStream.Dispose();
/// 简易的mongodb数据存储服务
public class DataService
/// 数据接名
static string DefaultDbName = "MongodbService";
static string DefaultTableName = "DataSet";
/// 获取对象
public static T Get(string key)
using (MongdbHelper db = new MongdbHelper(DefaultDbName, DefaultTableName))
IDictionary dict = new Dictionary();
dict.Add("Key", key);
IMongoQuery query = new QueryDocument()
{"Key",key}
var document = db.DataSet.FindOne(query);
if (document != null)
byte[] bytes = ((MongoDB.Bson.BsonBinaryData)document["Value"]).B
#region 反序列化字节数组
if (string.Equals(document["Type"].ToString(), typeof(T).Name, StringComparison.InvariantCultureIgnoreCase))
return SerializeHelper.BinaryDeSerialize(bytes);
return default(T);
#endregion
return default(T);
return default(T);
/// 存储数据
public static void Set(string key, T value)
using (MongdbHelper db = new MongdbHelper(DefaultDbName, DefaultTableName))
IMongoQuery query = new QueryDocument()
{"Key",key}
var document = db.DataSet.FindOne(query);
if (document != null)
document["Value"] = SerializeHelper.BinarySerialize(value);
document["Type"] = value.GetType().N
document["Date"] = DateTime.Now.ToString();
IDictionary newDict = new Dictionary();
newDict.Add("Value", SerializeHelper.BinarySerialize(value));
newDict.Add("Key", key);
newDict.Add("Type", value.GetType().Name);
newDict.Add("Date", DateTime.Now.ToString());
document = new BsonDocument(newDict);
db.DataSet.Save(document);
catch (Exception ex)
throw new Exception("保存数据出错", ex);
/// 存储对象
/// 适用于只有单个对象或单条记录的数据,例如系统配置
public static void Set(T value)
Set(typeof(T).Name, value);
/// 获取对象
/// 适用于只有单个对象或单条记录的数据,例如系统配置
public static T Ge()
return Get(typeof(T).Name);
使用举例:
有这个一个用户类:
/// 简易的用户模型
[Serializable]
public class UserModel
public int UserId
public string UserName
public string Name
可以用这样的方式来进行存取:
public UserModel CurrentUser
if (currentUser == null)
if (!string.IsNullOrEmpty(CurrentUserName))
currentUser = DataService.Get(this.CurrentUserName);
if (currentUser == null)
var user = IoC.Resolve().FindByAccountName(CurrentUserName);
if (user != null)
currentUser = new UserModel
UserName = CurrentUserName,
Name = user.Name,
UserId = user.ID
// 保存到mongodb 长久存储
DataService.Set(this.CurrentUserName, currentUser);
return currentU
阅读(...) 评论()}

我要回帖

更多关于 使用hashmap做缓存 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信