Arch-03-14-缓存策略
robin(有人谓肉饼,太有才了)的一文很强悍,摘在这儿做个灯引。
http://robbin.iteye.com/blog/770553
用 ibatis + memcached 的策略明显有缺陷,粒度太大,考虑用更小粒度高效的方案吧。
听起来 hibernate 的缓存不错,原理很好,之前的项目一直是类似机制,只不过用的是自己实现的 simpleJdbc. 现在需要在 ibatis 的基础上实现细粒度缓存,好象没那么简单。
=================================================
1. Voldemort (伏地魔)
public MessageBean getByID(long id) throws MessageNotFoundException, DAOException { MessageBean bean = null; Connection con = getConnection(); PreparedStatement pstmt = null; ResultSet rs = null; try { // load message row pstmt = con.prepareStatement("SELECT pMessageID, ownerID, senderID, recipientID, subject, body, readStatus, folderID, pMessageDate, status, creationDate, sentDate FROM message WHERE pMessageID = ?"); pstmt.setLong(1, id); rs = pstmt.executeQuery(); if (!rs.next()) { throw new MessageNotFoundException("Message " + id + " could not be loaded from the database."); } bean = read(rs, new MessageBean()); rs.close(); pstmt.close(); // load message properties rows Map p = new HashMap(); pstmt = con.prepareStatement("SELECT name, propValue FROM MessageProp WHERE pMessageID=?"); pstmt.setLong(1, id); rs = pstmt.executeQuery(); while (rs.next()) { p.put(rs.getString(1), rs.getString(2)); } bean.setProperties(p); rs.close(); pstmt.close(); // load message attachment IDs LongList attachmentList = new LongList(); try { pstmt = con.prepareStatement("SELECT attachmentID FROM attachment WHERE objectType=5 AND objectID=?"); pstmt.setLong(1, bean.getID()); rs = pstmt.executeQuery(); while (rs.next()) { attachmentList.add(rs.getLong(1)); } bean.setAttachments(attachmentList); } catch (SQLException sqle) { Log.error(sqle); } finally { ConnectionManager.close(rs, pstmt); } } catch (SQLException sqle) { throw new MessageNotFoundException("Message with id " + id + " could not be loaded from the database."); } catch (NumberFormatException nfe) { throw new MessageNotFoundException("Message with id " + id + " could not be loaded from the database."); } finally { ConnectionManager.close(rs, pstmt); releaseConnection(con); } return bean; }
#!/bin/bash/voldemort-service.sh # # Copyright 2008-2009 LinkedIn, Inc # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # if [ $# -gt 1 ]; then echo 'USAGE: bin/voldemort-server.sh [voldemort_home]' exit 1 fi base_dir=$(dirname $0)/.. for file in $base_dir/dist/*.jar; do CLASSPATH=$CLASSPATH:$file done for file in $base_dir/lib/*.jar; do CLASSPATH=$CLASSPATH:$file done for file in $base_dir/contrib/*/lib/*.jar; do CLASSPATH=$CLASSPATH:$file done CLASSPATH=$CLASSPATH:$base_dir/dist/resources if [ -z "$VOLD_OPTS" ]; then VOLD_OPTS="\ -Xmx2G -server \ -Dcom.sun.management.jmxremote \ -Dcom.sun.management.jmxremote.port=6650 \ -Dcom.sun.management.jmxremote.ssl=false \ -Dcom.sun.management.jmxremote.authenticate=false" fi java -Dlog4j.configuration=log4j.properties $VOLD_OPTS -cp $CLASSPATH voldemort.server.VoldemortServer $@
<!--cluster.xml--> <cluster> <name>pluscluster</name> <server> <id>0</id> <host>127.0.0.1</host> <http-port>8071</http-port> <socket-port>6666</socket-port> <admin-port>6667</admin-port> <partitions>0,1,2,3,4,5,6,7 </partitions> </server> </cluster>
node.id=0 max.threads=100 ############### DB options ###################### http.enable=false socket.enable=true jmx.enable=true storage.configs=voldemort.store.bdb.BdbStorageConfiguration,voldemort.store.memory.InMemoryStorageConfiguration,voldemort.store.memory.CacheStorageConfiguration slop.store.engine=memory # NIO connector settings. enable.nio.connector=true enable.nio.admin.connector=false # don't throttle admin client - set to a really high value stream.read.byte.per.sec=1000000000000 stream.write.byte.per.sec=1000000000000 # default buffer size is 10MB. We'll turn it down to 512KB admin.streams.buffer.size=524288 # use only 8 selectors (for nio) nio.connector.selectors=8 nio.admin.connector.selectors=8
4. 应用架构基于共享 Voldemort 缓存,利用 JGroup 传送消息的应用集群,讲起来有一匹布那么长,暂且略过,隔几天画个图上来。
5. 启动 JMX 监控
开启一个Jconsole 本地连接
6. 缓存性能优化之道
(1)客户端资源缓存
HTTPD server - “cache.conf.rpmnew”
(2)服务端页缓存
HTTP header in the response to Cache-Control max-age=3600.
(3)配置外部 CDN 缓存服务器
. 安装 CDN 缓存服务器 . 基于 URL . 服务器端生成页面时,重写静态资源地址指向 CDN URL . 当完成页面请求后,客户端使用 CDN URL 返回资源 . 如果 CDN 命中,直接返回客户端,否则,从应用服务器返回并存入 CDN,备用。
(4)调整虚拟机参数
JVM_HEAP_MAX=4096 JVM_HEAP_MIN=4096
7. 动手搭建山寨 CDN
参考原文 http://blog.csdn.net/jackem/article/details/3206440
目前对于 CDN 网络搭建技术有很多成熟的商业方案,对于资金受限的网站可能无法自己搭建或购买。这里提供了一套简单的实现CDN网络的技术架构,所使用的软件全部是开源高效且免费的。根据CDN网络技术原理,必须有一个动态DNS服务器,开源的可以使用bind,免费开源。不修改代码,bind 基本上可以实现简单的动态DNS解析功能。需要更强的自定义功能,可以自己修改代码实现。
(1)假设web站点部署在上海电信。
(2)在上海电信部署Bind,提供动态解析服务,在上海电信部署主Web站点;
(3)在全国各地找几个比较重要的机房部署 lighttpd 服务器提供静态资源下载,如北京网通,广州电信两个机房各放置2台服务器,安装上 lighttpd+mod_cache+mod_proxy 等;
(4)配置子下载服务器的 lighttpd 的 modCache 功能,并设置 proxy.server 为主站点上海机房IP。
(5)当北京网通用户访问主站的静态文件时,通过动态DNS解析得到北京网通机房服务器的IP地址,浏览器就从北京网通服务器上下载文件了,提高了响应速度,同时降低了主站的压力。
这样一个简单的技术架构已经完成。对于 lighttpd+modCache 的详细配置参考http://www.linux.com.cn/modcache/。
<bean id="usersCache" parent="cacheBean" depends-on="cacheFactoryManager"> <constructor-arg value="Users" /> <property name="type" ref="local"/> <!-- in milliseconds, 24 hours, checked every hour --> <property name="expirationTime" value="86400000"/> <property name="expirationPeriod" value="3600000"/> <property name="transactional" value="false"/> <property name="keyRetrieval" value="false"/> <property name="type" value="false"/> <property name="timeoutTime" value="60"/> <property name="timeUnit" value="false"/> <property name="additionalProperties" value="Map<String, String>"/> <property name="valueSerializer" value="false"/> <property name="disableEviction" value="false"/> <property name="prefixAware" value="false"/> <property name="maxCacheSize" value="10g"/> <sizeLimit </bean>