Orika 使用不当导致的内存溢出问题

前言

最近突然收到了系统推送消息告警。打开一看,好家伙!直接 kafka 堆积超过了 100w 条数据,就差基础服务的人找上门来了。

kafka告警

经过简单的一系列排查,终于找到是代码中 Orika 工具使用不当导致内存增加、cpu 过高导致消费变慢。

下面记录下排查的思路

阅读更多

JDK1.8在Windows系统上MMap后文件IO关闭无效

前言

最近在开发个小东西,大量涉及了文件的操作。当然这种事情很简单嘛,最基本的打开个文件流进行写不就行了?

1
2
3
4
FileChannel fc = new RandomAccessFile(file, "rw").getChannel();
MappedByteBuffer mb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 4096);
// ......
fc.close()

我本来也是这样想的,可是当你执行这条语句file.delete()的时候居然返回的是false,删除失败?why?我不是明明已经将文件流关闭了嘛?接下来就是疯狂找原因了。

阅读更多

FileChannel和MMAP的使用以及benchmark

前言

最近弄了一些小东西,发现它们都有个共同点:对文件的操作。无论是文件的快速写入又或者是大文件的读取等,都要求我们对文件IO有很深的了解。不同文件大小的读写操作,应该选择哪种方式能达到最快的效果?接下来我们看看Java中常见的文件操作方式以及它们在读写大文件时各自的效果。

阅读更多

SkipList原理及实现

重点

randLevel算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Redis实现
* 初始层数为1,每次随机生成一个随机数,取低16位
* 当取的这个值小于0.25倍的0xFFFF时,level++,否则退出。
* 返回level和maxLevel的最小值
*
* 这里的ZSKIPLIST_P是晋升的概率。对应的期望层高是E=1/(1-p)。
*/
#define ZSKIPLIST_MAXLEVEL 64
#define ZSKIPLIST_P 0.25
private int randLevel() {
int level = 1;
while ((random() & 0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
level += 1;
return (level < ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}
阅读更多

【比赛复盘】云上开发,高效智能–阿里云ECS Cloudbuild开发者大赛性能挑战赛道

前言

快暑假的时候,在阿里天池上面闲逛。诶,性能优化挑战赛?点进去看看,初略的读了一下赛题,要实现一个聊天室服务,部署在ECS服务器上面,然后对它进行一下手段的性能优化,感觉还挺合适的(ps: 当时因为写了一个秒杀系统并压测优化过、也看过一些性能调优的书,感觉自己很nb,后面才知道自己还是太嫩了🤣),顿时就报名了。

因为第一次参加这种比赛,所以给自己定的是前50就ok了。然后一个月的初赛,快结束的那一周排名十多名,感觉自己还是很厉害的,但是就一周的时间,看着自己排名直接跌出前 20,到了 23。才意识到自己高兴太早了。

接下来是一个月的复赛时间,这回是要实现一个集群了。中途遇到了老多问题,找了好多官网文档(VertxHazelcastIgniteLevelDB),也学到了不少,但还是感觉差点火候😅。每天早上七点多起床一直调试到晚上十点左右,官方人员都被烦的不要不要的了😂(希望不要厌烦)。还是太菜了哈哈哈。

不多说了,先上排名。

阅读更多

通过Java实现Raft算法

前言

7月份的时候参加了一个阿里天池的性能优化比赛,后面在复赛的时候因为是集群场景,需要考虑各个节点之间数据的一致性,本来想自己实现的,但奈何时间太短(ps: 太菜了😭),最终还是找了市面上成熟的中间件来实现(Ignite)。这不,还是手痒,自己实现一个基于Raft的一致性服务。

Github:zraft

个人博客:zhaommmmomo

阅读更多

ArrayList底层逻辑与实现

重点

扩容规则:底层是System.arraycopy()这个方法

  1. 每次扩容都是将新容量设置为1.5 * 旧容量
  2. 新容量如果小于需要的容量,将新容量设置为需要的容量
  3. 新容量如果大于可以分配的最大容量(整型最大值 - 8),新容量设置为(需要的容量小于最大分配容量)需要的容量或者设置为(需要的容量大于最大分配容量)整型最大值

懒加载机制:ArrayList初始化的时候并没有直接给数组分配容量,而是使用的一个空数组进行赋值,只有当第一次增加的时候才会真正的给数组进行容量分配。这样是为了防止用户初始化后没有进行使用导致内存的浪费。(只有用户调用无参构造方法的时候才是懒加载,其他两个构造函数是分配的另外一个空数组)

阅读更多

Java中的Thread

前言

想必各位都对线程这个词不陌生,我们都知道Java中可以通过Thread、Rannable、Callable和线程池来创建一个线程。但是一个线程的创建、运行到结束到底是一个什么样的过程呢?我们以一段代码为入口点来看看Java到底是如何弄的线程。

1
2
3
4
5
public static void main(String[] args) {
new Thread(() -> {
System.out.println("run...");
}).start();
}
阅读更多

Linux中TCP三次握手的实现

前言

网上三次握手八股文一大堆,我“为了面试”也去看了看,刚好那时候接触Linux比较多,突然想到TCP三次握手在Linux内核中是如何去实现的呢?是不是会有不同?然后我就开始了漫长的百度(ps: 我比较菜,还不能拿着Linux上千个源码文件去怼)、源码之路。终于弄清了Linux中TCP三次握手的大致过程。

阅读更多