Reactor网络模型

主-从Reactor网络模型 Main reactor thread 负责绑定监听端口 绑定端口后通过单线程acceptor建立tcp连接 建立tcp连接后通过epoll注策读事件 sub-reactor dispatch 一个四核 CPU服务器,我们可以设置 sub-reactor 为 4 负责监听tcp连接读写事件 当acceptor建立连接后,交由sub-reactor中的一个处理 收到tcp读事件后,交给工作线程处理任务 与单reactor线程相比(即读写事件监听线程和acceptor线程为同一线程),单reactor 线程既分发连接建立,又分发已建立连接的 I/O,有点忙不过来,在实战中的表现可能就是客户端连接成功率偏低。 threadpool 任务任务线程池 由于处理任务比较耗时,故将任务处理线程与tcp

  • 凯文
1 min read

JVM之JIT

JIT概述 即时编译是一项用来提升应用程序运行效率的技术。通常而言,代码会先被 Java 虚拟机解释执行,之后反复执行的热点代码则会被即时编译成为机器码,直接运行在底层硬件之上。 从 Java 8 开始,Java 虚拟机默认采用分层编译的方式。它将执行分为五个层次,分为为 0 层解释执行,1 层执行没有 profiling 的 C1 代码,2 层执行部分 profiling 的 C1 代码,3 层执行全部 profiling

  • 凯文
7 min read

jvm之线程池

java线程池实现继承关系 Executor==>ExecutorService-->AbstractExecutorService==>ThreadPoolExecutor Executor-接口 execute,执行某个Runnable实现类 ExecutorService-接口,较Executor提供了更多的功能 submit,执行Callable实现类,返回值通过Future返回 AbstractExecutorService-线程池抽象类 实现了submit方法 在执行submit方法前会将Callable转为FutureTask类,然后调用execute方法执行 FutureTask是Runnable的实现类 线程池基本都继承该抽象类 线程池实现类 ThreadPoolExecutor 实现了execute方法,在该方法中判断核心线程数 如果小于核心线程数,则通过addWorker新增核心线程执行该command 如果小于核心线程数,则将command添加至任务队列中 如果添加队列失败,则继续通过addWorker新增非核心线程 如果新增线程失败,

  • 凯文
3 min read

java线程池之ForkJoinPool

作用 计算机中一个任务一般是由一个线程来处理的,如果此时出现了一个非常耗时的大任务,比如对一个大的ArrayList每个元素进行+1操作,如果是普通的ThreadPoolExecutor就会出现线程池中只有一个线程正在处理这个大任务而其他线程却空闲着,这会导致CPU负载不均衡,空闲的处理器无法帮助工作。ForkJoinPool就是用来解决这种问题的,将一个大任务拆分成多个小任务后,使用fork可以将小任务分发给其他线程同时处理,使用join可以将多个线程处理的结果进行汇总;这实际上就是分治思想的并行版本 Java8中的parallelStream API就是基于ForkJoinPool实现的 ForkJoinPool的线程使用的是 Thread子类ForkJoinWorkerThread 实例 我们在提交任务时,一般不会直接继承ForkJoinTask,只要继承它的子类即可,框架提供了两种子类: RecursiveAction:用于没有返回结果的任务(类似Runnable) RecursiveTask:用于有返回结果的任务(类似Callable) public class ForJoinPollExecutor { public static

  • 凯文
2 min read

sleep、wait及park介绍

Thread.sleep(time) 该方法必须传入指定的时间,线程将进入休眠状态,通过jstack输出线程快照的话此时该线程的状态应该是TIMED_WAITING,表示休眠一段时间。 该方法会抛出InterruptedException异常,这是受检查异常,调用者必须处理。 通过sleep方法进入休眠的线程不会释放持有的锁,因此,在持有锁的时候调用该方法需要谨慎。 Object.wait() 方法 java的每个对象都隐式的继承了Object类。因此每个类都有自己的wait()方法。我们通过object.wait()方法也可以让线程进入休眠。wait()有3个重载方法: public final void wait() throws InterruptedException; public final

  • 凯文
8 min read
java

生产问题之CaffeineCache使用中的坑

问题描述 服务缓存中使用CaffeineCache时,通过CaffeineCache在数据更新并且超过refreshAfterWrite时间后首次获取缓存时,偶发性的获取不到最新的缓存 实现 public class CaffeineCacheTest { public static void main(String[] args) throws Exception { CaffeineCacheTest test = new CaffeineCacheTest(); Cache cache = test.caffeineCacheManager().getCache("test"); CacheObject cacheObject = (CacheObject) cache.get(

  • 凯文
3 min read
linux

linux上下文切换

上下文切换 CPU 上下文切换,就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。 上下文切换的类型 中断上下文切换 线程上下文切换 用户态内核态上下文切换 进程上下文切换 用户态内核态上下文切换 进程既可以在用户空间运行,又可以在内核空间中运行。进程在用户空间运行时,被称为进程的用户态,而陷入内核空间的时候,被称为进程的内核态。 从用户态到内核态的转变,需要通过系统调用来完成。比如,当我们查看文件内容时,就需要多次系统调用来完成:首先调用 open() 打开文件,

  • 凯文
5 min read
redis

分布式锁之redisson

使用redisson的原因 比zk性能要好 比使用redis.setnx的优势 使用redis.setnx时,如果系统挂掉,会一直锁住 redisson将ttl和set 通过lua脚本原子性批量执行 实现 Lock lock = redisson.getLock("test"); lock.lock(); 源码 RLock锁API public interface RLock { //----------------------Lock接口方法----------------------- /** * 加锁 锁的有效期默认30秒 */ void lock(); /** * tryLock()方法是有返回值的,它表示用来尝试获取锁,

  • 凯文
3 min read

响应式编程RxJava之Subject

概述 RxJava中常见的Subject有4种,分别是 AsyncSubject、 BehaviorSubject、 PublishSubject、 ReplaySubject。 一定要用Subcect.create()的方式创建并使用,不要用just(T)、from(T)、create(T)创建,否则会导致失效 AsyncSubject 简单的说使用AsyncSubject无论输入多少参数,永远只输出最后一个参数。 // 无论订阅的时候AsyncSubject是否Completed,均可以收到最后一个值的回调 AsyncSubject as = AsyncSubject.create(); as.onNext(1); as.onNext(2)

  • 凯文
3 min read
java

响应式编程RxJava之Single

简单入门 Single.just(T value); 通常使用RxJava,主要是为了异步处理一些任务。即传入一些值,经过逻辑处理之后返回结果。 以上代码中的just(T value),可以看作是传入参数。 有了输入,如何输出呢?我们讲到了异步处理,那自然得有一个异步回调才行吧,这简直理所应当吧。所以这里介绍最重要的"subscribe"概念。 Single.just(T value).subscribe(); 例如: int addValue(int a,

  • 凯文
8 min read
java

reactor响应式编程之 Mono & flux

Publisher 由于响应流的特点,我们不能再返回一个简单的POJO对象来表示结果了。必须返回一个类似Java中的Future的概念,在有结果可用时通知消费者进行消费响应。 Reactive Stream规范中这种被定义为Publisher<T> ,Publisher<T>是一个可以提供0-N个序列元素的提供者,并根据其订阅者Subscriber<? super T>的需求推送元素。一个Publisher<T>可以支持多个订阅者,并可以根据订阅者的逻辑进行推送序列元素。下面这个Excel计算就能说明一些Publisher<T>的特点。 Publisher&

  • 凯文
5 min read
java

响应式编程之RxJava VS Reactor

目前市场上比较流行的有几种,RxJava,Akka,Vert.x,Reactor。最常使用的两种框架,并且实现了响应式编程规范的是RxJava和Reactor。 两者之间有什么区别呢? API Flowable和FluxAPI很相似都支持,ReactiveX常见的那些操作符。map,filter,flatmap等等,具体操作符列表:http://reactivex.io/documentation/operators.html 在Java版本上: RxJava2.x必须至此Java 6,因为它Rxjava在安卓中用的很多 Reactor则至少要求Java 8. 其内部利用了很多新版Java的特性。并且还可以方便的转换为:CompletableFuture,java.

  • 凯文
4 min read
java

jvm类的加载及方法调用过程

类的加载过程 加载 加载是指查找字节流,并且据此创建类的过程。 加载需要借助类加载器,在 Java 虚拟机中,类加载器使用了双亲委派模型,即接收到加载请求时,会先将请求转发给父类加载器。 链接 验证:确保被加载类能够满足 Java 虚拟机的约束条件 准备:为被加载类的静态字段分配内存;部分 Java 虚拟机还会在此阶段构造其他跟类层次相关的数据结构,比如说用来实现虚方法的动态绑定的方法表 解析:将符号引用解析成为实际引用;如果符号引用指向一个未被加载的类,或者未被加载类的字段或方法,那么解析将触发这个类的加载(但未必触发这个类的链接以及初始化。) 初始化 常量值(ConstantValue)初始化直接由 Java

  • 凯文
7 min read

java基本数据类型

java基本数据类型介绍 在java中 false实际值为0 true为1 Java 的基本类型都有对应的值域和默认值。可以看到,byte、short、int、long、float 以及 double 的值域依次扩大,而且前面的值域被后面的值域所包含。因此,从前面的基本类型转换至后面的基本类型,无需强制转换。另外一点值得注意的是,尽管他们的默认值看起来不一样,但在内存中都是 0。 在 Java 中,正无穷和负无穷是有确切的值,在内存中分别等同于十六进制整数 0x7F800000 和 0xFF800000。0x7F800001 对应的浮点数是

  • 凯文
4 min read
java

Java 虚拟机执行Java 字节码过程

Java 虚拟机具体是怎样运行 Java 字节码的 java类加载 从虚拟机视角来看,执行 Java 代码首先需要将它编译而成的 class 文件加载到 Java 虚拟机中。加载后的 Java 类会被存放于方法区(Method Area)中。实际运行时,虚拟机会执行方法区内的代码。 如果你熟悉 X86 的话,你会发现这和段式内存管理中的代码段类似。而且,Java 虚拟机同样也在内存中划分出堆和栈来存储运行时数据。 不同的是,Java 虚拟机会将栈细分为面向 Java 方法的

  • 凯文
5 min read

业务日志收集

问题 当服务qps过高时,如果收集业务日志时直接写入kafka可能会导致接口延时上升,另外直接写入的日志不一定可直接使用,需要经过fink过滤处理,固采用以下方式收集海量的业务日志 服务将日志通过 log的方式写入碰盘文件,可异步写,降低io次数 有专门的agent采集文件日志,并写入kafka 将kafka的数据传输至flink中进行过滤处理,然后再导入另一个kafka topic 读取新的kafka topic数据,写入hive或 es

  • 凯文
1 min read

记录一次上线前压测过程

首次压测 95及99分位极度不稳 去掉CheckUtil 查看服务日志,发现某个trace CheckUtil耗时长,去掉该功能后压测 根据查看gc情况无关,而和jvm垃圾回收有关 查看gc情况 定位gc有问题,调整jvm参数 调整jvm参数 xmn8g 99分位稳定 问题:为什么年轻代自适应 未生效 AdaptiveSizePolicy调整的是 Eden、From 和 To 区的大小 并不会调整 年轻代的大小 年轻代过大,会不会导致回收时间过长 垃圾回收主要耗时点在于copy的过程,而扫描的过程是很快的,针对该场景,由于是qps高导致大量对象在年轻代回收,所以需要copy的对象是很少的,

  • 凯文
2 min read
linux

linux之lsof

lsof命令是什么? 可以列出被进程所打开的文件的信息。被打开的文件可以是 普通的文件 目录 网络文件系统的文件 字符设备文件 (函数)共享库 管道,命名管道 符号链接 底层的socket字流,网络socket,unix域名socket 在linux里面,大部分的东西都是被当做文件的…..还有其他很多 lsof使用 列出所有打开的文件: lsof 备注: 如果不加任何参数,就会打开所有被打开的文件,建议加上一下参数来具体定位 查看谁正在使用某个文件 lsof /filepath/file 递归查看某个目录的文件信息 lsof +D /filepath/

  • 凯文
2 min read
java

java-mysql时区问题

问题 数据库时间展示正常,但是web页面时间与数据库时间差 13/14 个小时 原因 mysql采用的是CST时区,而java使用的是北京时间,两个时区有时差13个小时有时差14个小时,故从数据库查出数据后,如果直接展示无问题,但是如果通过java程序 SimpleDateFormat转换,就会出现问题 解决方案 在通过SimpleDateFormat转换时间时,设置时区为 CST 此方案,后续所有使用SimpleDateFormat转换数据库时间时,都需要指定TimeZone 但是通过SimpleDateFormat转换非数据库date(如 当前date)时,不需要指定TimeZone format.setTimeZone(TimeZone.getTimeZone("CST&

  • 凯文
1 min read