listWorker(SearchReq param);
23 |
24 | Worker selectByKey(String name);
25 | }
--------------------------------------------------------------------------------
/l2cache-core/src/main/java/com/github/jesse/l2cache/schedule/RefreshExpiredCacheTask.java:
--------------------------------------------------------------------------------
1 | package com.github.jesse.l2cache.schedule;
2 |
3 | import com.github.jesse.l2cache.cache.Level1Cache;
4 |
5 | /**
6 | * 刷新过期缓存Task
7 | *
8 | * 该Task的主要目的是尽可能的保证 L1Cache 中是最新的数据。如guava、caffeine在访问时,若数据过期则先返回旧数据,再执行数据加载。
9 | * 如果 L1Cache 是 LoadingCache,并且自定义CuntomCacheLoader中 L2Cache 不为空,则同时刷新L1Cache和L2Cache。
10 | *
11 | * @author chenck
12 | * @date 2020/7/6 9:58
13 | */
14 | public class RefreshExpiredCacheTask implements Runnable {
15 |
16 | private final Level1Cache level1Cache;
17 |
18 | public RefreshExpiredCacheTask(Level1Cache level1Cache) {
19 | this.level1Cache = level1Cache;
20 | }
21 |
22 | @Override
23 | public void run() {
24 | this.level1Cache.refreshAllExpireCache();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/resources/static/admin/common/js/rule-add.js:
--------------------------------------------------------------------------------
1 | $("#form-add").validate({
2 | submitHandler:function(form){
3 | add();
4 | }
5 | });
6 |
7 | function add() {
8 | var dataFormJson=$("#form-add").serialize();
9 | $.ajax({
10 | cache : true,
11 | type : "POST",
12 | url : "/rule/add",
13 | data : dataFormJson,
14 | headers: {
15 | "Authorization":getCookie("token")
16 | },
17 | async : false,
18 | error : function(XMLHttpRequest){
19 | $.modal.alertError(XMLHttpRequest.responseJSON.msg);
20 | var token = getCookie("token");
21 | if(XMLHttpRequest.status == 1000 && ( token == "undefined" || token =="")){
22 | top.location.href = '/user/login';
23 | }
24 | },
25 | success : function(data) {
26 | $.operate.saveSuccess(data);
27 | }
28 | });
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-worker/src/main/java/com/jd/platform/hotkey/worker/netty/pusher/store/HotkeyTempStore.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.worker.netty.pusher.store;
2 |
3 | import com.jd.platform.hotkey.common.model.HotKeyModel;
4 |
5 | import java.util.concurrent.LinkedBlockingQueue;
6 |
7 | /**
8 | * 已热待上报入库的热key集中营
9 | * @author wuweifeng
10 | * @version 1.0
11 | * @date 2020-08-31
12 | */
13 | public class HotkeyTempStore {
14 | /**
15 | * 热key集中营
16 | */
17 | private static LinkedBlockingQueue hotKeyStoreQueue = new LinkedBlockingQueue<>();
18 |
19 | public static void push(HotKeyModel model) {
20 | hotKeyStoreQueue.offer(model);
21 | }
22 |
23 | public static LinkedBlockingQueue getQueue() {
24 | return hotKeyStoreQueue;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/java/com/jd/platform/hotkey/dashboard/mapper/UserMapper.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.dashboard.mapper;
2 |
3 | import com.jd.platform.hotkey.dashboard.common.domain.req.SearchReq;
4 | import com.jd.platform.hotkey.dashboard.model.User;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | import java.util.List;
8 |
9 | @Mapper
10 | public interface UserMapper {
11 | int deleteByPrimaryKey(Integer id);
12 |
13 | int insertSelective(User user);
14 |
15 | User selectByPrimaryKey(Integer id);
16 |
17 | int updateByPk(User record);
18 |
19 | List listUser(SearchReq param);
20 |
21 | User findByNameAndPwd(User user);
22 |
23 | List listApp();
24 |
25 | List selectHkUserList(User user);
26 |
27 | User selectByUserName(String userName);
28 | }
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/resources/static/admin/common/js/key-edit.js:
--------------------------------------------------------------------------------
1 | $("#form-edit").validate({
2 |
3 | submitHandler : function(form) {
4 | edit();
5 | }
6 | });
7 |
8 | function edit() {
9 | var dataFormJson = $("#form-edit").serialize();
10 | $.ajax({
11 | cache : true,
12 | type : "POST",
13 | url : "/key/edit",
14 | data : dataFormJson,
15 | headers: {
16 | "Authorization":getCookie("token")
17 | },
18 | async : false,
19 | error : function(XMLHttpRequest){
20 | $.modal.alertError(XMLHttpRequest.responseJSON.msg);
21 | var token = getCookie("token");
22 | if(XMLHttpRequest.status == 1000 && ( token == "undefined" || token =="")){
23 | top.location.href = '/user/login';
24 | }
25 | },
26 | success : function(data) {
27 | $.operate.saveSuccess(data);
28 | }
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/resources/static/admin/common/js/user-edit.js:
--------------------------------------------------------------------------------
1 | $("#form-edit").validate({
2 |
3 | submitHandler : function(form) {
4 | edit();
5 | }
6 | });
7 |
8 | function edit() {
9 | var dataFormJson = $("#form-edit").serialize();
10 | $.ajax({
11 | cache : true,
12 | type : "POST",
13 | url : "/user/edit",
14 | data : dataFormJson,
15 | headers: {
16 | "Authorization":getCookie("token")
17 | },
18 | async : false,
19 | error : function(XMLHttpRequest){
20 | $.modal.alertError(XMLHttpRequest.responseJSON.msg);
21 | var token = getCookie("token");
22 | if(XMLHttpRequest.status == 1000 && ( token == "undefined" || token =="")){
23 | top.location.href = '/user/login';
24 | }
25 | },
26 | success : function(data) {
27 | $.operate.saveSuccess(data);
28 | }
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/java/com/jd/platform/hotkey/dashboard/mapper/SummaryMapper.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.dashboard.mapper;
2 |
3 | import com.jd.platform.hotkey.dashboard.common.domain.req.SearchReq;
4 | import com.jd.platform.hotkey.dashboard.common.domain.vo.HitCountVo;
5 | import com.jd.platform.hotkey.dashboard.model.Summary;
6 | import org.apache.ibatis.annotations.Mapper;
7 |
8 | import java.util.Date;
9 | import java.util.List;
10 |
11 | /**
12 | * @author liyunfeng31
13 | */
14 | @Mapper
15 | public interface SummaryMapper {
16 |
17 | /**
18 | * records
19 | * @param records records
20 | * @return row
21 | */
22 | int saveOrUpdate(Summary records);
23 |
24 | List listRuleHitCount(SearchReq req);
25 |
26 | int clearExpireData(String app, Date expireDate);
27 | }
--------------------------------------------------------------------------------
/l2cache-spring-boot-starter/src/main/java/com/github/jesse/l2cache/spring/L2CacheProperties.java:
--------------------------------------------------------------------------------
1 | package com.github.jesse.l2cache.spring;
2 |
3 | import com.github.jesse.l2cache.CacheConfig;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 | import org.springframework.cloud.context.config.annotation.RefreshScope;
6 |
7 | /**
8 | * 一二级缓存属性配置
9 | * 注:Caffeine 一级缓存,Redis 二级缓存
10 | *
11 | * @author chenck
12 | * @date 2020/4/26 20:44
13 | */
14 | @ConfigurationProperties(prefix = "l2cache")
15 | @RefreshScope
16 | public class L2CacheProperties {
17 | /**
18 | * 缓存配置
19 | */
20 | private CacheConfig config;
21 |
22 | public CacheConfig getConfig() {
23 | return config;
24 | }
25 |
26 | public void setConfig(CacheConfig config) {
27 | this.config = config;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/java/com/jd/platform/hotkey/dashboard/controller/TestController.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.dashboard.controller;
2 |
3 | /**
4 | * @author wuweifeng
5 | * @version 1.0
6 | * @date 2020-07-16
7 | */
8 | //@RestController
9 | //public class TestController {
10 | // @Resource
11 | // private IConfigCenter configCenter;
12 | //
13 | // @RequestMapping("delete")
14 | // public Object delete(String key) {
15 | //// configCenter.putAndGrant(ConfigConstant.hotKeyRecordPath + "sample" + "/" + key, cn.weeget.hotkey.common.tool.Constant.DEFAULT_DELETE_VALUE, 1);
16 | // configCenter.putAndGrant(ConfigConstant.hotKeyRecordPath + "bbb" + "/" + key, "", 60);
17 | //// configCenter.delete(ConfigConstant.hotKeyPath + "sample" + "/" + key);
18 | //
19 | // return "1";
20 | // }
21 | //}
22 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/java/com/jd/platform/hotkey/dashboard/common/domain/vo/RuleLineChartVo.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.dashboard.common.domain.vo;
2 |
3 | /**
4 | * @author liyunfeng31
5 | */
6 | public class RuleLineChartVo {
7 |
8 | private String rule;
9 |
10 | private Integer count;
11 |
12 | public RuleLineChartVo() {
13 | }
14 |
15 | public RuleLineChartVo(String rule, Integer count) {
16 | this.rule = rule;
17 | this.count = count;
18 | }
19 |
20 | public String getRule() {
21 | return rule;
22 | }
23 |
24 | public void setRule(String rule) {
25 | this.rule = rule;
26 | }
27 |
28 | public Integer getCount() {
29 | return count;
30 | }
31 |
32 | public void setCount(Integer count) {
33 | this.count = count;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/resources/static/admin/assets/js/bootstrap/js/bootstrap-table/locale/bootstrap-table-zh-CN.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * bootstrap-table - v1.9.0 - 2015-09-30
3 | * https://github.com/wenzhixin/bootstrap-table
4 | * Copyright (c) 2015 zhixin wen
5 | * Licensed MIT License
6 | */
7 | !function(a){"use strict";a.fn.bootstrapTable.locales["zh-CN"]={formatLoadingMessage:function(){return"正在努力地加载数据中,请稍候……"},formatRecordsPerPage:function(a){return"每页显示 "+a+" 条记录"},formatShowingRows:function(a,b,c){return"显示第 "+a+" 到第 "+b+" 条记录,总共 "+c+" 条记录"},formatSearch:function(){return"搜索"},formatNoMatches:function(){return"没有找到匹配的记录"},formatPaginationSwitch:function(){return"隐藏/显示分页"},formatRefresh:function(){return"刷新"},formatToggle:function(){return"切换"},formatColumns:function(){return"列"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["zh-CN"])}(jQuery);
8 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-sample/src/main/java/com/jd/platform/hotkey/sample/config/RedisConfig.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.sample.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.data.redis.connection.RedisConnectionFactory;
6 | import org.springframework.data.redis.core.StringRedisTemplate;
7 |
8 | /**
9 | * @author wuweifeng wrote on 2017/10/27.
10 | */
11 | @Configuration
12 | public class RedisConfig {
13 |
14 | @Bean(name = {"redisTemplate", "stringRedisTemplate"})
15 | public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
16 | StringRedisTemplate redisTemplate = new StringRedisTemplate();
17 | redisTemplate.setConnectionFactory(factory);
18 | return redisTemplate;
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/resources/static/admin/assets/js/tree/treetable/stylesheets/jquery.treetable.css:
--------------------------------------------------------------------------------
1 | table.treetable span.indenter {
2 | display: inline-block;
3 | margin: 0;
4 | padding: 0;
5 | text-align: right;
6 |
7 | /* Disable text selection of nodes (for better D&D UX) */
8 | user-select: none;
9 | -khtml-user-select: none;
10 | -moz-user-select: none;
11 | -o-user-select: none;
12 | -webkit-user-select: none;
13 |
14 | /* Force content-box box model for indenter (Bootstrap compatibility) */
15 | -webkit-box-sizing: content-box;
16 | -moz-box-sizing: content-box;
17 | box-sizing: content-box;
18 |
19 | width: 19px;
20 | }
21 |
22 | table.treetable span.indenter a {
23 | background-position: left center;
24 | background-repeat: no-repeat;
25 | display: inline-block;
26 | text-decoration: none;
27 | width: 19px;
28 | }
29 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-client/src/main/java/com/jd/platform/hotkey/client/callback/ReceiveNewKeySubscribe.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.client.callback;
2 |
3 | import com.google.common.eventbus.Subscribe;
4 | import com.jd.platform.hotkey.common.model.HotKeyModel;
5 |
6 |
7 | /**
8 | * 监听有新key推送事件
9 | * @author wuweifeng wrote on 2020-02-21
10 | * @version 1.0
11 | */
12 | public class ReceiveNewKeySubscribe {
13 |
14 | private ReceiveNewKeyListener receiveNewKeyListener = new DefaultNewKeyListener();
15 |
16 | @Subscribe
17 | public void newKeyComing(ReceiveNewKeyEvent event) {
18 | HotKeyModel hotKeyModel = event.getModel();
19 | if (hotKeyModel == null) {
20 | return;
21 | }
22 | //收到新key推送
23 | if (receiveNewKeyListener != null) {
24 | receiveNewKeyListener.newKey(hotKeyModel);
25 | }
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-client/src/main/java/com/jd/platform/hotkey/client/core/eventbus/EventBusCenter.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.client.core.eventbus;
2 |
3 | import com.google.common.eventbus.EventBus;
4 |
5 | /**
6 | * @author wuweifeng wrote on 2020-01-07
7 | * @version 1.0
8 | */
9 | @SuppressWarnings("UnstableApiUsage")
10 | public class EventBusCenter {
11 |
12 | private static final EventBus eventBus = new EventBus();
13 |
14 | private EventBusCenter() {
15 |
16 | }
17 |
18 | public static EventBus getInstance() {
19 | return eventBus;
20 | }
21 |
22 | public static void register(Object obj) {
23 | eventBus.register(obj);
24 | }
25 |
26 | public static void unregister(Object obj) {
27 | eventBus.unregister(obj);
28 | }
29 |
30 | public static void post(Object obj) {
31 | eventBus.post(obj);
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-worker/src/main/java/com/jd/platform/hotkey/worker/netty/dashboard/DashboardHolder.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.worker.netty.dashboard;
2 |
3 | import com.jd.platform.hotkey.common.model.HotKeyMsg;
4 | import com.jd.platform.hotkey.common.model.MsgBuilder;
5 | import com.jd.platform.hotkey.common.model.typeenum.MessageType;
6 | import io.netty.channel.Channel;
7 |
8 | /**
9 | * @author wuweifeng
10 | * @version 1.0
11 | * @date 2020-08-31
12 | */
13 | public class DashboardHolder {
14 | /**
15 | * 是否连上了dashboard
16 | */
17 | public static boolean hasConnected = false;
18 | /**
19 | * channel
20 | */
21 | public static Channel channel = null;
22 |
23 | public static void flushToDashboard(String message) {
24 | channel.writeAndFlush(MsgBuilder.buildByteBuf(new HotKeyMsg(MessageType.REQUEST_HOT_KEY, message)));
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-common/src/main/java/com/jd/platform/hotkey/common/tool/HotKeyPathTool.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.common.tool;
2 |
3 | import com.jd.platform.hotkey.common.configcenter.ConfigConstant;
4 | import com.jd.platform.hotkey.common.model.HotKeyModel;
5 |
6 | /**
7 | * @author wuweifeng wrote on 2020-02-24
8 | * @version 1.0
9 | */
10 | public class HotKeyPathTool {
11 | /**
12 | * app的热key存放地址,client会监听该地址,当有热key变化时会响应
13 | */
14 | public static String keyPath(HotKeyModel hotKeyModel) {
15 | return ConfigConstant.hotKeyPath + hotKeyModel.getAppName() + "/" + hotKeyModel.getKey();
16 | }
17 |
18 | /**
19 | * worker将热key推送到该地址,供dashboard监听入库做记录
20 | */
21 | public static String keyRecordPath(HotKeyModel hotKeyModel) {
22 | return ConfigConstant.hotKeyRecordPath + hotKeyModel.getAppName() + "/" + hotKeyModel.getKey();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-client/src/main/java/com/jd/platform/hotkey/client/core/key/KeyHandlerFactory.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.client.core.key;
2 |
3 | import com.jd.platform.hotkey.common.model.HotKeyModel;
4 | import com.jd.platform.hotkey.common.model.KeyCountModel;
5 |
6 | /**
7 | * @author wuweifeng wrote on 2020-01-06
8 | * @version 1.0
9 | */
10 | public class KeyHandlerFactory {
11 | private static final DefaultKeyHandler iKeyHandler = new DefaultKeyHandler();
12 |
13 | private KeyHandlerFactory() {
14 | }
15 |
16 | public static IKeyPusher getPusher() {
17 | return iKeyHandler.keyPusher();
18 | }
19 |
20 | public static IKeyCollector getCollector() {
21 | return iKeyHandler.keyCollector();
22 | }
23 |
24 | public static IKeyCollector getCounter() {
25 | return iKeyHandler.keyCounter();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/resources/static/admin/assets/js/chart/polarChart.js:
--------------------------------------------------------------------------------
1 | var chartData = [
2 | {
3 | value : Math.random(),
4 | color: "#6ADAE4"
5 | },
6 | {
7 | value : Math.random(),
8 | color: "#F89406"
9 | },
10 | {
11 | value : Math.random(),
12 | color: "#FF0064"
13 | },
14 | {
15 | value : Math.random(),
16 | color: "#3498DB"
17 | },
18 | {
19 | value : Math.random(),
20 | color: "#1ABC9C"
21 | },
22 | {
23 | value : Math.random(),
24 | color: "#E74C3C"
25 | }
26 | ];
27 | var myPolarArea = new Chart(document.getElementById("canvas3").getContext("2d")).PolarArea(chartData);
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-client/src/main/java/com/jd/platform/hotkey/client/log/DefaultLogger.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.client.log;
2 |
3 | import org.slf4j.LoggerFactory;
4 |
5 | /**
6 | * @author wuweifeng
7 | * @version 1.0
8 | * @date 2020-04-21
9 | */
10 | public class DefaultLogger implements HotKeyLogger {
11 | @Override
12 | public void debug(Class> className, String info) {
13 | LoggerFactory.getLogger(className).debug(info);
14 | }
15 |
16 | @Override
17 | public void info(Class> className, String info) {
18 | LoggerFactory.getLogger(className).info(info);
19 | }
20 |
21 | @Override
22 | public void error(Class> className, String info) {
23 | LoggerFactory.getLogger(className).error(info);
24 | }
25 |
26 | @Override
27 | public void warn(Class> className, String info) {
28 | LoggerFactory.getLogger(className).warn(info);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/l2cache-core/src/main/java/com/github/jesse/l2cache/content/NullValue.java:
--------------------------------------------------------------------------------
1 | package com.github.jesse.l2cache.content;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * 简单的可序列化类,用作{@code null}替换缓存存储,否则不支持{@code null}值
7 | *
8 | * @author chenck
9 | * @date 2020/7/1 17:39
10 | */
11 | public class NullValue implements Serializable {
12 |
13 | private static final long serialVersionUID = 1L;
14 |
15 | public static final Object INSTANCE = new NullValue();
16 |
17 | private NullValue() {
18 | }
19 |
20 | private Object readResolve() {
21 | return INSTANCE;
22 | }
23 |
24 | @Override
25 | public boolean equals(Object obj) {
26 | return (this == obj || obj == null);
27 | }
28 |
29 | @Override
30 | public int hashCode() {
31 | return NullValue.class.hashCode();
32 | }
33 |
34 | @Override
35 | public String toString() {
36 | return "NullValue";
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/resources/static/admin/assets/js/progress-bar/number-pb.css:
--------------------------------------------------------------------------------
1 | .number-pb {
2 | background-color: #DDDDDD;
3 | height: 10px;
4 | margin: 10px 0;
5 | position: relative;
6 | }
7 | .number-pb .number-pb-shown {
8 | position: absolute;
9 | background-color: #65C3DF;
10 | /* background-image: linear-gradient(to right, #176785, #499989); */
11 | top: -1px;
12 | left: 0;
13 | height: 11px;
14 | }
15 | .number-pb .number-pb-num {
16 | position: absolute;
17 | background-color: #fff;
18 | left: 0;
19 | top: -0.45em;
20 | padding: 0 5px;
21 | min-width: 20px;
22 | }
23 | .number-pb-shown.dream {
24 | /* background-image: linear-gradient(to right, #0e153a, #1d2b64, #f8cdda); */
25 | background: #45B6B0;
26 | }
27 | .number-pb-shown.sun {
28 | /* background-image: linear-gradient(to right, #0f1b58, #e0a681, #e5e9bf); */
29 | background: #FF6B6B;
30 | }
31 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-client/src/main/java/com/jd/platform/hotkey/client/log/JdLogger.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.client.log;
2 |
3 | /**
4 | * @author wuweifeng wrote on 2020-02-24
5 | * @version 1.0
6 | */
7 | public class JdLogger {
8 | private static HotKeyLogger logger = new DefaultLogger();
9 |
10 | public static void setLogger(HotKeyLogger log) {
11 | if (log != null) {
12 | logger = log;
13 | }
14 | }
15 |
16 | public static void debug(Class className, String info) {
17 | logger.debug(className, info);
18 | }
19 |
20 | public static void info(Class className, String info) {
21 | logger.info(className, info);
22 | }
23 |
24 | public static void warn(Class className, String info) {
25 | logger.warn(className, info);
26 | }
27 |
28 | public static void error(Class className, String info) {
29 | logger.error(className, info);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/java/com/jd/platform/hotkey/dashboard/mapper/KeyRecordMapper.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.dashboard.mapper;
2 |
3 | import com.jd.platform.hotkey.dashboard.common.domain.req.SearchReq;
4 | import com.jd.platform.hotkey.dashboard.model.KeyRecord;
5 | import com.jd.platform.hotkey.dashboard.model.Statistics;
6 | import org.apache.ibatis.annotations.Mapper;
7 |
8 | import java.util.Date;
9 | import java.util.List;
10 |
11 | /**
12 | * @author liyunfeng31
13 | */
14 | @Mapper
15 | public interface KeyRecordMapper {
16 |
17 | int insertSelective(KeyRecord record);
18 |
19 | KeyRecord selectByPrimaryKey(Long id);
20 |
21 | List listKeyRecord(SearchReq req);
22 |
23 | int batchInsert(List list);
24 |
25 | List maxHotKey(SearchReq req);
26 |
27 | List statisticsByRule(SearchReq req);
28 |
29 | int clearExpireData(String app, Date expireDate);
30 | }
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-worker/src/main/java/com/jd/platform/hotkey/worker/tool/SafeExecute.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.worker.tool;
2 |
3 | import java.util.function.Consumer;
4 |
5 | /**
6 | * @author wuweifeng wrote on 2020-03-10
7 | * @version 1.0
8 | */
9 | public class SafeExecute {
10 |
11 | public static void execute(Consumer consumer, String exMsg) {
12 | try {
13 | consumer.accept(null);
14 | } catch (Exception e) {
15 | System.out.println(exMsg);
16 | }
17 | }
18 |
19 | public static void main(String[] args) {
20 | execute(s -> doSome1(0), "exception");
21 | }
22 |
23 | public static void doSome(int i) {
24 | try {
25 | int j = 1 / i;
26 | } catch (Exception e) {
27 | System.out.println("exception");
28 | }
29 | }
30 |
31 | public static void doSome1(int i) {
32 | int j = 1 / i;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/l2cache-core/src/test/resources/redisson.yaml:
--------------------------------------------------------------------------------
1 | # cluster sentinel with high availability
2 | singleServerConfig:
3 | # 节点地址
4 | address: "redis://127.0.0.1:6379"
5 | # 密码
6 | password:
7 | # 连接空闲超时,单位:毫秒,默认10000
8 | idleConnectionTimeout: 10000
9 | # 连接超时,单位:毫秒,默认10000
10 | connectTimeout: 10000
11 | # 命令等待超时,单位:毫秒,默认3000
12 | timeout: 3000
13 | # 命令失败重试次数,默认3
14 | retryAttempts: 3
15 | # 命令重试发送时间间隔,单位:毫秒,默认1500
16 | retryInterval: 1500
17 | # 单个连接最大订阅数量,默认5
18 | subscriptionsPerConnection: 5
19 | # 客户端名称,默认null
20 | clientName: null
21 | # 发布和订阅连接的最小空闲连接数(默认1)
22 | subscriptionConnectionMinimumIdleSize: 1
23 | # 发布和订阅连接池大小(默认50)
24 | subscriptionConnectionPoolSize: 50
25 | # 最小空闲连接数(默认32)
26 | connectionMinimumIdleSize: 10
27 | # 连接池大小(默认64)
28 | connectionPoolSize: 64
29 | # 数据库编号,默认0
30 | database: 0
31 | # 线程池数量
32 | threads: 2
33 | # Netty线程池数量
34 | nettyThreads: 2
35 | # 编码,序列化反序列化
36 | codec: ! {}
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-common/src/main/java/com/jd/platform/hotkey/common/model/typeenum/MessageType.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.common.model.typeenum;
2 |
3 | /**
4 | * @author wuweifeng wrote on 2020-01-06
5 | * @version 1.0
6 | */
7 | public enum MessageType {
8 | APP_NAME((byte) 1),
9 | REQUEST_NEW_KEY((byte) 2),
10 | RESPONSE_NEW_KEY((byte) 3),
11 | REQUEST_HIT_COUNT((byte) 7), //命中率
12 | REQUEST_HOT_KEY((byte) 8), //热key,worker->dashboard
13 | PING((byte) 4), PONG((byte) 5),
14 | EMPTY((byte) 6);
15 |
16 | private byte type;
17 |
18 | MessageType(byte type) {
19 | this.type = type;
20 | }
21 |
22 | public byte getType() {
23 | return type;
24 | }
25 |
26 | public static MessageType get(byte type) {
27 | for (MessageType value : values()) {
28 | if (value.type == type) {
29 | return value;
30 | }
31 | }
32 | return null;
33 | }
34 | }
--------------------------------------------------------------------------------
/l2cache-core/src/test/java/com/github/jesse/l2cache/test/Test1.java:
--------------------------------------------------------------------------------
1 | package com.github.jesse.l2cache.test;
2 |
3 | import org.redisson.api.RLock;
4 | import org.redisson.api.RedissonClient;
5 |
6 | import java.util.concurrent.TimeUnit;
7 | import java.util.concurrent.atomic.AtomicInteger;
8 |
9 | /**
10 | * @author chenck
11 | * @date 2020/12/3 18:47
12 | */
13 | public class Test1 {
14 |
15 | public static void main(String[] args) {
16 | AtomicInteger waitRefreshNum = new AtomicInteger();
17 | System.out.println("获取:" + waitRefreshNum.get());
18 | System.out.println("加1:" + waitRefreshNum.getAndIncrement());
19 | System.out.println("获取:" + waitRefreshNum.get());
20 | System.out.println("加1:" + waitRefreshNum.getAndIncrement());
21 |
22 | System.out.println("获取:" + waitRefreshNum.get());
23 | System.out.println(waitRefreshNum.getAndSet(0));
24 | System.out.println("获取:" + waitRefreshNum.get());
25 |
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-client/src/main/java/com/jd/platform/hotkey/client/cache/CacheFactory.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.client.cache;
2 |
3 | import com.jd.platform.hotkey.client.core.rule.KeyRuleHolder;
4 |
5 | /**
6 | * 用户可以自定义cache
7 | * @author wuweifeng wrote on 2020-02-24
8 | * @version 1.0
9 | */
10 | public class CacheFactory {
11 | private static final LocalCache DEFAULT_CACHE = new DefaultCaffeineCache();
12 |
13 | /**
14 | * 创建一个本地缓存实例
15 | */
16 | public static LocalCache build(int duration) {
17 | return new CaffeineCache(duration);
18 | }
19 |
20 | public static LocalCache getNonNullCache(String key) {
21 | LocalCache localCache = getCache(key);
22 | if (localCache == null) {
23 | return DEFAULT_CACHE;
24 | }
25 | return localCache;
26 | }
27 |
28 | public static LocalCache getCache(String key) {
29 | return KeyRuleHolder.findByKey(key);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/l2cache-core/src/main/java/com/github/jesse/l2cache/util/pool/CallableMdcWrapper.java:
--------------------------------------------------------------------------------
1 | package com.github.jesse.l2cache.util.pool;
2 |
3 | import org.slf4j.MDC;
4 |
5 | import java.util.Map;
6 | import java.util.concurrent.Callable;
7 |
8 | /**
9 | * @author chenck
10 | * @date 2021/5/11 17:09
11 | */
12 | public class CallableMdcWrapper implements Callable {
13 |
14 | private static final long serialVersionUID = 1L;
15 |
16 | Callable callable;
17 | Map contextMap;
18 |
19 | public CallableMdcWrapper(Callable callable) {
20 | this.callable = callable;
21 | this.contextMap = MDC.getCopyOfContextMap();
22 | }
23 |
24 | @Override
25 | public T call() throws Exception {
26 | Map oldContext = MdcUtil.beforeExecution(contextMap);
27 | try {
28 | return callable.call();
29 | } finally {
30 | MdcUtil.afterExecution(oldContext);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/l2cache-spring-boot-starter/src/main/java/com/github/jesse/l2cache/spring/EnableL2Cache.java:
--------------------------------------------------------------------------------
1 | package com.github.jesse.l2cache.spring;
2 |
3 | import com.github.jesse.l2cache.spring.config.HotKeyConfiguration;
4 | import com.github.jesse.l2cache.spring.config.L2CacheConfiguration;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.context.annotation.Import;
7 |
8 | import java.lang.annotation.Documented;
9 | import java.lang.annotation.ElementType;
10 | import java.lang.annotation.Retention;
11 | import java.lang.annotation.RetentionPolicy;
12 | import java.lang.annotation.Target;
13 |
14 | /**
15 | * 开启 L2Cache 组件
16 | *
17 | * 注:Spring Enable 注解模式
18 | *
19 | * @author chenck
20 | * @date 2020/5/26 17:10
21 | */
22 | @Retention(RetentionPolicy.RUNTIME)
23 | @Target({ElementType.TYPE})
24 | @Documented
25 | @Import({L2CacheConfiguration.class, HotKeyConfiguration.class})
26 | @Configuration
27 | public @interface EnableL2Cache {
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-worker/src/main/java/com/jd/platform/hotkey/worker/model/TotalCount.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.worker.model;
2 |
3 | /**
4 | * @author wuweifeng
5 | * @version 1.0
6 | * @date 2020-05-20
7 | */
8 | public class TotalCount {
9 | private long totalReceiveCount;
10 | private long totalDealCount;
11 |
12 | public TotalCount(long totalReceiveCount, long totalDealCount) {
13 | this.totalReceiveCount = totalReceiveCount;
14 | this.totalDealCount = totalDealCount;
15 | }
16 |
17 | public long getTotalReceiveCount() {
18 | return totalReceiveCount;
19 | }
20 |
21 | public void setTotalReceiveCount(long totalReceiveCount) {
22 | this.totalReceiveCount = totalReceiveCount;
23 | }
24 |
25 | public long getTotalDealCount() {
26 | return totalDealCount;
27 | }
28 |
29 | public void setTotalDealCount(long totalDealCount) {
30 | this.totalDealCount = totalDealCount;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-dashboard/src/main/java/com/jd/platform/hotkey/dashboard/cache/CaffeineBuilder.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.dashboard.cache;
2 |
3 | import com.github.benmanes.caffeine.cache.Cache;
4 | import com.github.benmanes.caffeine.cache.Caffeine;
5 |
6 | import java.util.concurrent.TimeUnit;
7 |
8 | /**
9 | * @author wuweifeng wrote on 2019-12-12
10 | * @version 1.0
11 | */
12 | public class CaffeineBuilder {
13 |
14 | public static Cache cache(int duration) {
15 | return cache(128, 1000000, duration);
16 | }
17 |
18 |
19 | /**
20 | * 构建所有来的要缓存的key getCache
21 | */
22 | public static Cache cache(int minSize, int maxSize, int expireSeconds) {
23 | return Caffeine.newBuilder()
24 | .initialCapacity(minSize)//初始大小
25 | .maximumSize(maxSize)//最大数量
26 | .expireAfterWrite(expireSeconds, TimeUnit.SECONDS)//过期时间
27 | .build();
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/README.en.md:
--------------------------------------------------------------------------------
1 | # l2cache
2 |
3 | #### Description
4 | 基于 `Caffeine`、 `Redis` 、 `Spring Cache` 实现的二级缓存。
5 |
6 | #### Software Architecture
7 | Software architecture description
8 |
9 | #### Installation
10 |
11 | 1. xxxx
12 | 2. xxxx
13 | 3. xxxx
14 |
15 | #### Instructions
16 |
17 | 1. xxxx
18 | 2. xxxx
19 | 3. xxxx
20 |
21 | #### Contribution
22 |
23 | 1. Fork the repository
24 | 2. Create Feat_xxx branch
25 | 3. Commit your code
26 | 4. Create Pull Request
27 |
28 |
29 | #### Gitee Feature
30 |
31 | 1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
32 | 2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
33 | 3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
34 | 4. The most valuable open source project [GVP](https://gitee.com/gvp)
35 | 5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
36 | 6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
37 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-client/src/main/java/com/jd/platform/hotkey/client/core/key/DefaultKeyHandler.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.client.core.key;
2 |
3 | import com.jd.platform.hotkey.common.model.HotKeyModel;
4 | import com.jd.platform.hotkey.common.model.KeyCountModel;
5 |
6 | /**
7 | * @author wuweifeng wrote on 2020-02-25
8 | * @version 1.0
9 | */
10 | public class DefaultKeyHandler {
11 | private IKeyPusher iKeyPusher = new NettyKeyPusher();
12 |
13 | private IKeyCollector iKeyCollector = new TurnKeyCollector();
14 |
15 | private IKeyCollector iKeyCounter = new TurnCountCollector();
16 |
17 |
18 | public IKeyPusher keyPusher() {
19 | return iKeyPusher;
20 | }
21 |
22 | public IKeyCollector keyCollector() {
23 | return iKeyCollector;
24 | }
25 |
26 | public IKeyCollector keyCounter() {
27 | return iKeyCounter;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-worker/src/main/java/com/jd/platform/hotkey/worker/starters/InitStarter.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.worker.starters;
2 |
3 | import com.jd.platform.hotkey.worker.tool.InitConstant;
4 | import org.springframework.beans.factory.annotation.Value;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.stereotype.Component;
7 |
8 | /**
9 | * @author wuweifeng
10 | * @version 1.0
11 | * @date 2020-05-22
12 | */
13 | @Component
14 | public class InitStarter {
15 | @Value("${netty.timeOut}")
16 | private int timeOut;
17 | @Value("${disruptor.bufferSize}")
18 | private int bufferSize;
19 | @Value("${caffeine.minutes}")
20 | private int caffeineMinutes;
21 |
22 | @Bean("initParam")
23 | public Object init() {
24 | InitConstant.timeOut = timeOut;
25 | InitConstant.bufferSize = bufferSize;
26 | InitConstant.caffeineMaxMinutes = caffeineMinutes;
27 |
28 | return null;
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/l2cache-example/src/main/java/com/github/jesse/l2cache/example/config/RedissonConfig.java:
--------------------------------------------------------------------------------
1 | package com.github.jesse.l2cache.example.config;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.redisson.Redisson;
5 | import org.redisson.api.RedissonClient;
6 | import org.springframework.cloud.context.config.annotation.RefreshScope;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 |
10 | /**
11 | * Redisson 配置
12 | *
13 | * @author chenck
14 | * @date 2020/9/2 14:32
15 | */
16 | @RefreshScope
17 | @Slf4j
18 | @Configuration
19 | public class RedissonConfig {
20 |
21 |
22 | // @Bean
23 | // public RedissonClient redissonClient2() {
24 | // RedissonClient redissonClient = Redisson.create();
25 | // return redissonClient;
26 | // }
27 | // @Bean
28 | // public RedissonClient redissonClient() {
29 | // RedissonClient redissonClient = Redisson.create();
30 | // return redissonClient;
31 | // }
32 | }
33 |
--------------------------------------------------------------------------------
/l2cache-example/src/test/java/com/github/jesse/l2cache/example/ConcurrentReferenceHashMapTest.java:
--------------------------------------------------------------------------------
1 | package com.github.jesse.l2cache.example;
2 |
3 | import org.springframework.util.ConcurrentReferenceHashMap;
4 |
5 | import java.util.Map;
6 |
7 | /**
8 | * @author chenck
9 | * @date 2020/10/5 19:30
10 | */
11 | public class ConcurrentReferenceHashMapTest {
12 |
13 | /**
14 | * -Xmx5M -Xms5M -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps
15 | * 结论:频繁的GC
16 | */
17 | public static void main(String[] args) {
18 | Map valueLoaderCache = new ConcurrentReferenceHashMap<>();
19 | for (int i = 0; i < 10000000; i++) {
20 | if (i % 10000 == 0) {
21 | System.out.println(valueLoaderCache.size());
22 | }
23 | valueLoaderCache.put("key" + i, "valuevvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv" + i);
24 | }
25 | System.out.println(valueLoaderCache.size());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/l2cache-jd-hotkey/jd-hotkey-common/src/main/java/com/jd/platform/hotkey/common/tool/Constant.java:
--------------------------------------------------------------------------------
1 | package com.jd.platform.hotkey.common.tool;
2 |
3 | /**
4 | * @author wuweifeng wrote on 2019-12-05
5 | * @version 1.0
6 | */
7 | public class Constant {
8 | public static String PING = "ping";
9 | public static String PONG = "pong";
10 |
11 | /**
12 | * 该值在ProducerFactory有修改
13 | */
14 | public static int Default_Threads = 4;
15 |
16 | public static int MAGIC_NUMBER = 0x12fcf76;
17 | /**
18 | * netty的分隔符
19 | */
20 | public static String DELIMITER = "$(* *)$";
21 | /**
22 | * 数量统计时,rule+时间 组成key用的分隔符
23 | */
24 | public static String COUNT_DELIMITER = "#**#";
25 |
26 | public static String BAK_DELIMITER = "#\\*\\*#";
27 |
28 | /**
29 | * 当客户端要删除某个key时,就往etcd里赋值这个value,设置1秒过期,就算删除了
30 | */
31 | public static String DEFAULT_DELETE_VALUE = "#[DELETE]#";
32 |
33 | //单次包最大2M
34 | public static int MAX_LENGTH = 2 * 1024 * 1024;
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/l2cache-core/src/main/java/com/github/jesse/l2cache/util/BiConsumerWrapper.java:
--------------------------------------------------------------------------------
1 | package com.github.jesse.l2cache.util;
2 |
3 | import com.github.jesse.l2cache.util.pool.MdcUtil;
4 | import org.slf4j.MDC;
5 |
6 | import java.util.Map;
7 | import java.util.function.BiConsumer;
8 |
9 | /**
10 | * @author chenck
11 | * @date 2023/5/9 14:38
12 | */
13 | public class BiConsumerWrapper implements BiConsumer