假如我有数千万甚至是上亿的用户数据,我想把用户自增ID和用户名UserName放到缓存里。
我的需求是,当要查询用户的信息时,我想先从缓存里根据用户名UserName获取到用户的ID,
然后再通过ID在数据库里查询用户的信息。
我想当一个用户表达到上亿的数量级别时,用自增ID来查询肯定比用UserName来查询快好多倍,即使UserName做了簇级索引。
我现在的疑问是:
1.做这样的缓存需要什么样配置的服务器,ID为自增ID,UserName最大长度为20.上亿数量级的数据,
一个内存为4G的服务器能支持的了吗?
2.应该怎么样来实现缓存,数据几乎不会变化,但是要频繁的新增数据到缓存里,应该怎么样才能既容易写入缓存又容易从缓存里查询数据,并且这些操作不能耗太大的性能。
我能想到的缓存方案有:
     方案1.objCache.Insert(CacheKey, objObject);CacheKey对应的是用户名UserName,objObject对应的是自增ID,通过Cache[UserName]方式来获取自增ID。这样的好处是新增缓存容易,读取缓存数据也很容易。但是问题是,这样新增上亿数量级的缓存性能是否有问题?
     方案2.定义一个Hashtable(哈希表)来存放用户名UserName(key)和自增ID(value),然后把Hashtable存到缓存里,当要查询或者新增数据时把Hashtable从缓存里读取出来,然后再对Hashtable进行查询或者新增数据。但是问题是,这样的Hashtable将是一个非常庞大的对象,频繁的从缓存里写入读取,会不会也很好性能呢?况且上亿数量级别的哈希表Hashtable[key]这样读取数据会快吗?高手们,你们是怎么处理这个问题的呢?一起来探讨一下吧!

解决方案 »

  1.   

    个人意见:
    可以根据UserName的字母顺序分表,
    查询前判断该查那张表。数据量过大,
    数据分区分表的必要性就非常明显了。
      

  2.   

    另外,许多时候我们只需要缓存20分钟,即使这些数据的后台对应数据从来不变化,但是只要前台并不需要读取,为什么要让它们占用内存呢?你知道内存空间比硬盘空间贵多少倍吗?许多时候我们在数据有20分钟没有被反复读取的时候就必须清除缓存单元,并且缓存系统自己应该有多种内部的机制在物理内存达到一定限度时就将一部分最不频繁使用的数据自动的释放掉,然后释放申请的物理内存空间,直到空出足够多的空间为止。System.Web.Caching.Cache就是这样的可以自动释放缓存数据,并且提供现成的多种CacheDependency同时你也可以自定义CacheDependency的框架。
      

  3.   

    说得非常精辟呀
    缓存的意义在于保留大量数据中,最有必要最有意义的一小部分数据。
    如果把所有数据都缓存起来,那就不是缓存。其实程序缓存,跟CPU缓存的道理是类似的。
    内存2G,CPU缓存才2-8M,
    如果缓存也2G,
    那有什么意义呢。并且,这个2-8M缓存的命中率是重中之重。
    INTEL公司为此费尽心思。
    现在基本都是采用改良的多路分支预测技术。这意味着在大量数据面前,
    缓存的动态算法也非常重要。
    就是sp1234大牛所说的自动化缓存依赖。
      

  4.   

    缓存保留的数据不宜太大,用来保留有用的,所以说缓存的算法很重要的。
    数据库那么大,可以考虑表分区。
    查询的时候,根据算法到相应的分区进行查询,速度会提升不少。
    如果有条件的话,可以利用单独的缓存服务器,或者web application集群,利用hash算法,到对应的服务器上查找
      

  5.   

    引子:
    海量数据的查询优化是一个很复杂的问题 !0. 硬件方面;(服务器配置、集群设置、硬盘容量、内存大小等)
    1. 从数据库结构;(表结构设计)
    2. 从索引;(索引、视图、触发器、游标等)
    3. 从SQL语句优化;所以,你不能单纯的从一两个方面考虑。正文:
    正如你上面所说,那么ID也是放在客户端的缓存中而已,对服务器端不会有什么印象(也算是一种优化吧);至于放在服务器端的缓存那就没必要、也没有那种可能性,很不符合需求。
    还有就是4G内存对于一台机子而言,貌似已经很难在扩展了。但是,你又要达到上亿级别的访问,那就不能片面的考了问题了,应该换一种思考方式。可以考虑服务器集群等方面。
      

  6.   

    在数据中要定位到你的那条记录的复杂度为log2(n)
    就是将n以2对开
    也就是1亿数据的话,最多检索27次就可以找到你要的那条记录
      

  7.   

    用户名可以是中文的,怎么分表?你看这样子处理行不行:
    先把用户名进行MD5转换,然后再根据MD5得到的值取其前两位进行分表查询。
    这样子行吗?频繁的进行MD5运算耗性能大吗?
      

  8.   


    MD5转换那是相当费的
    unicode码是直接取就可以拉。不过unicode太多,不好分表。要不把所有的用户名和编号写成文件,
    然后进行全文搜索,
    不知道怎么样
      

  9.   

    CPU的缓存相对内存来说数量级上差距很大,缓存放什么东西,怎么放,缓存的命中率,命中率低的是否应该从缓存中淘汰?这些都需要考虑。我看你说的那个更像是一个存储而不是一个缓存。
      

  10.   

    有上亿用户,楼主肯定有钱搞N个服务器啦,别说几条大内存.当然从技术角度来说,我的建议是:
    1. 如果是基于cookie来保存用户名,那可以同时保存ID,查询时直接查询ID2.如果一定要基于用户名,那就把用户名建索引吧.3.如果一定要加到缓存中,在加载到缓存中时,只提取近三个月内登录过的用户,估计这样数据量能降低9/10
      如果按一个用户占30byte字节,100万用户大约占30M 加上其它支出,50M足够.
    4.ASP.NET后台管理cache键/值对时,好象就是基于字典来管理的。读效能没问题,不过,你有这么多要写入的吗?无非就是新注册的用户需要再写入吧?
      
      

  11.   

    应该越来越清晰才对呀。
    lz有没有注意到csdn的登陆机制?
    那个两个星期不用再登陆的功能,
    目的和你的一样哦,
    也是为了减轻系统负担。上面已经有人说过了,
    可以把所有用户分类,
    分为活跃用户和沉寂用户。其实解决这个需求的思路是很多的,
    是个系统问题,可以从各个方面考虑。
      

  12.   

    你们是怎么操作缓存的呢?
    是单个分散插入缓存还是整体插入缓存?
    objCache.Insert(CacheKey, objObject);
    Cache[UserName]
      

  13.   

    假如不用自增ID呢?把用户名的HASH值作为ID,这个缓存就可以避免了吧
      

  14.   

    上亿级别的应该用分布式比较好吧
    1亿=100M
    也就是说全放缓存里内存消耗是单个数据消耗×100M
    单个数据是40Byte,你4Gb内存就没了,这还不算系统和其他服务的内存消耗
      

  15.   

    我觉得先不要去讨论你的缓存是不是能支持多少数据量,先要看看你用缓存来做什么,如果你是存一个用户的对象,那就要看,这个对象都做什么用,如果只是会用到id,那就存id好了,如果只是用个名字那就存名字好了,而不要一下就把一整个的对象生出来然后一坨坨的放在缓存里,那样做没有丝毫的好处,有很多东西都是在用的时候才去掉,而并不是所有的用户在浏览网站的时候会做所有的事情,你早早的把一个胖对象放在缓存里干什么用呢?即便你有亿万的用户,那你同时在线的人,也不会那么多,我不相信你现在的服务器能支持亿万吞吐量,那你同时在线的人究竟有多少,才是你实际应用时候产生的消耗。个人拙见,错误之处,大家指正!
      

  16.   

    看这篇文章《串行FLASH数据缓冲区的管理》,有参考的实现代码!
    http://blog.csdn.net/fjb2080/archive/2010/04/19/5500798.aspx
      

  17.   

    1亿,其实数量真不大,4GB少点,但是可以,8GB就好办多了。
    通过命中率择优缓存会节约很多资源,4GB是完全可以胜任的,完全。
    这么大的数据量是实时需要吗?如果真是实时需要,内存是小问题,带宽是个大问题...这么大数据量应该不是单机系统吧。
      

  18.   

    建啥缓存?按你的要求来看 给name列建立索引 然后把索引放到keep池里不就实现了?
      

  19.   

    上亿用户用Hash表是放不下的。
    建议你只把最近使用的用户信息放到Hash表中,比如放100万,性能和全放在Hash表中应该没有太大的区别。
      

  20.   

    sql里面有个rownumber 看看能不能用上  顺便多弄几台服务器 
      

  21.   

    个人觉得,大家看问题都有一种教条性: 只有小数据量的,经常用的,就放在缓存中难道大量的就不能放在所谓的缓存中?如果 有足够的,富余的内存用,且用起来行之有效,何乐而不为?首先楼主说的只是把 用户名及对应的ID放到内存中,并不是把数据库中用户的全部信息放到内存中.当用户输入用户名时,首先找到对应的 ID,然后用 select * from tb where id=@id
    在数据库中,主键ID唯一性索引/自增ID,查询起来肯定是比 查询起来,效能肯定比查询name来得快得多.如果楼主服务器有8G内存,如果我能花500M或1G甚至2G空间把这个方案搞成,那有何不行?
      

  22.   

    "ID和用户名UserName放到缓存里。
    我的需求是,当要查询用户的信息时,我想先从缓存里根据用户名UserName获取到用户的ID,
    然后再通过ID在数据库里查询用户的信息。
    "
    你不觉得费二便事吗?先从缓存中查,然后再从数据中查.
    而且这里缓存毫不意义.缓存不是这么用地~~~
    如果数据量真的很大,建议做索引和数据库分布.
      

  23.   

    愚见:放缓存,然后根据用户名得到ID,??虽然N年没接触DB,总觉得这思路不可取
      

  24.   

    第一,我认为“用自增ID来查询肯定比用UserName来查询快好多倍”是不正确的,数据库查询的效率瓶颈在硬盘,不是内存,而比较是在内存中进行的。整数还是字符串的比较性能差,比起硬盘来微不足道。
    第二,如果是单台服务器想要缓存整个用户id与用户名信息,感觉不是很好。这个数据量的HASH是很容易冲突的,4G内存也是不够用的。如果细分到条或块,并指定一个合理的缓存时间,应该就可以解决这个问题。
    第三,如果关注性能就不要用Hashtable了,应该用Dictionary。
    对于这点,建立与数据库更新关联的缓存系统就不需要销毁缓存了。不要说大缓存没有意义,毕竟有内存不用也是浪费。
    如果有规律可循,并且内存紧张的情况下,当然缓存越小并且命中率越高才越好。但是,试问在随机概率中如何采用什么预测技术?
      

  25.   


    没有理解我说要表达的意思。
    我没有要lz搞什么分支预测的事情。
    那帖是想根据sp1234的意思,
    讲解下缓存的意义和要点。而且,从头往下看,
    我一直是建议优化数据结构和处理过程,
    在执行查询前,
    就把查询范围缩到最小,
    这个思路!!