




已阅读5页,还剩3页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
舍得网支撑 1 亿 pv/天构架,开源了说是支持 1 亿 pv/天,也许有点夸张,也是为了吸引您能点进来,如果您能认真看完相信也不会让您失望,当然,肯定有很多“高手”会对此会嗤之以鼻,没关系,有很多眼高手低的人总喜欢评论别人却从不会看清自己。如果大家真想支持我、支持中国人开源项目,请把该文贴到自己的博客中或者收藏本文,记得包含文档的下载地址!谢谢。我说的系统主要是构建在 hibernate 之上的高效数据库缓存系统,其中包含了分布式解决方案,该系统已经应用在舍得网上了,没有发现大问题,本人也相信该系统已经足够强大,应付数百万 IP/天的应用都不是问题,我这么说肯定有人会对此表示怀疑,其实系统到底能撑多少 IP/天不在于系统本身而是在于使用该系统的人。代码看上去很简单,其实却是两年经验的总结,整过过程也遇到了很多难点,最后一一解决了,所以也请各位珍惜他人的劳动成果。本系统非常简洁易用,主程序BaseManager.java 不到 1000 行代码,用“精悍”来形容绝对不为过,1000 行代码却包含了数据库对象的缓存、列表和长度的缓存、按字段散列缓存、update 延时更新、自动清除列表缓存等功能,用它来实现像论坛、博客、校友录、交友社区等绝大部分应用网站都足够了。我在理想状态下做了压力测试,在没有数据库操作的 jsp 页面(舍得网新首页)里可以完成2000 多 requests 每秒(正常情况可能有 1/1000 的 request 有数据库查询,其余 999/1000 都是直接从缓存里读取) ,物品详情页每秒可完成 3000 多 requests,纯静态 html 页面也只能完成 7000 多 requests/秒,我对首页进行了三个小时的压力测试,完成了 24850800 个requests,java 一点事都没有,内存没有上涨。按照 2000 个 requests/秒算,一天按 15 小时计算,那么每天能完成 3600*15*2000=1 亿零 8 百万 requests,当然这是理想状态,实际状态就算打一折,还能完成 1000 万 pv/天,要知道,这只是一个普通 1 万 3 千块钱买的服务器,内存 4G,CPU2 个,LinuxAS4 系统,apache2.0.63/resin2.1.17/jdk6.0 的环境。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。现在进入正题。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。为什么要用缓存?如果问这个问题说明你还是新手,数据库吞吐量毕竟有限,每秒读写5000 次了不起了,如果不用缓存,假设一个页面有 100 个数据库操作,50 个用户并发数据库就歇菜,这样最多能支撑的 pv 也就 50*3600*15=270 万,而且数据库服务器累得半死,搞不好什么时候就累死了。我的这套缓存系统比单独用 memcached 做缓存还要强大,相当于在 memcached 上再做了两级缓存,大家都知道 memcached 很强了,但是吞吐量还是有限,每秒 20000 次 get 和 put 当遇到超大规模的应用时还是会歇菜,本地 HashMap 每秒可执行上百万次 put 和 get,在这上面损耗的性能几乎可以忽略不记了。温馨提示:能不用分布式的时候就不要用分布式,非用分布式的时候再考虑用 memcached,我的缓存系统在这方面都已经实现了,改个配置就可以了,有兴趣的可以仔细测试测试!一般数据库缓存在我看来包含四种。第一种:单个对象的缓存(一个对象就是数据库一行记录) ,对于单个对象的缓存,用 HashMap 就可以了,稍微复杂一点用 LRU 算法包装一个HashMap,再复杂一点的分布式用 memcached 即可,没什么太难的;第二种:列表缓存,就像论坛里帖子的列表;第三种:长度的缓存,比如一个论坛板块里有多少个帖子,这样才方便实现分页。第四种:复杂一点的 group,sum,count 查询,比如一个论坛里按点击数排名的最 HOT 的帖子列表。第一种比较好实现,后面三种比较困难,似乎没有通用的解决办法,我暂时以列表缓存(第二种)为例分析。mysql 和 hibernate 的底层在做通用的列表缓存时都是根据查询条件把列表结果缓存起来,但是只要该表的记录有任何变化(增加/删除/ 修改) ,列表缓存要全部清除,这样只要一个表的记录经常变化(通常情况都会这样) ,列表缓存几乎失效,命中率太低了。本人想了一个办法改善了列表缓存,当表的记录有改变时,遍历所有列表缓存,只有那些被影响到的列表缓存才会被删除,而不是直接清除所有列表缓存,比如在一个论坛版(id=1)里增加了一个帖子,那么只要清除 id=1 这个版对应的列表缓存就可以了,版 id=2就不用清除了。这样处理有个好处,可以缓存各种查询条件(如等于、大于、不等于、小于)的列表缓存,但也有个潜在的性能问题,由于需要遍历,CPU 符合比较大,如果列表缓存最大长度设置成 10000,两个 4 核的 CPU 每秒也只能遍历完 300 多次,这样如果每秒有超过 300 个 insert/update/delete,系统就吃不消了。在前面两种解决办法都不完美的情况下,本人和同事经过几个星期的思索,总算得出了根据表的某几个字段做散列的缓存办法,这种办法无需大规模遍历,所以 CPU 符合非常小,由于这种列表缓存按照字段做了散列,所以命中率极高。思路如下:每个表有 3 个缓存Map(key=value 键值对) ,第一个 Map 是对象缓存 A,在 A 中,key 是数据库的 id,Value是数据库对象(也就是一行数据) ;第二个 Map 是通用列表缓存 B,B 的最大长度一般1000 左右,在 B 中,key 是查询条件拼出来的 String(如start=0,length=15#active=0#state=0) ,Value 是该条件查询下的所有 id 组成的 List;第三个Map 是散列缓存 C,在 C 中, key 是散列的字段(如根据 userId 散列的话,其中某个 key就是 userId=109 这样的 String)组成的 String,value 是一个和 B 类似的 HashMap。其中只有 B 这个 Map 是需要遍历的,不知道说明白了没有,看完小面这个例子应该就明白了,就用论坛的回复表作说明,假设回复表 T 中假设有字段 id,topicId,postUserId 等字段(topicId 就是帖子的 id,postUserId 是发布者 id) 。第一种情况,也是最常用的情况,就是获取一个帖子对应的回复,sql 语句应该是象select id from T where topicId=2008 order by createTime desc limit 0,5select id from T where topicId=2008 order by createTime desc limit 5,5select id from T where topicId=2008 order by createTime desc limit 10,5的样子,那么这种列表很显然用 topicId 做散列是最好的,把上面三个列表缓存(可以是N 个)都散列到 key 是 topicId=2008 这一个 Map 中,当 id 是 2008 的帖子有新的回复时,系统自动把 key 是 topicId=2008 的散列 Map 清除即可。由于这种散列不需要遍历,因此可以设置成很大,例如 100000,这样 10 万个帖子对应的所有回复列表都可以缓存起来,当有一个帖子有新的回复时,其余 99999 个帖子对应的回复列表都不会动,缓存的命中率极高。第二种情况,就是后台需要显示最新的回复,sql 语句应该是象select id from T order by createTime desc limit 0,50的样子,这种情况不需要散列,因为后台不可能有太多人访问,常用列表也不会太多,所以直接放到通用列表缓存 B 中即可。第三种情况,获取一个用户的回复,sql 语句象select id from T where userId=2046 order by createTime desc limit 0,15select id from T where userId=2046 order by createTime desc limit 15,15select id from T where userId=2046 order by createTime desc limit 30,15的样子,那么这种列表和第一种情况类似,用 userId 做散列即可。第四种情况,获取一个用户对某个帖子的回复,sql 语句象select id from T where topicId=2008 and userId=2046 order by createTime desc limit 0,15select id from T where topicId=2008 and userId=2046 order by createTime desc limit 15,15的样子,这种情况比较少见,一般以 topicId=2008 为准,也放到 key 是 topicId=2008 这个散列 Map 里即可。那么最后的缓存结构应该是下面这个样子:缓存 A 是:Key 键(long 型) Value 值(类型 T)11 Id=11 的 T 对象22 Id=22 的 T 对象133 Id=133 的 T 对象列表缓存 B 是:Key 键(String 型) Value 值(ArrayList 型)from T order by createTime desc limit 0,50 ArrayList,对应取出来的所有 idfrom T order by createTime desc limit 50,50 ArrayList,对应取出来的所有 idfrom T order by createTime desc limit 100,50 ArrayList,对应取出来的所有 id散列缓存 C 是:Key 键(String 型) Value 值(HashMap)userId=2046Key 键(String 型) Value 值(ArrayList)userId=2046#0,5 id 组成的 ListuserId=2046#5,5 id 组成的 ListuserId=2046#15,5 id 组成的 ListuserId=2047Key 键(String 型) Value 值(ArrayList)userId=2047#0,5 id 组成的 ListuserId=2047#5,5 id 组成的 ListuserId=2047#15,5 id 组成的 ListuserId=2048 Key 键(String 型) Value 值(ArrayList)userId=2048#topicId=2008#0,5 id 组成的 ListuserId=2048#5,5 id 组成的 ListuserId=2048#15,5 id 组成的 List总结:这种缓存思路可以存储大规模的列表,缓存命中率极高,因此可以承受超大规模的应用,但是需要技术人员根据自身业务逻辑来配置需要做散列的字段,一般用一个表的索引键做散列(注意顺序,最散的字段放前面) ,假设以 userId 为例,可以存储 N 个用户的M 种列表,如果某个用户的相关数据发生变化,其余 N-1 个用户的列表缓存纹丝不动。以上说明的都是如何缓存列表,缓存长度和缓存列表思路完全一样,如缓存象 select count(*) from T where topicId=2008 这样的长度,也是放到 topicId=2008 这个散列 Map 中。如果再配合好使用 mysql 的内存表和 memcached,加上 F5 设备做分布式负载均衡,该系统对付像1000 万 IP/天这种规模级的应用都足够了,除搜索引擎外一般的应用网站到不了这种规模。再次申明:系统到底是不是强大不在系统本身而在于使用该系统的人!这个缓存系统是我和同事几年经验的总结,看似简单,其实也没那么简单,把它作为开源有下面几个目的:第一,真的希望有很多人能用它;第二:希望更多的人能够完善和改进它;第三:希望大家能聚到一起为通用高效数据库缓存构架作出贡献,毕竟,数据库操作是各种应用最常用的操作,也是最容易产生性能瓶颈的地方。Zip 包中包含了配置方法和测试用的 jsp,只要把它配置成一个 web 应用就可以快速调试并看到缓存的力量了,文档和下载地址是/akaladocs/api/com/akala/dbcache/core/BaseManager.html。配置说明文件在 docs/开始配置.txt 里有说明。最后啰嗦一句,如果大家真想支持我、支持中国人开源项目,请把该文贴到自己的博客中或者收藏本文,记得包含文档的下载地址!谢谢。thank you and Good luck 。QQ 群:24561583JVM 参数调优是一个很头痛的问题,可能和应用有关系,下面是本人一些调优的实践经验,希望对读者能有帮助,环境 LinuxAS4,resin2.1.17,JDK6.0,2CPU,4G 内存,dell2950 服务器,网站是 一:串行垃圾回收,也就是默认配置,完成 10 万 request 用时 153 秒,JVM 参数配置如下$JAVA_ARGS .= “ -Dresin.home=$SERVER_ROOT -server -Xms2048M -Xmx2048M -Xmn512M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:MaxTenuringThreshold=7 -XX:GCTimeRatio=19 -Xnoclassgc -Xloggc:log/gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps “;这种配置一般在 resin 启动 24 小时内似乎没有大问题,网站可以正常访问,但查看日志发现,在接近 24 小时时,Full GC 执行越来越频繁,大约每隔 3 分钟就有一次 Full GC,每次Full GC 系统会停顿 6 秒左右,作为一个网站来说,用户等待 6 秒恐怕太长了,所以这种方式有待改善。MaxTenuringThreshold=7 表示一个对象如果在救助空间移动 7 次还没有被回收就放入年老代,GCTimeRatio=19 表示 java 可以用 5%的时间来做垃圾回收,1/(1+19)=1 /20=5%。二:并行回收,完成 10 万 request 用时 117 秒,配置如下:$JAVA_ARGS .= “ -Dresin.home=$SERVER_ROOT -server -Xmx2048M -Xms2048M -Xmn512M -XX:PermSize=256M -XX:MaxPermSize=256M -Xnoclassgc -Xloggc:log/gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC -XX:MaxGCPauseMillis=500 -XX:+UseAdaptiveSizePolicy -XX:MaxTenuringThreshold=7 -XX:GCTimeRatio=19 “;并行回收我尝试过多种组合配置,似乎都没什么用,resin 启动 3 小时左右就会停顿,时间超过 10 秒。也有可能是参数设置不够好的原因, MaxGCPauseMillis 表示 GC 最大停顿时间,在 resin 刚启动还没有执行 Full GC 时系统是正常的,但一旦执行 Full GC, MaxGCPauseMillis 根本没有用,停顿时间可能超过 20 秒,之后会发生什么我也不再关心了,赶紧重启 resin,尝试其他回收策略。三:并发回收,完成 10 万 request 用时 60 秒,比并行回收差不多快一倍,是默认回收策略性能的 2.5 倍,配置如下:$JAVA_ARGS .= “ -Dresin.home=$SERVER_ROOT -server -Xms2048M -Xmx2048M -Xmn512M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=7 -XX:GCTimeRatio=19 -Xnoclassgc -Xloggc:log/gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 “;这个配置虽然不会出现 10 秒连不上的情况,但系统重启 3 个小时左右,每隔几分钟就会有 5 秒连不上的情况,查看 gc.log,发现在执行 ParNewGC 时有个 promotion failed 错误,从而转向执行 Full GC,造成系统停顿,而且会很频繁,每隔几分钟就有一次,所以还得改善。UseCMSCompactAtFullCollection 是表是执行 Full GC 后对内存进行整理压缩,免得产生内存碎片,CMSFullGCsBeforeCompaction=N 表示执行 N 次 Full GC 后执行内存压缩。四:增量回收,完成 10 万 request 用时 171 秒,太慢了,配置如下$JAVA_ARGS .= “ -Dresin.home=$SERVER_ROOT -server -Xms2048M -Xmx2048M -Xmn512M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:MaxTenuringThreshold=7 -XX:GCTimeRatio=19 -Xnoclassgc -Xloggc:log/gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xincgc “;似乎回收得也不太干净,而且也对性能有较大影响,不值得试。五:并发回收的 I-CMS 模式,和增量回收差不多,完成 10 万 request 用时 170 秒。$JAVA_ARGS .= “ -Dresin.home=$SERVER_ROOT -server -Xms2048M -Xmx2048M -Xmn512M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:MaxTenuringThreshold=7 -XX:GCTimeRatio=19 -Xnoclassgc -Xloggc:log/gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing -XX:CMSIncrementalDutyCycleMin=0 -XX:CMSIncrementalDutyCycle=10 -XX:-TraceClassUnloading “;采用了 sun 推荐的参数,回收效果不好,照样有停顿,数小时之内就会频繁出现停顿,什么 sun 推荐的参数,照样不好使。六:递增式低暂停收集器,还叫什么火车式回收,不知道属于哪个系,完成 10 万 request用时 153 秒$JAVA_ARGS .= “ -Dresin.home=$SERVER_ROOT -server -Xms2048M -Xmx2048M -Xmn512M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:MaxTenuringThreshold=7 -XX:GCTimeRatio=19 -Xnoclassgc -Xloggc:log/gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseTrainGC “;该配置效果也不好,影响性能,所以没试。七:相比之下,还是并发回收比较好,性能比较高,只要能解决 ParNewGC(并行回收年轻代)时的 promotion failed 错误就一切好办了,查了很多文章,发现引起 promotion failed 错误的原因是 CMS 来不及回收( CMS 默认在年老代占到 90%左右才会执行) ,年老代又没有足够的空间供 GC 把一些活的对象从年轻代移到年老代,所以执行 Full GC。 CMSInitiatingOccupancyFraction=70 表示年老代占到约 70%时就开始执行 CMS,这样就不会出现 Full GC 了。SoftRefLRUPolicyMSPerMB 这个参数也是我认为比较有用的,官方解释是 softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap,我觉得没必要等 1 秒,所以设置成 0。配置如下$JAVA_ARGS .= “ -Dresin.home=$SERVER_ROOT -server -Xms2048M -Xmx2048M -Xmn512M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=7 -XX:GCTimeRatio=19 -Xnoclassgc -XX:+DisableExplicitGC -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:-CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime -Xloggc:log/gc.log “;上面这个配置内存上升的很慢,24 小时之内几乎没有停顿现象,最长的只停滞了0.8s,ParNew GC 每 30 秒左右才执行一次,每次回收约 0.2 秒,看来问题应该暂时解决了。参数不明白的可以上网查,本人认为比较重要的几个参数是:-Xms -Xmx -Xmn MaxTenuringThreshold GCTimeRatio UseConcMarkSweepGC CMSInitiatingOccupancyFraction SoftRefLRUPolicyMSPerMBMemcached 是什么?Memcached 是高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度。Memcached 由 Danga Interactive 开发,用于提升 LiveJ 访问速度的。LJ每秒动态页面访问量几千次,用户 700 万。Memcached 将数据库负载大幅度降低,更好的分配资源,更快速访问。如何使用 memcached-Server 端?在服务端运行:# ./memcached -d -m 2048 -l 0 -p 11211这将会启动一个占用 2G 内存的进程,并打开 11211 端口用于接收请求。由于 32 位系统只能处理 4G 内存的寻址,所以在大于 4G 内存使用 PAE 的 32 位服务器上可以运行2-3 个进程,并在不同端口进行监听。如何使用 memcached-Client 端?(Java 版是这样的,参看 /memcached/#download)String serverStr = “2:12321“;String serverlist = serverStr;/String serverlist = “:12345“, “:12345“ ;/Integer weights = new Integer(5), new Integer(2) ; int initialConnections = 100;int minSpareConnections = 50;int maxSpareConnections = 500; long maxIdleTime = 1000 * 60 * 30; / 30 minuteslong maxBusyTime = 1000 * 60 * 5; / 5 minuteslong maintThreadSleep = 1000 * 5; / 5 secondsint socketTimeOut = 1000 * 3; / 3 seconds to block on reads/int socketConnectTO = 1000 * 3; / 3 seconds to block on initial connections. If 0, then will use blocking connect (default)/boolean failover = false; / turn off auto-failover in event of server down boolean nagleAlg = false; / turn off Nagles algorithm on all sockets in pool /boolean aliveCheck = false; / disable health check of socket on checkoutpool = SockIOPool.getInstance(“mymemcac
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030中国聚氨酯粉末涂料行业市场发展趋势与前景展望战略研究报告
- 2025-2030中国绝缘粉末涂料市场前景调研及投资运作模式探讨研究报告
- 外墙胶泥施工方案
- 2025-2030中国精油行业发展分析及投资前景与战略规划研究报告
- 2025年胶滚项目可行性研究报告
- 2025-2030中国祛斑露行业发展分析及投资前景预测研究报告
- 2025-2030中国磷化行业市场深度调研及竞争格局与投资研究报告
- 2025-2030中国硬盘行业市场现状供需分析及重点企业投资评估规划分析研究报告
- 2025-2030中国矿用防爆电器行业发展现状及发展趋势与投资战略研究报告
- 2025年联体钢叉项目可行性研究报告
- 工业互联网平台的商业模式与盈利策略
- 2024年09月2024渤海银行上海分行校园招聘笔试历年参考题库附带答案详解
- 2025年辽宁省辽渔集团招聘笔试参考题库含答案解析
- 《员工招聘与选拔》课件
- 南昌起义模板
- 【MOOC】体育舞蹈与文化-大连理工大学 中国大学慕课MOOC答案
- 接处警流程培训
- 2024年商丘职业技术学院单招职业技能测试题库附答案
- 《园林植物病虫害》课件
- 小红书食用农产品承诺书示例
- 空调维保服务投标方案 (技术方案)
评论
0/150
提交评论