采坑日志
这篇文章关于本人的采坑记录,常见的就不加了,相信也能百度的到。
Rsa加密解密
在获取rsa加密后拿到的秘钥(分为公钥和私钥)作为解密秘钥。在window中运行解密没有问题,但是在Linux服务器上解密就变成了带有乱码的数据,导致数据不对引发错误。
加密解密都是用RSA,秘钥也是对的。问题就出在这里
Cipher cipher = Cipher.getInstance("RSA");
这是不完全的RSA方式,应该将完整RSA的填充方式加上
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
解决!
线程池卡死问题
在一个用定时任务驱动的方法体中,有三四个网络请求与多个数据库更新方法。测试时发现服务器上跑完整个流程是十秒左右,但是数据量稍大的情况下又很紧急,就显得慢。于是我使用了线程池技术来驱动,刚开始的时候还好,后面发现有卡死的情况。
代码如下:
private static volatile ThreadPoolExecutor singleExecutor = null;
private static Object ojb = new Object();
public static synchronized ThreadPoolExecutor getInstanceThreadPool() {
if (null == singleExecutor) {
singleExecutor = new ThreadPoolExecutor(3, 10, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(400));
singleExecutor.allowCoreThreadTimeOut(true);
}
return singleExecutor;
}
public List<String> getXXX(List<String> ids) {
Thread thread = null;
ThreadPoolExecutor executor = getInstanceThreadPool();
List<Pair<Date, Thread>> activeThreads = new ArrayList<>();
try{
for(String id:ids) {
thread = new Thread(() -> {
synchronized (ojb) {
activeThreads.add(Pair.of(DateUtils.getDate(new Date(), "25s", 1), Thread.currentThread()));
}
// 逻辑xxxx
}
executor.execute(thread);
}
int blockTime = 0;
while (true) {
Threads.sleep(3000);
BlockingQueue<Runnable> queue = executor.getQueue();
int queueSize = CollectionUtils.size(queue);
logger.info("当前排队线程数 " + queueSize);
logger.info("当前活动线程数 " + executor.getActiveCount());
if (activeThreads.size() > 0) {
logger.info("thread size is " + activeThreads.size());
for (int i = activeThreads.size() - 1; i >= 0; i--) {
Pair<Date, Thread> pair = activeThreads.get(i);
if (null != pair && new Date().getTime() - pair.getKey().getTime() > 1000) {
if (pair.getValue().isAlive()) {
pair.getValue().stop();
}
activeThreads.remove(i);
logger.info("stop the thread");
}
}
}
if (queueSize == 0 && activeThreads.size() == 0) {
break;
}
if (queueSize > 0 && executor.getActiveCount() == 0 && activeThreads.size() == 0) {
blockTime ++;
} else {
blockTime = 0;
}
logger.info("block time is: " + blockTime);
if (blockTime > 100) {
for (Runnable runnable : queue) {
executor.remove(runnable);
}
logger.info("thread over time");
break;
}
}
} catch (Exception e) {
logger.error("fk schedule error:", e);
}
}
看到这里,发现有死循环检测。本以为是这里发生问题,但是有卡死退出检查:
即:if (blockTime > 100)
也有等待队列移除:
for (Runnable runnable : queue) {
executor.remove(runnable);
}
所以不在检测中。
我也想到资源竞争问题,但是由于时间问题,排查起来比较麻烦。
后来我发现这线程池是个单例方法~~ 好家伙,如果卡死的话不会像对象一样可以初始化。当机立断,直接改成了即用即建。
将如下:
// 将单例移除,把ThreadPoolExecutor executor = getInstanceThreadPool(); 改成如下
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 10, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(200));
// 后增加如下代码
finally {
executor.shutdownNow();
}
MySQL 索引失效问题
在一次表数据关联分页查询的时候,发现查询耗时比较长。本以为是数据量的问题,然后看了下才两万多条数据,根据MySQL性能不可能慢,主要是执行sql没有任何异常。我是建了多个普通索引,后面排查是否sql有not in等关键字使索引失效,没有发现。用EXPLAIN 来解析sql 发现主表type 是All,性能巨差。查了很多次,问了AI,根据列出的可能发生问题列表进行排查。后来发现 表字段的字符集也会导致索引失效问题。
如下排查两张表的关联字段:
发现有一个为utf8bm4_bin 另一个为utf8bm4_general_ci,立即都改为utf8bm4_general_ci,然后发现快了数倍
持续更新中。。。。