1. 缓存优化

This commit is contained in:
qaiu
2024-09-18 13:24:33 +08:00
parent 4516aa8300
commit 0bbf022c5d
24 changed files with 370 additions and 263 deletions

View File

@@ -1,8 +1,8 @@
package cn.qaiu.lz.web.http;
import cn.qaiu.lz.common.util.URLParamUtil;
import cn.qaiu.lz.web.model.CacheLinkInfo;
import cn.qaiu.lz.web.service.CacheService;
import cn.qaiu.parser.PanDomainTemplate;
import cn.qaiu.vx.core.annotaions.RouteHandler;
import cn.qaiu.vx.core.annotaions.RouteMapping;
import cn.qaiu.vx.core.enums.RouteMethod;
@@ -31,8 +31,7 @@ public class ServerApi {
Promise<Void> promise = Promise.promise();
String url = URLParamUtil.parserParams(request);
PanDomainTemplate panDomainTemplate = PanDomainTemplate.fromShareUrl(url).setShareLinkInfoPwd(pwd);
cacheService.getAndSaveCachedShareLink(panDomainTemplate)
cacheService.getCachedByShareUrlAndPwd(url, pwd)
.onSuccess(res -> ResponseUtil.redirect(
response.putHeader("nfd-cache-hit", res.getCacheHit().toString())
.putHeader("nfd-cache-expires", res.getExpires()),
@@ -42,39 +41,32 @@ public class ServerApi {
}
@RouteMapping(value = "/json/parser", method = RouteMethod.GET, order = 3)
public Future<String> parseJson(HttpServerRequest request, String pwd) {
public Future<CacheLinkInfo> parseJson(HttpServerRequest request, String pwd) {
String url = URLParamUtil.parserParams(request);
return PanDomainTemplate.fromShareUrl(url).setShareLinkInfoPwd(pwd).createTool().parse();
return cacheService.getCachedByShareUrlAndPwd(url, pwd);
}
@RouteMapping(value = "/json/:type/:key", method = RouteMethod.GET, order = 2)
public Future<String> parseKeyJson(String type, String key) {
String code = "";
public Future<CacheLinkInfo> parseKeyJson(String type, String key) {
String pwd = "";
if (key.contains("@")) {
String[] keys = key.split("@");
key = keys[0];
code = keys[1];
pwd = keys[1];
}
return PanDomainTemplate.fromShortName(type)
.generateShareLink(key).setShareLinkInfoPwd(code).createTool().parse();
return cacheService.getCachedByShareKeyAndPwd(type, key, pwd);
}
@RouteMapping(value = "/:type/:key", method = RouteMethod.GET, order = 1)
public Future<Void> parseKey(HttpServerResponse response, String type, String key) {
Promise<Void> promise = Promise.promise();
String code = "";
String pwd = "";
if (key.contains("@")) {
String[] keys = key.split("@");
key = keys[0];
code = keys[1];
pwd = keys[1];
}
PanDomainTemplate panDomainTemplate = PanDomainTemplate
.fromShortName(type)
.generateShareLink(key)
.setShareLinkInfoPwd(code);
cacheService.getAndSaveCachedShareLink(panDomainTemplate)
cacheService.getCachedByShareKeyAndPwd(type, key, pwd)
.onSuccess(res -> ResponseUtil.redirect(
response.putHeader("nfd-cache-hit", res.getCacheHit().toString())
.putHeader("nfd-cache-expires", res.getExpires()),

View File

@@ -0,0 +1,68 @@
package cn.qaiu.lz.web.model;
import cn.qaiu.db.ddl.Length;
import cn.qaiu.db.ddl.Table;
import cn.qaiu.lz.common.ToJson;
import io.vertx.codegen.annotations.DataObject;
import io.vertx.core.json.JsonObject;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author <a href="https://qaiu.top">QAIU</a>
* @date 2024/9/11 16:06
*/
@Table(value = "api_statistics_info", keyFields = "share_key")
@Data
@DataObject
@NoArgsConstructor
public class ApiStatisticsInfo implements ToJson {
/**
* pan type 单独拿出来便于统计.
*/
@Length(varcharSize = 4)
private String panType;
/**
* 分享key type:key
*/
@Length(varcharSize = 4096)
private String shareKey;
/**
* 命中缓存次数
*/
private Integer cacheHitTotal;
/**
* api解析次数
*/
private Integer apiParserTotal;
/**
* 更新时间戳
*/
private Long updateTs;
// 使用 JsonObject 构造
public ApiStatisticsInfo(JsonObject json) {
if (json.containsKey("panType")) {
this.setPanType(json.getString("panType"));
}
if (json.containsKey("shareKey")) {
this.setShareKey(json.getString("shareKey"));
}
if (json.containsKey("cacheHitTotal")) {
this.setCacheHitTotal(json.getInteger("cacheHitTotal"));
}
if (json.containsKey("apiParserTotal")) {
this.setApiParserTotal(json.getInteger("apiParserTotal"));
}
if (json.containsKey("updateTs")) {
this.setUpdateTs(json.getLong("updateTs"));
}
}
}

View File

@@ -20,7 +20,7 @@ import lombok.NoArgsConstructor;
public class CacheLinkInfo implements ToJson {
/**
* 缓存key: type@ShareKey; e.g. lz@xxxx
* 缓存key: type:ShareKey; e.g. lz:xxxx
*/
@Length(varcharSize = 4096)
private String shareKey;
@@ -51,6 +51,20 @@ public class CacheLinkInfo implements ToJson {
// 使用 JsonObject 构造
public CacheLinkInfo(JsonObject json) {
CacheLinkInfoConverter.fromJson(json, this);
if (json.containsKey("shareKey")) {
this.setShareKey(json.getString("shareKey"));
}
if (json.containsKey("directLink")) {
this.setDirectLink(json.getString("directLink"));
}
if (json.containsKey("expires")) {
this.setExpires(json.getString("expires"));
}
if (json.containsKey("expiration")) {
this.setExpiration(json.getLong("expiration"));
}
this.setCacheHit(json.getBoolean("cacheHit", false));
}
}

View File

@@ -1,23 +0,0 @@
package cn.qaiu.lz.web.model;
import io.vertx.core.json.JsonObject;
// CacheLinkInfoConverter.java
public class CacheLinkInfoConverter {
public static void fromJson(JsonObject json, CacheLinkInfo obj) {
if (json.containsKey("shareKey")) {
obj.setShareKey(json.getString("shareKey"));
}
if (json.containsKey("directLink")) {
obj.setDirectLink(json.getString("directLink"));
}
if (json.containsKey("expires")) {
obj.setExpires(json.getString("expires"));
}
if (json.containsKey("expiration")) {
obj.setExpiration(json.getLong("expiration"));
}
obj.setCacheHit(json.getBoolean("cacheHit", false));
}
}

View File

@@ -10,14 +10,14 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@DataObject
public class StatisticsInfo implements ToJson {
Integer fail;
Integer success;
Integer parserTotal;
Integer cacheTotal;
Integer total;
public StatisticsInfo(JsonObject jsonObject) {
this.fail = jsonObject.getInteger("fail");
this.success = jsonObject.getInteger("success");
this.parserTotal = jsonObject.getInteger("parserTotal");
this.cacheTotal = jsonObject.getInteger("cacheTotal");
this.total = jsonObject.getInteger("total");
}
}

View File

@@ -1,7 +1,6 @@
package cn.qaiu.lz.web.service;
import cn.qaiu.lz.web.model.CacheLinkInfo;
import cn.qaiu.parser.PanDomainTemplate;
import cn.qaiu.vx.core.base.BaseAsyncService;
import io.vertx.codegen.annotations.ProxyGen;
import io.vertx.core.Future;
@@ -13,5 +12,7 @@ import io.vertx.core.Future;
@ProxyGen
public interface CacheService extends BaseAsyncService {
Future<CacheLinkInfo> getAndSaveCachedShareLink(PanDomainTemplate shareLinkInfo);
Future<CacheLinkInfo> getCachedByShareKeyAndPwd(String type, String shareKey, String pwd);
Future<CacheLinkInfo> getCachedByShareUrlAndPwd(String shareUrl, String pwd);
}

View File

@@ -5,7 +5,7 @@ import cn.qaiu.lz.common.cache.CacheConfigLoader;
import cn.qaiu.lz.common.cache.CacheManager;
import cn.qaiu.lz.web.model.CacheLinkInfo;
import cn.qaiu.lz.web.service.CacheService;
import cn.qaiu.parser.PanDomainTemplate;
import cn.qaiu.parser.ParserCreate;
import cn.qaiu.vx.core.annotaions.Service;
import io.vertx.core.Future;
import io.vertx.core.Promise;
@@ -19,21 +19,22 @@ public class CacheServiceImpl implements CacheService {
private final CacheManager cacheManager = new CacheManager();
@Override
public Future<CacheLinkInfo> getAndSaveCachedShareLink(PanDomainTemplate template) {
private Future<CacheLinkInfo> getAndSaveCachedShareLink(ParserCreate parserCreate) {
Promise<CacheLinkInfo> promise = Promise.promise();
// 构建组合的缓存key
ShareLinkInfo shareLinkInfo = template.getShareLinkInfo();
ShareLinkInfo shareLinkInfo = parserCreate.getShareLinkInfo();
String cacheKey = generateCacheKey(shareLinkInfo.getType(), shareLinkInfo.getShareKey());
// 尝试从缓存中获取
cacheManager.get(cacheKey).onSuccess(result -> {
// 判断是否已过期
// 未命中或者过期
if (!result.getCacheHit() || result.getExpiration() < System.currentTimeMillis()) {
template.createTool().parse().onSuccess(redirectUrl -> {
// parse
result.setCacheHit(false);
result.setExpiration(0L);
parserCreate.createTool().parse().onSuccess(redirectUrl -> {
long expires = System.currentTimeMillis() +
CacheConfigLoader.getDuration(shareLinkInfo.getType()) * 60 * 1000;
CacheConfigLoader.getDuration(shareLinkInfo.getType()) * 60 * 1000L;
result.setDirectLink(redirectUrl);
// result.setExpires(generateDate(expires));
promise.complete(result);
@@ -45,10 +46,12 @@ public class CacheServiceImpl implements CacheService {
"shareKey", cacheKey
));
cacheManager.cacheShareLink(cacheLinkInfo).onFailure(Throwable::printStackTrace);
cacheManager.updateTotalByParser(cacheKey).onFailure(Throwable::printStackTrace);
}).onFailure(promise::fail);
} else {
result.setExpires(generateDate(result.getExpiration()));
promise.complete(result);
cacheManager.updateTotalByCached(cacheKey).onFailure(Throwable::printStackTrace);
}
}).onFailure(t -> promise.fail(t.fillInStackTrace()));
return promise.future();
@@ -62,4 +65,16 @@ public class CacheServiceImpl implements CacheService {
private String generateDate(Long ts) {
return DateFormatUtils.format(new Date(ts), "yyyy-MM-dd hh:mm:ss");
}
@Override
public Future<CacheLinkInfo> getCachedByShareKeyAndPwd(String type, String shareKey, String pwd) {
ParserCreate parserCreate = ParserCreate.fromType(type).shareKey(shareKey).setShareLinkInfoPwd(pwd);
return getAndSaveCachedShareLink(parserCreate);
}
@Override
public Future<CacheLinkInfo> getCachedByShareUrlAndPwd(String shareUrl, String pwd) {
ParserCreate parserCreate = ParserCreate.fromShareUrl(shareUrl).setShareLinkInfoPwd(pwd);
return getAndSaveCachedShareLink(parserCreate);
}
}

View File

@@ -48,10 +48,9 @@ public class DbServiceImpl implements DbService {
JDBCPool client = JDBCPoolInit.instance().getPool();
Promise<StatisticsInfo> promise = Promise.promise();
String sql = """
select COUNT(CASE "code" WHEN 500 THEN "code" END ) "fail",
COUNT(CASE "code" WHEN 200 THEN "code" END ) "success",
count(1) "total"
from "t_parser_log_info"
select sum(api_parser_total) parserTotal,sum("cache_hit_total") cacheTotal,
sum(api_parser_total) + sum("cache_hit_total") total
from "api_statistics_info";
""";
SqlTemplate.forQuery(client, sql).mapTo(StatisticsInfo.class).execute(new HashMap<>()).onSuccess(row -> {
StatisticsInfo info;