【AICon】探索RAG 技术在实际应用中遇到的挑战及应对策略!AICon精华内容已上线73%>>> 了解详情
写点什么

Java 云托管服务的开支削减策略

  • 2017-09-19
  • 本文字数:3784 字

    阅读完需:约 12 分钟

摘要

  • 随着项目不断扩大,你需要将其迁移到更大的虚拟机上。但如果新虚拟机环境超出了你的需求则会产生额外开支。
  • 相比虚拟机,容器具有更小的粒度,并且无需重启运行中的实例即可垂直扩展。
  • 单体应用和历史遗留应用无需更改配置,即可从虚拟机迁移至容器中。
  • Java 的垂直扩展需要适当配置 JVM 和清理垃圾回收器。
  • “即用即付”和“按需付费”这两种云收费模型的对比,及提高效率的正确选择。

云服务会很昂贵,而当你为不需要的资源付费时尤其如此;另一方面,资源不足又会导致宕机。身为程序员该如何应对?这篇文章将会讨论一些技术,来帮助你恰到好处地只支付实际消耗的资源,且不受应用体量增长的限制。

认清现实:你在虚拟机上多花钱了

任何解决方案的第一步当然都是要承认问题的存在。以下详述大部分云用户都在面对的问题:

几乎所有的云服务供应商都提供一系列不同体量的虚拟机供选择。而如何选择合适的体量往往让人左右为难:选小了会有性能问题,负载上去搞不好还会挂。选多了?那常规负载和空闲时的资源就都浪费了。你自己的云托管应用是不是经历过类似的情形?

当项目开始横向扩展,资源使用低效的问题会重复出现在每个新加入的实例上。所以,这个问题也会相应地增长。

进一步说,如果你想在同一个虚拟机中增加一点点服务,目前大部分云服务供应商能提供的唯一方案是更换双倍体量的虚拟机。参考AWS 的方案:

更糟糕的是,迁移过程会导致服务中断:需要停掉现在的虚拟机,一步步重新部署或迁移应用,其中不可避免会有相关的棘手问题需要解决。

可见虚拟机在资源使用方面不够灵活高效,并且针对动态负载的调整能力很有限。这种缺乏弹性的方式导致了额外的开支。

如何高效地进行双向扩展

如果横向扩展无助于资源的高效利用,我们就需要深入虚拟机内部,理解垂直扩展是如何实现的。

垂直扩展可以在现有基础上优化任何应用实例的内存和CPU 使用。如果配置得当,这种方法对单体应用和微服务都同样有效。

在虚拟机内通过动态增加或减少资源来进行垂直扩展同时又不中断服务是一项艰巨的任务。虚拟机提供了内存膨胀(memory balloning)的技术,但它并不是自动化的,需要用工具监控宿主系统和客户系统中的内存压力,然后进行相应的向上或向下扩展。而实际情况是这个方法并不太好用,自动化的内存共享才更实用。

得益于开创性的同宿主内容器间资源自动分享,基于 cgroups 的容器技术拥有更高级别的灵活性。在设定范围内,空闲的资源会自动分配给相同硬件节点内的其他容器。

不同于虚拟机,容器内的资源无需重启应用实例即可轻松实现扩展。

结果就是,同一容器实时更改体量大小要比迁移至更大的虚拟机更加容易、经济和迅速。

从虚拟机迁移至容器

容器分为两种:应用容器和系统容器。应用容器(如Docker 或rkt)一般运行在单个进程中,而系统容器(LXD、OpenVZ)则更像是完整的操作系统,可以运行全功能的初始化系统如systemd、SysVinit 和openrc,这些初始化系统允许在单一容器中的进程孵化出其他进程如openssh、crond 或syslogd 等。这两种容器都支持垂直扩展来让资源分配更有效率。

理想情况下,在一个新项目中你可能想基于应用容器开始从头设计,因为应用容器可以使用Docker 公开的模板较为容易地创建所需镜像。但关于容器的一个普遍存在的认知误区就是容器只适用于全新的应用(微服务和原生云)。已有的经验和用例可以证实,将已有的工作从虚拟机迁移至容器,而不重写或重新设计应用也是完全可能的。

对于单体应用和遗留应用来说,使用系统容器会更合适,因为你可以重用之前为虚拟机设计的架构和配置等:使用标准网络配置,如组播;在容器内运行多个进程,避免因不恰当的内存限制决策导致的问题;确保在容器重启过程写入本地文件系统是安全的;依照现有的方法排查问题和分析日志;使用大量基于SSH 的配置工具;对其他老旧但重要的任务有较好兼容性。

为了从虚拟机中迁移出来,单体应用的拓扑结构需要拆解成更小的逻辑块,分布于互联的容器内。下图简单示意了拆解过程:

每个应用组件被置于隔离的容器内。通常这样可以简化应用的拓扑结构,因为项目中的某些部分可能在新架构中不是必需的。

例如,Jave EE WebLogic Server 在虚拟机环境中运行大致需要包含三种实例:管理服务器、节点管理(进程)和被管理服务器。拆解之后,我们可以去掉节点管理,因为它是作为虚拟机代理来添加或删除被管理服务器实例的。而现在,利用容器的编排(orchestration)平台以及一系列 WLST(WebLogic Server Scriting Tool)脚本,容器可以自动添加被管理服务器实例并将其直连到管理服务器上。

为继续迁移,你需要准备所需的容器镜像。对系统容器来说,这个过程比应用容器要复杂一点。你可以自己编译生成,或者使用像 Jelastic 之类的包含系统容器预设模板的编排工具来完成。

最后,部署项目并配置所需的互联接。

现在每个容器都可以动态向上向下扩展而无需停机。相比于虚拟机,容器更加轻量,所以扩展花费的时间比起虚拟机也要少得多。因为容器很容易从头再分配或克隆,所以横向扩展同样变得很顺畅。

启用带有内存收缩机制的垃圾回收器

对y 于Java 的垂直扩展来说,只用容器是不够的;JVM 同样需要合理配置。尤其值得注意的是,你所选择的垃圾收集器需要在运行时提供内存收缩机制。

这种垃圾收回收会将所有存活对象打包,去除垃圾对象,撤回(uncommit)和释放空闲内存。相较而言,如果是不支持内存紧缩的垃圾收集器或未经优化配置的JVM,Java 应用会占用所有提交的内存,不能实现按应用负载变化的垂直扩展。很不幸,JDK 8 的默认并行垃圾收集器(-XX:+UseParallelGC)就不支持内存收缩,且没能解决JVM 低效使用内存的问题。幸运的是,将垃圾收集器更换为 Garbage-First (-XX:+UseG1GC)可以很容易地解决这个问题。

请看下面的例子:即使你的应用内存占用很低(图中蓝色部分),未使用的资源还是不能分配给其他进程或其他容器,因为它们全部分给了 JVM(桔红色部分)。

(点击看大图)

好消息是,JDK 9 会默认启用支持内存收缩的G1 垃圾回收器。主要的好处之一就是可以减少空闲内存碎片,同时缩短垃圾回收的停顿时间,且无需撤回未使用的堆内存。

如果你的JDK 版本低于9,可以使用以下参数启用G1 垃圾收集器:

-XX:+UseG1GC

后面这两个参数用来配置内存资源的垂直扩展:

  • Xms——设置扩展的步长

  • Xmx——设置扩展的上限

并且,在低负载或空闲期,应用应该定期调用 Full GC,如 System.gc()。此过程可在应用逻辑内部实现,或借助外部工具 Jelastic 垃圾回收代理实现。

在下图中,我们展示了启用以下JVM 启动参数后300 秒内的内存使用情况:

-XX:+UseG1GC -Xmx2g -Xms32m

(点击看大图)

如图所示,资源使用方面对比之前的例子有了巨大的提升。保留内存部分(桔红色)随着真实使用的部分(蓝色)缓慢增长,且空闲期内的资源没有浪费,所有最大堆内未使用的资源都可以被同一宿主内的其他容器或进程利用。

由此可证,容器技术和G1 垃圾回收器的结合为Java 云服务提供了最高效的资源利用。

选择按需付费的云服务

最后(但很重要)的一步是选择“按需付费”收费模型的云服务,这样我们的花销就完全基于所消耗的部分。

云计算经常被拿来和电力使用相比较,(电力公司)按需求提供资源,属于“即用即付”。但他们之间有一个主要的区别——当你只多用了一点电时,电费账单并不会翻倍!

大部分云服务供应商采用“即用即付”的收费模型,这意味着可以一开始选一个小一点的服务器,然后随着项目增长再逐步增加服务器。但就像我之前描述的那样,你不可能简单地选择刚好适合你现在需求的服务体量,然后不用额外的人工操作,不用停止服务,就能按你的需求扩展。所以你会一直为这些限制买单——一开始是小机器,然后体量加倍,最后扩展为许多虚拟机,但每个都未被充分使用。

对比而言,得益于容器技术,“按需付费”的收费模型考虑的是当前应用实例的负载,并且实时供应或回收必需的资源。结果就是,你只需支付实际使用的那部分资源,并且不需要复杂的重新配置就可以扩展。

(点击看大图)

但如果你已经受制于某个供应商,虚拟机已经在工作了,你正在为那些限制买单,且没准备好改变它,那是否还有机会缓解状况,提高效率,节省开支?答案是,你可以用一个大一点的虚拟机,在上面安装一个容器引擎,然后把工作负载从那堆小虚拟机上迁移过来。这样你的应用就会运行在虚拟机中的容器内——像夹心蛋糕一样。但这样有助于巩固和精简已占用资源,同时释放和共享未占用资源。

认识到垂直扩展的好处有助于快速排除一系列性能问题,避免盲目横向扩展带来的不必要的复杂性,以及减少云端应用的开销——无论是单体应用还是微服务。

关于作者

Ruslan Synytsky是 Jelastic 的 CEO 和联合创始人。Jelastic 向开发者提供多云平台即服务(multi-cloud Platform-as-a-Service)。他设计了平台的核心技术,可在全世界范围内的数据中心部署和运行上百万个容器。Synytsky 致力于搭建高可用集群方案,为云端遗留应用和微服务应用的自动垂直扩展和水平扩展提供改进和增强方案。他在技术和商业方面都有丰富经验,并热衷参与各种程序员、主机提供商、集成商和企业相关的交流会议。

查看英文原文: Cost Reduction Strategies on Java Cloud Hosting Services


感谢薛命灯对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-09-19 17:261413

评论

发布
暂无评论
发现更多内容

产品经理训练营--第四周作业

月亮 😝

第四章学习总结

Kalman

产品经理 产品经理训练

2 期架构师训练营 - 第十周作业与总结

云飞扬

架构师训练营第2期

快递架构设计

梧桐

2 期架构师训练营 - 第十一周作业与总结

云飞扬

架构师训练营第2期

第十三周-总结

jizhi7

第十一周课后练习

Binary

第11周学习总结

Binary

架构师训练营 4 期 第6周

引花眠

架构师训练营 4 期

MyBatis专栏 - 二级缓存

小马哥

Java mybatis 七日更 2月春节不断更

架构内容

梧桐

2 期架构师训练营 - 第十二周作业与总结

云飞扬

架构师训练营第2期

「架构师训练营 4 期」 第六周 - 001&2

凯迪

架构师训练营 4 期

2 期架构师训练营 - 第十三周作业与总结

云飞扬

架构师训练营第2期

白话Mysql的锁和事务隔离级别!死锁、间隙锁你都知道吗?

Java鱼仔

MySQL 高可用

iOS中MVC、MVP、MVVM、VIPER等技术框架的选型与实践

行者

架构设计 Architecture

大作业(二)-知识点

hunk

架构师训练营第2期

协会组织如何实现数字化落地应用?

boshi

数字化转型 七日更

大作业一

jizhi7

第十二周总结

jizhi7

第四章作业

Kalman

产品经理 产品经理训练营

数组与链表学习总结

Nick

数组 链表 数据结构与算法

第十周作业总结

jizhi7

产品 0 期 - 第四/五周作业

Jxin

记录一次BAT一线互联网公司前端JavaScript面试

我是哪吒

JavaScript 学习 面试 大前端 2月春节不断更

怀乡恋土的人们

熊斌

学习 2月春节不断更

大作业二

jizhi7

第十一周 - 总结

jizhi7

与前端训练营的日子 -- Week15

SamGo

学习

week11 作业

zbest

大作业一:

未来已来

Java云托管服务的开支削减策略_Java_Ruslan Synytsky_InfoQ精选文章