您的位置:首页 > 运维架构

TOP K+LRU缓存刷新

2015-09-30 15:04 225 查看
本地缓存机制常被用来存储系统中变化频率不高的数据,常见的变化频率不高数据有:比如商品配置,可能商家的商品描述信息基本不变化,价格变化也不是很频繁,那可以存在缓存里减少访问数据库。又比如某类计算存在热数据,即某些问题的计算入参在短时间内频繁重,则可以把计算结果缓存起来。

设计了类似LRU+TOP K的思路,针对新来的请求先查缓存,若没有实时计算,并把结果添加到缓存,之后对缓存按照请求次数和最近访问时间排序(先按照时间由近到远,再按照请求次数由大到小,最终顺序为请求次数由大到小,次数相同的时间由近到远),每次更新后删除顺序值大于缓存SIZE的计算结果。

示例代码如下:

public class ComputeServiceWithCache {

/** 计算结果缓存MAP(用于查询) */

private volatile Map<String, ComputeResult> resultCacheMap = new HashMap<String, ComputeResult>();

/** 已排序缓存列表(用于排序,维护在内存中,提高排序效率) */

private List<ComputeResult> cacheRankList = new ArrayList<ComputeResult>();

/** 计算服务 */

private ComputeService computeService;

/** 缓存大小 */

private static final int CACHE_SIZE = 100;

/** 数值1 */

private static final int ONE = 1;

/**

* 计算买卖双方的关系

*

* @param buyerId 买家ID

* @param sellerId 卖家ID

* @return 计算结果

*/

public ComputeResult computeRelation(String buyerId, String sellerId) {

String cacheKey = buyerId + sellerId;

ComputeResult result = findRelationInCache(cacheKey);

if (null == result) {

result = computeService.compute(buyerId, sellerId);

addComputeResultToCache(result);

}

return result;

}

/**

* 添加缓存并对缓存按照访问次数和最近访问时间排序

*

* @param result 当前计算结果

*/

public synchronized void addComputeResultToCache(ComputeResult result) {

// 添加缓存

List<ComputeResult> cacheRankList = composeCacheRankList(result);

// 按照访问次数和最近访问时间对缓存排序

sortCache(cacheRankList);

resultCacheMap.put(result.getCacheKey(), result);

if (cacheRankList.size() >= CACHE_SIZE) {

ComputeResult lastRankResult = cacheRankList.get(cacheRankList.size() - 1);

resultCacheMap.remove(lastRankResult.getCacheKey());

}

}

/**

* 添加缓存

*

* @param result 当前计算结果

* @return cacheRankList 待排序缓存列表

*/

private List<ComputeResult> composeCacheRankList(ComputeResult result) {

result.setVisitCnt(ONE);

result.setVisitTime(new Date());

ComputeResult cachedResult = resultCacheMap.get(result.getCacheKey());

if (null != cachedResult) {

Integer currentVisitCnt = result.getVisitCnt() + ONE;

result.setVisitCnt(currentVisitCnt);

for (ComputeResult tempResult : cacheRankList) {

if (StringUtil.equals(tempResult.getCacheKey(), result.getCacheKey())) {

tempResult.setVisitCnt(currentVisitCnt);

}

}

} else {

cacheRankList.add(result);

}

return cacheRankList;

}

/**

* 按照访问次数和最近访问时间对缓存排序

* (先按照时间由近到远,再按照请求次数由大到小,最终顺序为请求次数由大到小,次数相同的时间由近到远)

* @param cacheRankList 待排序缓存列表

*/

private void sortCache(List<ComputeResult> cacheRankList) {

Collections.sort(cacheRankList, new Comparator<ComputeResult>() {

@Override

public int compare(ComputeResult left, ComputeResult right) {

return left.getVisitTime().after(right.getVisitTime()) ? -1 : 1;

}

});

Collections.sort(cacheRankList, new Comparator<ComputeResult>() {

@Override

public int compare(ComputeResult left, ComputeResult right) {

return left.getVisitCnt() - right.getVisitCnt();

}

});

}

private class ComputeResult {

/** 计算结果缓存key */

private String cacheKey;

/** 计算结果访问次数 */

private Integer visitCnt;

/** 计算结果最近访问时间 */

private Date visitTime;

/** 结果关系值 */

private Integer relationValue;

/**

* Getter method for property <tt>visitTime</tt>.

*

* @return property value of visitTime

*/

public Date getVisitTime() {

return visitTime;

}

/**

* Setter method for property <tt>visitTime</tt>.

*

* @param visitTime value to be assigned to property visitTime

*/

public void setVisitTime(Date visitTime) {

this.visitTime = visitTime;

}

/**

* Getter method for property <tt>cacheKey</tt>.

*

* @return property value of cacheKey

*/

public String getCacheKey() {

return cacheKey;

}

/**

* Setter method for property <tt>cacheKey</tt>.

*

* @param cacheKey value to be assigned to property cacheKey

*/

public void setCacheKey(String cacheKey) {

this.cacheKey = cacheKey;

}

/**

* Getter method for property <tt>visitCnt</tt>.

*

* @return property value of visitCnt

*/

public Integer getVisitCnt() {

return visitCnt;

}

/**

* Setter method for property <tt>visitCnt</tt>.

*

* @param visitCnt value to be assigned to property visitCnt

*/

public void setVisitCnt(Integer visitCnt) {

this.visitCnt = visitCnt;

}

/**

* Getter method for property <tt>relationValue</tt>.

*

* @return property value of relationValue

*/

public Integer getRelationValue() {

return relationValue;

}

/**

* Setter method for property <tt>relationValue</tt>.

*

* @param relationValue value to be assigned to property relationValue

*/

public void setRelationValue(Integer relationValue) {

this.relationValue = relationValue;

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: