pprof 实战-服务性能分析与优化
背景
最近重构了我们业务上的一个服务,该服务的功能是为终端提供一些版本文件信息和素材数据信息。
具体到代码逻辑上也非常简单,就是把配置在数据库表里的数据都捞到本地缓存,每次请求的时候,根据终端的版本信息做一些过滤判断,然后把本地缓存的所有文件数据都下发下去。
由于终端请求机制等等历史原因,该服务存在两个问题:一个是每天0点的时候请求流量会暴涨,工作日会涨1倍流量,而节假日有时候可能会3-4倍;另一个是每次请求时,会把数据库中的所有数据全部下发下去,也就导致每次请求返回的包体都很大。
在实际线上监控中发现,每到0点的时候,就会出现耗时猛涨一波的情况,而此时CPU和内存使用率虽然也有上涨,但基本也不会到很高的级别,所以对这里出现的原因进行了具体的分析。
而要说 Go 服务的性能分析,那就不得不提到 pprof 这个性能分析利器,本文也借着本次性能分析优化记录一下使用 pprof 的实战经验。
rocksDB
背景
嵌入式数据库 RocksDB 是 Facebook 基于 LevelDB 开发的一种嵌入式 Key-value 存储系统,该数据库能够充分利用闪存的性能,大大提升应用服务器的速度。
Rocksdb 这个开源引擎是基于 Google 的 leveldb 1.5 版本,据说对其做了许多优化,性能相对 leveldb 有了很大的提升,而且解决了 leveldb 主动限制写的问题。
Facebook 使用 RocksDB 来驱动一些面向用户的应用,这些应用由于需要通过网络访问外部存储而性能低下,此外 Facebook 还用 RocksDB 来解决固态硬盘 IO利用率不高相关的一些问题。Facebook 的数据库工程师 Dhruba Borthakur 在其个人博客介绍了 RocksDB 的设计原由和原理,但实际上催生 RocksDB 的最大动力来自服务器闪存存储卡的价格大幅下滑,Facebook 的定制服务器已经开始全面采用闪存。
随着闪存存储时代的到来,一些新的应用可以在闪存中管理并快速访问自己的数据集,无需通过网络访问外部数据。这些新应用使用的就是这种嵌入式数据库。
数据库查询如果在本地闪存中进行,速度理论上会比通过数据中心内部网络查询快一倍,因为数据库中心内部网络有50微妙的延迟。
RocksDB 的能够充分利用闪存的高IOPS性能,同时也能利用多核服务器的计算性能。
Kafka 知识汇总
简介
Kafka 被定位为一个分布式流式处理平台,它以高吞吐、可持久化、可水平扩展、支持流数据处理等多种特性而被广泛使用。Kafka 在现代的系统中主要承担三大角色:
- 消息系统:Kafka 和传统的消息系统(也称作消息中间件)都具备系统解耦、冗余存储、流量削峰、缓冲、异步通信、扩展性、可恢复性等功能。与此同时,Kafka 还提供了大多数消息系统难以实现的消息顺序性保障及回溯消费的功能。
- 存储系统:Kafka 把消息持久化到磁盘,相比于其他基于内存存储的系统而言,有效地降低了数据丢失的风险。也正是得益于Kafka 的消息持久化功能和多副本机制,我们可以把Kafka作为长期的数据存储系统来使用,只需要把对应的数据保留策略设置为“永久”或启用主题的日志压缩功能即可。
- 流式处理平台:Kafka 不仅为每个流行的流式处理框架提供了可靠的数据来源,还提供了一个完整的流式处理类库,比如窗口、连接、变换和聚合等各类操作。
Go 内存对齐
一次内存泄漏的排查
业务背景
我们有一款产品跟海外某个国家的客户有业务合作,因此,我们在这个国家的服务器上单独部署了一整套的服务(大概有八九个微服务),这些服务的宿主机大概都集中在三、四台宿主机上。这些服务日复一日,年复一年的并肩作战着,直到有一天……
初见端倪
前阵子,我们在一个服务进行扩容、重启的时候,总是概率性的出现如下错误导致的 panic:
Google 的结果是说由于 Linux 分配的客户端连接端口用尽,无法建立 socket 连接导致的。
这时候还有点懵逼,单纯以为是容器的宿主机有问题,于是,我重新在另外一台机器进行了节点扩容,这次很幸运,服务启动成功了,于是乎以为问题已经顺利解决,可以美美的下班了。
Golang 常见问题
使用 channel 导致的死锁和内存泄漏问题
使用 channel 导致的死锁和内存泄漏问题
死锁出现的条件
死锁有三个必要条件他们分别是循环等待、资源共享、非抢占式,在 go 并发中出现通道死锁只有两种情况:
- 数据要发送,但是没有人接收;
- 数据要接收,但是没有人发送;
发送单个值的死锁
在下面这种情况下,就会出现死锁的情况:
a := make(chan int)
a <- 1 //将数据写入channel
z := <-a //从channel中读取数据
原因在于:
- 有且只有一个协程时,无缓冲的通道
- 先发送会阻塞在发送,先接收会阻塞在接收处。
- 发送操作在接收者准备好之前是阻塞的,接收操作在发送之前是阻塞的。
解决办法就是改为缓冲通道,或者使用协程配对。