香港阿里云ip路由

深圳阿里云到香港阿里云 要经过美国线路… 香港阿里云到深圳阿里云 看起来像走的内网到浙江阿里云 深圳阿里云到香港阿里云 [root@xxxxx ~]# traceroute 47.52.xx.xx traceroute to 47.52.xx.xx (47.52.xx.xx), 30 hops max, 60 byte packets 1 * * * 2 11.219.126.105 (11.219.126.105) 6.572 ms 11.219.127.109 (11.219.127.109) 6.830 ms 11.219.126.105 (11.219.126.105) 6.833 ms (美国) 3 11.219.127.154 (11.219.127.154) 5.981 ms 11.219.127.146 (11.219.127.146) 5.663 ms 11.219.126.154 (11.219.126.154) 5.612 ms 4 11.177.232.122 (11.177.232.122) 1.963 ms… Continue reading 香港阿里云ip路由

项目的jvm内存分析

项目的jvm内存分析 我们的项目是一个 java 写的高重删多副本二级存储,放在2U4节点服务器上跑,使用万兆交换机相连,写的速度能达到300M/s,但是读的速度只能达到30~40MB/s.分析,读速度之所以这么慢.主要是因为:为了实现重删,我们采用了数据变长分块,生成hash,最后利用全局hash库过滤重复数据,最后数据保存到当前正在使用的map文件.当多个文件同时写入的时候这个过程,把连续的数据变得离散. 使得读取数据的时候,硬盘每一次都是随机读.读性能相当差.为了提高读性能,我们对数据模型做了修改,对入口做了分组,把分组连续的数据做成定长1M块存储. 重构后,读性能确实上升了一倍,但是程序的稳定性不行.连续写入数据几个小时后,程序性能就开始慢慢往下降,最后直接内存溢出. 直接内存 使用htop看程序内存占用,发现占用的内存确实比实际配置的高很多.造成这种原因,因为我们使用了java nio 提供的直接内存接口,这部分内存都不是从堆中分配的: 显式分配 ByteBuffer.allocateDirect(int size) 程序里一些循环里面的临时ByteBuffer是使用直接内存生成的.这一部分,都改过来: ByteBuffer.allocate 使用了nio内存映射: FileChannel.map(MapMode mode,long position, long size) 我们的hash索引是保存在文件里,当布隆过滤器没有命中,使用内存映射来真实读取.因为设计上的原因,基本上不会释放. jvm参数配置有问题 -XX:+DisableExplicitGC 我们使用了DisableExplicitGC,因为大量Direct ByteBuffer 所以最后导致OOM.看了很多文章都建议不要开启. DirectMemory 默认的大小是等同于JVM最大堆.所以最终看起来程序内存比我们配置的-Xmx 高很多. 堆内内存 开启** G1 gc log**后,查看日志发现有大量的mix gc,感觉这部分影响了系统性能. -XX:+UseG1GC -XX:+PrintGCDetails-verbose:gc -Xloggc:gc.log 使用jmx内存监控 jstatd -J-Djava.security.policy=jstatd.all.policy 监测程序内存情况,发现写入数据的时候old eden会不断往上涨,然后引发mix gc,不断重复这个过程.而Survivor eden不怎么变.就觉得非常奇怪.为什么直接就在old eden分配呢? 对比老版本,看看有没有相同的情况,老版本在相同的jvm 参数下,跑的时候内存比较稳定.都是在servivor eden 上分配的.这下更苦逼,基本可以说明是:我们改出来的. 使用jmap 把整个程序的堆内存dump下来,看了看占了堆内存90%的是long[]和byte[]再仔细细分,前者主要是用在了布隆过滤器上,后者也多是数据传递时候的一些数组.看不出什么问题. 偶然,把老版本的堆内存参数-Xmx配置低一些,发现老版本也出现相识的问题.这下好了,原来问题一直有,只是我们现在分配的数据多了,大了,更容易暴露出来. 重新观察新程序gc,发现刚开始的时候,其实新版本也是在servivor… Continue reading 项目的jvm内存分析

Linux文件系统基础

前面 本文在摘录了一些基本概念 文件描述符 文件描述符是一些小值整数,用于文件系统在处理文件的时候,标识被处理文件. 因此文件描述符的总数也就是系统可以打开的文件的最大数量 当Linux系统开始运行的时候,有三个文件描述符已经被使用: 标准输入:0 标准输出:1 标准错误:2 其他文件的文件描述符,在调用open函数时返回.文件描述符有操作系统分配,每次分配最小的. 库函数 系统调用实际上就是指最底层的一个调用,在linux程序设计里面就是底层调用的意思。面向的是硬件。而库函数调用则面向的是应用开发的,相当于应用程序的api,采用这样的方式有很多种原因: 双缓冲技术的实现。 可移植性。(系统调用是操作系统相关的,因此一般没有跨操作系统的可移植性。) 底层调用本身的一些性能方面的缺陷。 让api也可以有了级别和专门的工作面向。 函数库调用 系统调用 在所有的ANSI C编译器版本中,C库函数是相同的 各个操作系统的系统调用是不同的 它调用函数库中的一段程序(或函数) 它调用系统内核的服务 与用户程序相联系 是操作系统的一个入口点 在用户地址空间执行 在内核地址空间执行 它的运行时间属于“用户时间” 它的运行时间属于“系统”时间 属于过程调用,调用开销较小 需要在用户空间和内核上下文环境间切换,开销较大 在C函数库libc中有大约300个函数 在UNIX中大约有90个系统调用 典型的C函数库调用:system fprintf malloc 典型的系统调用:chdir fork write brk; /proc文件系统 Linux将一切看做文件,硬件设备在文件系统中也有相应的文件 /proc文件系统,可以看做是一个特殊的文件系统,每一个独立的硬件在这个系统中,都对应着一个文件,用户可以通过proc文件系统像访问文件一样来访问硬件设备。 也可以通过ps -ef |grep xxx获取程序pid,然后在/proc/pid/文件夹下查看该程序的运行情况. 参考 linux文件写过程 Linux 文件操作总结

java锁机制介绍

java锁 乐观锁与悲观锁 乐观锁与悲观锁都是一种锁机制。用于实现线程同步机制。 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。适用于数据频繁修改的场景。 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。 java中的锁机制 synchronized 在java5之前,使用关键字synchronized修饰一个方法或者代码块对临界资源的保护实现多线程并发同步。有四种不同的同步块: 实例方法 静态方法 实例方法中的同步块 静态方法中的同步块 synchronized(lockObject) { //需要访问的临界资源 } ReentrantLock Java5 java.util.concurrent.locks 提供了Lock接口。Lock提供了更加灵活的锁实现。写法一般如下: lock.lock(); try { //需要访问的临界资源 } finally { lock.unlock(); } 获取锁的方式: lock() 阻塞持续等待直到获取锁 tryLock() 方式获得锁,默认不阻塞,不等待,如果能够获取锁返回true,可以设置等待时间。 lockInterruptibly() 中断锁, 使用中断锁在等待获取锁的时候,会响应线程中断。 在Java1.5中,synchronized是一个重量级操作,需要调用操作系统相关接口,性能是低效的,有可能给线程加锁消耗的时间比有用操作消耗的时间更多。到了Java1.6,synchronized进行了很多的优化,有适应自旋、锁消除、锁粗化、轻量级锁及偏向锁等,效率有了本质上的提高。在之后推出的Java1.7与1.8中,均对该关键字的实现机理做了优化。 两种锁在低并发的情况下性能都差不多,更推荐使用synchronized,毕竟不用怕忘记在finnaly中执行unlock()。 但在高并发量的条件下,synchronized性能会迅速下降几十倍,因为多了很多自旋锁操作,而ReentrantLock的性能却能依然维持一个水准。 当线程通过synchronized等待锁时是不能被Thread.interrupt()中断的 Semaphore 使用方法与ReentrantLock相似。 acquire()方法默认为可响应中断锁,与ReentrantLock.lockInterruptibly()作用效果一致。 支持多个临界资源,而ReentrantLock只支持一个临界资源 Atom系列原子类 public class AtomicInteger extends Number… Continue reading java锁机制介绍

Published
Categorized as java

java实现move操作

java实现move操作 这类操作与文件所在的文件系统息息相关. File的renameTo一般只用于同级目录修改文件名。 想要多级目录移动文件还得用Files.move方法。 同一个文件系统下会进行move操作 不同文件系统,则通过拷贝-删除的方式实现move。 package io.move; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; /** * move-test<br/> * ├── dir1<br/> * │   └── child<br/> * │   └── hui3<br/> * └── hui1<br/> * <p> * move-test<br/> * ├── dir1<br/> * │   └── child<br/> * │   └── hui3<br/> * └── hui2<br/>… Continue reading java实现move操作