从Java转向Go--AeroFS的一段奇妙之旅

createh55个月前 (02-01)技术教程46

AeroFS是一家为企业提供安全和廉价的私有云存储方案。日前,AeroFS的开发团队发现程序内存发现异常(AeroFS应用大部分是基于Java开发的),经过排查后发现JVMs之间无法进行更多的只读内存共享,于是决定采用新的开发工具,选用Go语言,随后,代码减半、常驻内存下降、Docker镜像内存也减少许多。AeroFS开发团队将这一事件记录下来,我们一起来看下。

AeroFS应用由很多微服务构成,主要以Java来编写。在一段时间里,它运作良好,服务的用户约为几千。但当我们转到Docker时,发现程序内存占用出现大幅攀升。于是前期我们先是使用了Docker监控工具进行检查,最后得出如下的检测脚本:

for line in `docker ps | awk '{print $1}' | grep -v CONTAINER`; do \

  echo $(( `cat /sys/fs/cgroup/memory/docker/$line*/memory.usage_in_bytes` / 1024 / 1024 ))MB \

  $(docker ps | grep $line | awk '{printf $NF" "}') ; \

done | sort –n

运行后输出结果是运行中的容器清单,以常驻内存大小进行排序。例如:

  • 46MB web
  • 66MB verification
  • 74MB openid
  • 82MB havre
  • 105MB logcollection
  • 146MB sp
  • 181MB Sparta

该分析没有覆盖那些内存占用异常高的Java服务,因为这是非常规的。我们总结了几点造成内存占用高的因素:

  1. 由于tomcat servlet被放置于单独的容器上,造成JVMs的增加。
  2. JVMs之间无法进行更多的只读内存共享:原因是所有共享库都依赖于JVM本身,以及很多JARs是被多服务所使用的。
  3. 内存分离会导致过多的批量启发,从而使由服务分配的缓存增多。

有鉴于此,我们决定使用新的工具。

代码名字:Greasefire

随后我把该为AeroFS程序减负的项目作为黑客松参赛项目,我的竞赛点是:

  • CPU占用下降
  • 保持内存的稳定和安全
  • 常驻内存占用减少一倍甚至更多

新工具尝试

为了实现CPU和内存的优化目标,选择的语音需要以系统编程为设计根本。经过一番筛选后,Go和Rust成为了我的目标。这两者都能很方便地编译出能在最小型容器运行的小型静态二进制代码,都具有良好的性能表现,安全性以及并发处理支持,最关键的是比JVM有着更少的内存占用。

Rust的类型系统特性非常迷人。但是它与Go相比还是显得稚嫩,同时支持库在HTTP和低阶网络编程上有所欠缺。

与C家族相近的Go入门较易,但是有很多独有的特性需要结合支持文档进行细读。幸好支持文档写得详尽而细致,与标准库资源无缝连接,所以能够使初学者写出清晰可读性高的代码。此外,易于与文本编辑器如vim等整合的gofmt工具的提供,也是很令人兴奋的。

结果

  • 代码缩减了约一半,从175行减少为96行。
  • 常驻内存从87MB下降为3MB,减少了将近29倍。
  • Docker镜像大小从668MB减少为4.3MB。

在黑客马拉松的最后一天,我还对CA(Certificate Authority 认证授权)进行了优化。我们的认证服务先是从内部服务和桌面用户机器上接收证书签名请求,然后以P2P方式在用户和服务器间返回相关签名认证。当我以新CA替换原来的Java时,常驻内存更是减少了100倍。最后,该项目获得了黑客松的技术卓越奖。

原文链接:Aerofs

相关文章

Python之面向对象:私有属性是掩耳盗铃还是恰到好处

引言声明,今天的文章中没有一行Python代码,更多的是对编程语言设计理念的思考。上一篇文章中介绍了关于Python面向对象封装特性的私有属性的相关内容,提到了Python中关于私有属性的实现是通过“...

Java基础——面试官:你来说说反射如何获取私有对象的属性和方法

最近,@Python大星 的朋友小鹿参加了一场#Java#面试。有一道题是这样的 >>>【面试官问:你来说说反射如何获取私有对象的属性和方法?】问题的答案我们文章中揭晓,先看下反射的...

思考:Java对象之生(java中对象的概念的理解)

内存、性能是程序永恒的话题,实际开发中关于卡顿、OOM也经常是打不完的两只老虎,关于卡顿、OOM的定位方法和工具比较多,这篇文章也不打算赘述了,本章主要是来整理一下JVM的内存模型以及Java对象的生...

内部类Java(内部类定义)

概念将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。什么时候使用内部类一个事物内部还有一个独立的事物,内部的事物脱离外部的事物无法独立使用比如汽车只有一个发动机,电脑只有一...

终于搞懂了 Java 8 的内存结构,再也不纠结方法区和常量池了

java8内存结构图虚拟机内存与本地内存的区别Java虚拟机在执行的时候会把管理的内存分配成不同的区域,这些区域被称为虚拟机内存,同时,对于虚拟机没有直接管理的物理内存,也有一定的利用,这些被利用却不...

Java虚拟机运行时数据区的内部结构布局

运行时数据区的内部结构主要分为方法区(Method Area)、堆(Heap)、程序计数器(Program Counter Register)、本地方法栈(Native Method Stack)、虚...