工作总结_性能优化(粗稿)
性能指标
基本
吞吐量
延迟
监控系统指标:
CPU使用率,load, (Docker) Throttled_time,用户时间,内核时间
内存使用率(java进程Rss),swap
网络IO (连接数,连接状态,吞吐量)
磁盘IO
监控jvm:
堆内存 (总占用,Eden占用,Survivor占用,OldGen占用)
垃圾回收 (次数,延迟,Full GC)
jit (总编译时间,CodeCache 使用)
监控外部依赖
请求量
延迟
错误数
性能分析
简单的排队模型理论: 延迟随使用率呈指数上升趋势
明确性能优化目标,延迟 or 吞吐
建立性能测试环境!!!与生产越接近越好
吞吐量:不断增大负载,检查性...
工作总结_应用可用性
故障隔离
隔离是为了在发生故障时,将传播和影响范围尽可能限定在一个较小的范围内,避免造成滚雪球效应,导致整个系统的不可用
进程内隔离
在公司的发展过程中,不可避免的会形成一些大而全的应用,为了避免某些功能的某些模块出现异常导致应用的所有功能的不可用,需要在应用中不同功能模块间做隔离。
优点:模块间通信方便,开发简单,功能间无需拆分单独部署
缺点:CPU,内存等资源无法做到隔离,如果某模块出现故障耗尽CPU及内存,故障仍然会扩散至整个进程中
案例1:某模块代码bug,出现死循环,将CPU耗尽,整个服务处理能力大幅下降
案例2:某模块本地内存缓存巨量膨胀,将内存耗尽,频繁Full GC,整个服务处理能力大幅下降
进程内隔离方式
线程池隔离
不同模块设置不同的线程池进行执行,...
自制一个简易的缓存组件
简介
github:https://github.com/nothinghappen/tinyCache
一个简易的本地内存缓存组件,支持缓存查询,定时更新,过期删除,LRU缓存驱逐,并且支持并发读写
设计背景为读高频,写低频的场景
功能
创建
通过Builder创建一个Cache实例
// 无容量限制的缓存
Cache cache = CacheBuilder.newBuilder().build();
// 容量限制为100的缓存
Cache cache = CacheBuilder.newBuilder().setCapacity(100).build();
添加
通过add方法添加缓存
Cache cache = CacheBuilder.newBuil...
jvm堆外内存上升排查
背景
应用内存在由32G缩小至16G后,经常出现docker OOM。设置的java堆大小为11G,而java进程Rss不断上升最终导致OOM,因此怀疑是堆外内存上升导致的
排查
pmap
先用pmap观察内存映射情况,发现有很多64M的内存映射。google了一下,发现是glibc默认内存分配器ptmalloc的分配区(arena)。
在 Doug Lea 实现的内存分配器中只有一个主分配区(main arena),每次分配内存都必须对主分配区加锁,分配完成后释放锁,在 SMP 多线程环境下,对主分配区的锁的争用很激烈,严重影响了 malloc 的分配效率。于是 Wolfram Gloger 在 Doug Lea 的基础上改进使得Glibc 的 malloc 可以支持...
MySql随笔--索引
索引
聚集索引(clustered index) : id为PK,聚集索引,叶子节点存储行记录;
辅助索引(secondary index) : name为KEY,普通索引,叶子节点存储PK值,即id
回表:通过辅助索引查询数据,需要扫描两遍索引树:
先通过普通索引定位到主键值id=5
在通过聚集索引定位到行记录
B+树索引
可用查询类型,假设存在索引 (a,b,c),最左前缀匹配原则,想要所有列都使用索引,筛选条件必须按照索引字段从左到右的顺序匹配,并且向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如
全值匹配 select * from table where a=xxx and b=xxx and c=xxx
...
TCP连接大量CLOSE_WAIT
背景
线上一台机器突然出现大量调用其他服务超时异常。过了一遍监控指标,发现网络连接指标存在异常,机器上处于CLOES_WAIT状态的tcp连接数量从某一时刻开始不断上升,并且已经积累了一定的量
首先回顾一下TCP连接的状态转移,如图:
CLOSE_WAIT状态处于TCP四次挥手的过程中,当对端主动关闭连接时,会向本端发送FIN,本端回复ACK,此时本端的tcp连接状态就进入CLOES_WAIT状态。接着本端在发送FIN给对端,对端回复ACK,此时tcp连接进入CLOSED状态,完成可tcp连接的关闭。
大量的tcp连接处于CLOES_WAIT状态,说明对端主动关闭tcp连接,本端(被动关闭的一方)没有发出FIN包
分析
首先怀疑应用程序代码的问题,调用其他服务...
Redis横向扩容带来的性能衰退
问题背景
某应用每次查询需要通过mget从Redis批量获取大批key的数据,某次Redis集群改造,将该应用读取的Redis集群由原来的4个分片扩展为20个分片。改造完成后应用读取Redis耗时出现大幅上升
问题原因
目前Redis集群通过特定的hash策略将key映射到不同的分片上,且hash策略通常与业务无关。这就造成了业务上一次批量获取的key的数据,可能分布在多个分片上。
客户端在使用mget批量获取数据时,需要多次网络IO从不同的分片上去获取数据。而目前公司框架部门封装的Redis客户端的实现为串行IO,也就是说会串行的从多个实例上读取数据
而随着集群分片数量的增多,数据分散在更多的分片上,导致客户端mget批量获取数据时需要更多的网络IO,最终导致耗时上升。同时网络...
应用full gc排查记录
问题背景
应用使用G1 GC,在某一时刻后,开始出现频繁的full gc
排查
通过gc 日志获取一些线索
存在大量大对象分配,大部分触发GC的原因为大对象分配,相关日志片段:[GC pause (G1 Humongous Allocation)
存在转移失败(to-space exhausted),转移失败一般发生在young gc后survivor区和老年代空间没有足够空间容纳存活对象时,转移失败会导致较长的young gc耗时。转移失败时,回收器会将未成功复制的分区全部置为老年代分区,并且一般之后会紧跟着一次full gc进行全堆的回收。但是分析日志后并不是每次转移失败后都会进行full gc,这里猜测是因为JDK8u60之后,在年轻代回收的最后(对象转移之后),会进行巨型...
共计 22 篇文章,3 页。