很久沒有更新博客,希望以後有時間還是持續去寫,現在才發現這是很棒的過程。很早之前就整理過有關緩存的使用和介紹,現在將它貼出來,也作為個人筆記:
許多Web應用都將數據保存到RDBMS中,應用服務器從中讀取數據並在浏覽器中顯示。但隨著數據量的增大、訪問的集中,就會出現RDBMS的負擔加重、數據庫響應惡化、網站顯示延遲等重大影響。這時就該memcached大顯身手了。memcached是高性能的分布式內存緩存服務器。一般的使用目的是,通過緩存數據庫查詢結果,減少數據庫訪問次數,以提高動態Web應用的速度、提高可擴展性。
為了提高性能,memcached中保存的數據都存儲在memcached內置的內存存儲空間中。由於數據僅存在於內存中,因此重啟memcached、重啟操作系統會導致全部數據消失。另外,內容容量達到指定值之後,就基於LRU(Least Recently Used)算法自動刪除不使用的緩存。memcached本身是為緩存而設計的服務器,因此並沒有過多考慮數據的永久性問題。
Spring配置:
<beannamebeanname="memcachedClient" class="net.rubyeye.xmemcached.utils.XMemcachedClientFactoryBean"destroy-method="shutdown"> <property name="servers" value="${VIPCPS_MC_S1_HOST}:${VIPCPS_MC_S1_PORT}${VIPCPS_MC_S2_HOST}:${VIPCPS_MC_S2_PORT}${VIPCPS_MC_S3_HOST}:${VIPCPS_MC_S3_PORT}${VIPCPS_MC_S4_HOST}:${VIPCPS_MC_S4_PORT}${VIPCPS_MC_S5_HOST}:${VIPCPS_MC_S5_PORT}"></property> <!-- nio connection poolsize.不建議使用連接池,待性能測試 --> <property name="connectionPoolSize" value="1"></property> <!-- Distributed strategy --> <property name="sessionLocator"> <bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator"></bean> </property> </bean>
redis是一個key-value存儲系統。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sortedset --有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數據都是緩存在內存中。區別的是redis會周期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了master-slave(主從)同步。
Redis 是一個高性能的key-value數據庫。redis的出現,很大程度補償了memcached這類key/value存儲的不足,在部 分場合可以對關系數據庫起到很好的補充作用。它提供了Python,Ruby,Erlang,PHP客戶端,使用很方便。[1]
Redis支持主從同步。數據可以從主服務器向任意數量的從服務器上同步,從服務器可以是關聯其他從服務器的主服務器。這使得Redis可執行單層樹復制。從盤可以有意無意的對數據進行寫操作。由於完全實現了發布/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道並接收主服務器完整的消息發布記錄。同步對讀取操作的可擴展性和數據冗余很有幫助。
redis的存儲分為內存存儲、磁盤存儲和log文件三部分,配置文件中有三個參數對其進行配置。save seconds updates,save配置,指出在多長時間內,有多少次更新操作,就將數據同步到數據文件。這個可以多個條件配合,比如默認配置文件中的設置,就設置了三個條件。appendonly yes/no ,appendonly配置,指出是否在每次更新操作後進行日志記錄,如果不開啟,可能會在斷電時導致一段時間內的數據丟失。因為redis本身同步數據文件是按上面的save條件來同步的,所以有的數據會在一段時間內只存在於內存中。appendfsync no/always/everysec ,appendfsync配置,no表示等操作系統進行數據緩存同步到磁盤,always表示每次更新操作後手動調用fsync()將數據寫到磁盤,everysec表示每秒同步一次。
Redis更多的是作為Memched的一種替換而存在。
用key值和client代表值的hash值之間的某種運算來確定 存儲的server。
為了解決負載均衡,當server節點太少就要構造虛擬的server節點。
解決了簡單hash的以下弱點:
1)增刪市點時,更新效率低。當系統中存儲節點數量發生增加或減少時,映射公式將發生變化為hash(object)%(N±1),這將使得所有obiect的映射位置發生變化,整個系統數據對象的映射位置都需要重新進行計算,系統無法對外界訪問進行正常響應,將導致系統處於崩潰狀態。
2)平衡性差,未考慮節點性能差異。由於硬件性能的提升,新添加的節點具有更好的承載能力,如何對算法進行改進,使節點性能可以得到較好利用。
3)單調性不足。衡量數據分布技術的一項重要指標是單調性,單調性是指如果已經有一些內容通過哈希計算分派到了相應的緩沖中,當又有新的緩沖加入到系統中時,哈希的結果應能夠保證原有已分配的內容可以被映射到新的緩沖中去,而不會被映射到舊的緩沖集合中的其他緩沖區。
<!-- 默認 --> <bean id="jedisPoolConfig"class="redis.clients.jedis.JedisPoolConfig"> <property name="maxActive"value="${redis.pool.maxActive}" /> <property name="maxIdle"value="${redis.pool.maxIdle}" /> <property name="maxWait"value="${redis.pool.maxWait}" /> <property name="testOnBorrow"value="${redis.pool.testOnBorrow}" /> </bean> <bean id="stringRedisTemplate0" class="org.springframework.data.redis.core.StringRedisTemplate" p:connection-factory-ref="jedisConnectionFactory0"scope="prototype"></bean> <bean id="stringRedisTemplate1" class="org.springframework.data.redis.core.StringRedisTemplate" p:connection-factory-ref="jedisConnectionFactory1"scope="prototype"></bean> <!-- 自定義 --> <bean id="jedisConnectionFactory0" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName"value="${VIPCPS_REDIS_HOST_0}" /> <property name="port"value="${VIPCPS_REDIS_PORT_0}" /> <property name="poolConfig"ref="jedisPoolConfig" /> </bean> <bean id="jedisConnectionFactory1" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName"value="${VIPCPS_REDIS_HOST_1}" /> <property name="port"value="${VIPCPS_REDIS_PORT_1}" /> <property name="poolConfig"ref="jedisPoolConfig" /> </bean> <bean id="redisTemplateRouter" class="com.vipshop.unionweb.framework.redis.RedisTemplateRouter"> <constructor-arg> <list> <ref bean="stringRedisTemplate0"/> <ref bean="stringRedisTemplate1"/> </list> </constructor-arg> </bean>
public class RedisTemplateRouter { privatestatic finalLogger logger = LoggerFactory.getLogger(RedisTemplateRouter.class); privatestatic CRC32 crc32 = newCRC32(); /** * 服務數量 */ privatestatic intSERVER_COUNT = 1; privatestatic ListredisTemplates = newArrayList (); publicRedisTemplateRouter(List redisTemplates){ RedisTemplateRouter.redisTemplates= redisTemplates; SERVER_COUNT= redisTemplates.size(); } publicstatic List getRedisTemplates() { returnredisTemplates; } publicstatic StringRedisTemplategetRouteRedis(String key) { crc32.reset(); crc32.update(key.getBytes()); longcrc32Value = crc32.getValue(); intindex = Math.abs((int) (crc32Value% SERVER_COUNT)); logger.debug("route to redis [key:{},index:{},crc32:{}]",new Object[] {key, index, crc32Value}); returnredisTemplates.get(index); } }
用法:
RedisTemplate template= RedisTemplateRouter.getRouteRedis(key); Object result = template.opsForValue().get(key);
是一個純Java的進程內緩存框架;緩存在內存和磁盤存儲可以伸縮到數G; Ehcache是一種廣泛使用的開源Java分布式緩存;支持LRU、LFU和FIFO多種淘汰算法;可以對頁面、對象、數據進行緩存,同時支持集群/分布式緩存;
對象緩存就是將查詢的數據,添加到緩存中,下次再次查詢的時候直接從緩存中獲取,而不去數據庫中查詢。