Redisは、ある期間の受注数を統計します(Guavaキャッシュで解決を支援します).
11684 ワード
概要
会社はこのような需要があって、店舗のある時間帯(自然の日で計算して、24時間を超えない)類の注文数を統計する必要があります.これらの統計データは永続化されないため、パフォーマンスの問題を考慮してRedisを統計する準備ができています.-設計構想:Reidsの1つの秩序ある集合で実現する.店舗Idは、整列集合keyとして、注文IDは整列集合memberとして、Redisタイムスタンプが整列集合であるscoreに挿入される.増加するときはzadd(cacheKey,System.currentTimeMillis()、orderId)、統計するときはzcount(cacheKey,beginTimestamp,endTimestamp)で、ある時間帯の注文数を統計します.-思考:Redisを挿入するだけでなく、古いデータをどのように整理するか、つまり昨日の夜23:59:59までの古いデータを整理するかを考えなければなりません.自然な考えは、昨日までのタイムスタンプを生成し、挿入するたびに以前の古いデータを整理することです.-質問:-1.昨日のタイムスタンプを生成するたびに、時間のかかる操作でなくても必要ありません.一日に一度だけ生成すればいいので、他の生成は無駄です.では、昨日のタイムスタンプを再生成するにはどうすればいいのでしょうか.-2.挿入するたびにクリーンアップする必要はありません.毎日1回クリーンアップすればいいです.自然な日に注文数を保存しているからです.どうやって1日に1回掃除しますか?解決:guavaのキャッシュを用いて、類似のタイミングの機能を実現するのが全体的な方法です.キャッシュキーを使用して自動ロードは存在しません.Guavaのキャッシュからトリガを除去し、Redisの古いデータをクリーンアップします.-問題1:我々自身の業務状況によって、古いデータを整理する必要はなく、Redisメモリが爆発しないことを保証すればいい.数時間遅れたり、1日遅れて掃除したりしても問題はありません.したがって、昨日初めて生成されたタイムスタンプはローカルでキャッシュできます.その後、必要に応じてローカルキャッシュから直接取得すればいいので、毎回このタイムスタンプを生成する必要はありません.翌日に再生成するのを待つ必要はありません.-質問2:注文数を更新するときは、店舗IDと最近クリーンアップしたタイムスタンプをguavaキャッシュに挿入し、挿入する前に古いデータをクリーンアップします.guavaのキャッシュ内のkeyが期限切れでクリーンアップされると、リスナーがトリガーされ、古いデータが再びクリーンアップされます.
guava demoの使用
ソース実装
会社はこのような需要があって、店舗のある時間帯(自然の日で計算して、24時間を超えない)類の注文数を統計する必要があります.これらの統計データは永続化されないため、パフォーマンスの問題を考慮してRedisを統計する準備ができています.-設計構想:Reidsの1つの秩序ある集合で実現する.店舗Idは、整列集合keyとして、注文IDは整列集合memberとして、Redisタイムスタンプが整列集合であるscoreに挿入される.増加するときはzadd(cacheKey,System.currentTimeMillis()、orderId)、統計するときはzcount(cacheKey,beginTimestamp,endTimestamp)で、ある時間帯の注文数を統計します.-思考:Redisを挿入するだけでなく、古いデータをどのように整理するか、つまり昨日の夜23:59:59までの古いデータを整理するかを考えなければなりません.自然な考えは、昨日までのタイムスタンプを生成し、挿入するたびに以前の古いデータを整理することです.-質問:-1.昨日のタイムスタンプを生成するたびに、時間のかかる操作でなくても必要ありません.一日に一度だけ生成すればいいので、他の生成は無駄です.では、昨日のタイムスタンプを再生成するにはどうすればいいのでしょうか.-2.挿入するたびにクリーンアップする必要はありません.毎日1回クリーンアップすればいいです.自然な日に注文数を保存しているからです.どうやって1日に1回掃除しますか?解決:guavaのキャッシュを用いて、類似のタイミングの機能を実現するのが全体的な方法です.キャッシュキーを使用して自動ロードは存在しません.Guavaのキャッシュからトリガを除去し、Redisの古いデータをクリーンアップします.-問題1:我々自身の業務状況によって、古いデータを整理する必要はなく、Redisメモリが爆発しないことを保証すればいい.数時間遅れたり、1日遅れて掃除したりしても問題はありません.したがって、昨日初めて生成されたタイムスタンプはローカルでキャッシュできます.その後、必要に応じてローカルキャッシュから直接取得すればいいので、毎回このタイムスタンプを生成する必要はありません.翌日に再生成するのを待つ必要はありません.-質問2:注文数を更新するときは、店舗IDと最近クリーンアップしたタイムスタンプをguavaキャッシュに挿入し、挿入する前に古いデータをクリーンアップします.guavaのキャッシュ内のkeyが期限切れでクリーンアップされると、リスナーがトリガーされ、古いデータが再びクリーンアップされます.
guava demoの使用
public static void main(String[] args) throws ExecutionException, InterruptedException{
// LoadingCache,LoadingCache
LoadingCache studentCache
//CacheBuilder , newBuilder() CacheBuilder
= CacheBuilder.newBuilder()
// 8,
.concurrencyLevel(8)
// 8
.expireAfterWrite(8, TimeUnit.SECONDS)
// 10
.initialCapacity(10)
// 100, 100 LRU
.maximumSize(100)
//
.recordStats()
//
.removalListener(new RemovalListener
ソース実装
public class RedisUtil {
private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);
private RedisUtil() {
}
private static final String YESTERDAY = "yesterday";
private static final RedisExtraService redisExtraService = SpringContext.getBean(RedisExtraService.class);
// ,
private static final LoadingCache timeCache = CacheBuilder.newBuilder()
.maximumSize(1)
.expireAfterWrite(1, TimeUnit.DAYS)
.build(new CacheLoader() {
@Override
public Long load(String key) throws Exception {
return DateUtil.getYesterdayEndTime();
}
});
// key
private static final RemovalListener removalListener = new RemovalListener() {
@Override
public void onRemoval(RemovalNotification notification) {
String key = notification.getKey();
Long recentNeedRemoveTime = notification.getValue();
// , key
if (!recentNeedRemoveTime.equals(getRecentNeedRemoveTime()))
redisExtraService.zremrangeByScore(key, 0, recentNeedRemoveTime);
}
};
// redis key
private static final Cache entityCache = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterWrite(1, TimeUnit.DAYS)
.removalListener(removalListener)
.build();
public static void updateOrderCount(final String entityId, final String orderId) {
checkArgument(entityId != null && orderId != null);
try {
entityCache.get(entityId, new Callable() {
@Override
public Long call() throws Exception {
// key , , key
Long recentNeedRemoveTime = getRecentNeedRemoveTime();
redisExtraService.zremrangeByScore(entityId, 0, recentNeedRemoveTime);
return recentNeedRemoveTime;
}
});
} catch (ExecutionException e) {
logger.error(" entityCache , entityId: {}", entityId);
//
redisExtraService.zremrangeByScore(entityId, 0, getRecentNeedRemoveTime());
}
String cacheKey = getRedisKey(entityId);
Jedis jedis = redisExtraService.getResource();
// long yesterdayEndTime = DateUtil.getYesterdayEndTime();
// long yesterdayEndTime;
// try {
// yesterdayEndTime = timeCache.get(YESTERDAY);
// } catch (ExecutionException e) {
// logger.error(" timeCache yesterdayEndTime ");
// yesterdayEndTime = DateUtil.getYesterdayEndTime();
// }
try {
Pipeline pipeline = jedis.pipelined();
// pipeline.zremrangeByScore(cacheKey, 0, yesterdayEndTime);
pipeline.zadd(cacheKey, System.currentTimeMillis(), orderId);
pipeline.expire(cacheKey, OrderCacheConstant.EXPIRE_DAY);
pipeline.sync();
} finally {
redisExtraService.returnResource(jedis);
}
}
public static Long getOrderCount(String entityId, long beginTimestamp, long endTimestamp) {
checkArgument(entityId != null);
String cacheKey = getRedisKey(entityId);
return redisExtraService.zcount(cacheKey, beginTimestamp, endTimestamp);
}
protected static String getRedisKey(String entityId) {
return OrderCacheConstant.KEY_ORDER_COUNT + entityId;
}
/**
* ,
*
* @return
*/
private static Long getRecentNeedRemoveTime() {
Long yesterdayEndTime;
try {
yesterdayEndTime = timeCache.get(YESTERDAY);
} catch (ExecutionException e) {
logger.error(" timeCache yesterdayEndTime ");
yesterdayEndTime = DateUtil.getYesterdayEndTime();
}
return yesterdayEndTime;
}
}