个人博客网站制作教程,怎么建免费网站,建筑企业办公系统公司,简易h5制作开发作为站点可靠性工程师 #xff08;SRE#xff09;#xff0c;我确保我们的生产服务高效#xff0c;可扩展且可靠。 典型的SRE是生产大师#xff0c;必须对更广泛的体系结构有很好的了解#xff0c;并精通许多更精细的细节。 SRE是会说多种语言的程序员#xff0c;这是很… 作为站点可靠性工程师 SRE我确保我们的生产服务高效可扩展且可靠。 典型的SRE是生产大师必须对更广泛的体系结构有很好的了解并精通许多更精细的细节。 SRE是会说多种语言的程序员这是很常见的他们希望能够理解多种不同的语言。 例如C 可能很难编写测试和正确使用但具有高性能非常适合诸如数据库之类的后端系统。 Python很容易编写非常适合快速编写脚本对自动化很有用。 Java位于中间位置尽管它是一种编译语言但它提供了类型安全性性能以及许多其他优点使其成为编写Web基础结构的理想选择。 尽管SRE采用的许多最佳实践可以推广到任何语言但是Java还是存在一些独特的挑战。 本文计划重点介绍其中一些并讨论我们可以采取哪些措施来解决这些问题。 部署方式 一个典型的Java应用程序由数百个类文件组成这些类文件由您的团队编写或者由应用程序依赖的通用库编写。 为了控制类文件的数量并提供更好的版本控制和分隔通常将它们捆绑到JAR或WAR文件中。 托管Java应用程序的方法有很多一种流行的方法是使用Java Servlet容器例如Tomcat或JBoss 。 从理论上讲它们提供了一些通用的Web基础结构和库以使其更易于部署和管理Java应用程序。 以Tomcat一个提供实际Web服务器并代表您加载应用程序的Java程序为例。 这在某些情况下可能会很好地起作用但实际上会增加额外的复杂性。 例如您现在需要跟踪JRE版本Tomcat版本和应用程序版本。 测试不兼容性并确保每个人都使用相同版本的完整堆栈可能会出现问题并导致细微的问题。 Tomcat还带来了自己的定制配置这是另一回事。 一个很好的承租人是“ 保持简单 ”但是在Servlet容器方法中您必须跟踪几十个Tomcat文件一个或多个组成应用程序的WAR文件以及所有的Tomcat配置。随之而来。 因此有些框架通过嵌入自己的Web服务器而不是托管在完整的应用程序服务器中试图减少这种开销。 仍然有一个JVM但它会调用一个JAR文件其中包含运行该应用程序所需的所有内容。 支持这些独立应用程序的流行框架是Dropwizard和Spring Boot 。 要部署该应用程序的新版本只需更改一个文件然后重新启动JVM。 这在开发和测试应用程序时也很有用因为每个人都在使用相同版本的堆栈。 对于回滚SRE的核心工具之一来说它也特别有用因为只需更改一个文件即可可以快速更改符号链接。 Tomcat样式的WAR文件要注意的一件事是该文件将包含应用程序类文件以及该应用程序依赖于JAR文件的所有库。 在独立方法中所有依赖项都合并到单个Fat JAR中 。 单个JAR文件其中包含整个应用程序的类文件。 这些Fat或Uber JAR不仅易于版本化和复制因为它是单个不可变文件而且由于对依赖项中未使用的类进行修剪而实际上可以小于等效的WAR文件。 通过不需要单独的JVM和JAR文件甚至可以更进一步。 实际上例如capsule.io之类的工具可以将JAR文件JVM和所有配置捆绑到一个可执行文件中。 现在我们可以真正确保整个堆栈都使用相同的版本并且部署与服务器上可能已经安装的内容无关。 保持简单并使用单个Fat JAR或可能的可执行文件使应用程序的版本快速便捷。 启动 即使Java是一种编译语言它也不会编译为机器代码而是会编译为字节码。 在运行时Java虚拟机JVM解释字节码并以最有效的方式执行它。 例如 即时 JIT编译使JVM可以监视应用程序的使用方式并即时将字节码编译为最佳机器代码。 从长远来看这对应用程序可能是有利的但是在启动过程中它可能会使应用程序在数十分钟或更长时间内处于次优状态。 需要注意的是这对负载平衡监视容量规划等有影响。 在多服务器部署中最佳实践是将流量缓慢增加到新启动的任务使其有时间进行预热并且不损害服务的整体性能。 在将新任务放入用户服务路径之前您可能会通过向其发送人工流量来预热新任务。 如果预热过程无法逼近正常的用户流量则人工流量可能会出现问题。 实际上这种伪造的流量可能会触发JIT对通常不会发生的情况进行优化从而使应用程序处于未达到最佳状态或处于比未进行JIT时更糟糕的状态。 容量规划时也应考虑启动缓慢。 不要期望冷任务与热任务处理相同的负载。 推出新版本的应用程序时这一点很重要因为系统的容量会下降直到任务预热。 如果不考虑这一点可能会同时重新加载太多任务从而导致基于容量的级联中断。 期待冷启动并尝试以实际流量预热应用程序。 监控方式 该建议是通用的监视建议 但是对于Java值得重复。 确保从Java应用程序导出最重要和最有用的度量标准并对其进行收集并轻松绘制图形。 有许多工具和框架可用于导出指标甚至还有更多的工具和框架可用于收集汇总和显示。 当出现问题时应该仅从收集的指标中排除故障即可 。 您不应该依赖日志文件或查看代码来处理中断。 大多数中断是由更改引起的。 也就是说应用程序的新版本配置更改新的流量来源硬件故障或后端依赖关系的行为不同。 应用程序导出的度量标准应包括识别Java版本应用程序和使用中的配置的方法。 它应该分解流量混合错误计数等的来源。还应该跟踪后端依赖项的运行状况延迟错误率等。 在大多数情况下这足以快速诊断出故障。 特定于Java的指标可以帮助您了解应用程序的运行状况和性能。 指导有关如何扩展和优化应用程序的未来决策。 垃圾回收时间堆大小线程数JIT时间都很重要并且特定于Java。 最后关于测量响应时间或等待时间的注释。 也就是说应用程序处理请求所花费的时间。 许多人会误以为平均等待时间部分原因是它很容易计算。 平均值可能会引起误解 因为它没有显示分布的形状 。 大多数请求可能会很快得到处理但请求的尾部可能很少但需要一段时间。 这对于JVM应用程序尤其令人不安因为在垃圾回收过程中有一个“ 停止世界” STW阶段在此阶段应用程序必须暂停以允许垃圾回收完成。 在此暂停中不会响应任何请求并且用户可能要等待几秒钟。 最好收集最大或99或更高的百分比延迟。 对于百分位数也就是说每100个请求中有99个的送达速度快于该数字。 查看最坏情况下的延迟更有意义并且更能反映用户感知的性能。 衡量重要的指标以后可以依靠。 内存管理 您花费大量时间来学习各种JVM垃圾收集算法 。 当前的最新状态是并发收集器G1或CMS 。 您可以决定哪种方法最适合您的应用程序但目前G1可能是赢家。 有很多很棒的文章解释了它们的工作方式但我将介绍一些关键主题。 启动时Java虚拟机JVM通常会保留大量OS内存并将其分为堆和非堆。 非堆包含诸如Metaspace 正式称为Permgen 和堆栈空间之类的区域。 元空间用于类定义而堆栈空间用于每个线程的堆栈。 堆用于创建的对象这些对象通常占用大部分内存使用量。 与典型的可执行文件不同JVM具有-Xms和-Xmx标志 用于控制堆的最小和最大大小。 这些限制限制了JVM将使用的最大RAM量这可以使服务器上的内存需求可预测。 通常将这两个标志设置为相同的值以提供它们以填充服务器上的可用RAM。 还有一些针对Docker容器调整大小的最佳实践。 垃圾回收GC是通过查找不再使用即不再引用且可以回收的Java对象来管理此堆的过程。 在大多数情况下JVM会扫描对象的完整图并标记找到的对象。 最后将所有未访问的内容删除。 为了确保没有竞争状况GC通常必须停止运行STW这会在应用程序完成时将其暂停一会儿。 GC是可能是不必要的怨恨的根源因为它被归咎于许多性能问题。 通常这归结为不了解GC的工作原理。 例如如果堆的大小太小则JVM可以主动进行垃圾收集从而徒劳地释放空间。 然后应用程序可能会陷入“ GC崩溃 ”循环中这在释放空间方面几乎没有进展并且在GC中花费了越来越多的时间而不是运行应用程序代码。 可能发生这种情况的两种常见情况是内存泄漏或资源耗尽 。 垃圾收集的语言不应允许通常所说的内存泄漏但是它们可能会发生。 例如维护一个永不过期的对象的缓存。 此缓存将永远增长即使该缓存中的对象可能永远不会再使用它们仍然被引用因此不适合进行垃圾回收。 另一个常见的情况是无限队列 。 如果您的应用程序将传入的请求放置在无限制的队列中则该队列可能永远增长。 如果请求数量激增保留在队列中的对象可能会增加堆使用率从而导致应用程序在GC中花费越来越多的时间。 因此应用程序将有更少的时间来处理来自队列的请求从而导致积压量增加。 随着GC努力寻找任何要释放的对象这逐渐失去控制直到应用程序无法取得任何进展。 另外一个细节是垃圾收集器算法具有许多优化措施可以尝试减少总的GC时间。 一个重要的发现 弱代假设 是对象要么存在很短时间例如与处理请求有关要么存在很长时间例如管理寿命长的资源的全局对象。 因此堆进一步划分为年轻空间和旧空间。 在年轻空间中运行的GC算法假定对象将被释放否则GC会将对象提升到旧空间。 用于旧空间的算法做出了相反的假设即对象不会被释放。 因此也可以调整年轻人/老年人的大小并且根据G1或CMS方法将有所不同。 但是如果年轻空间太小那么应该只存在很短时间的物体最终将被提升到旧空间。 打破了旧的GC算法所做的某些假设导致GC的运行效率降低并导致了诸如内存碎片之类的次要问题。 如前所述GC是长尾延迟的来源因此应关闭监视。 应该记录GC每个阶段所花费的时间以及GC运行之前和之后堆空间的满度按年轻/旧/等等分解。 这提供了调优或改进应用程序以控制GC所需的所有提示。 让GC成为您的朋友。 应该特别注意堆和垃圾收集器并且应该对其进行调整甚至是粗略地调整以确保即使在满载/最坏的情况下也有足够的堆空间。 其他技巧 调试 Java有许多丰富的工具可用于在开发和生产过程中进行调试。 例如可以捕获正在运行的应用程序中的实时堆栈跟踪和堆转储。 这对于了解内存泄漏或死锁很有用。 但是通常必须确保应用程序已启动以允许这些功能并且典型工具jmap jcmd等在服务器上实际可用。 在Docker容器或非标准环境中运行应用程序可能会使此操作更加困难因此请测试并编写一本有关如何执行此操作的手册。 许多框架还通过Web服务公开了许多此类信息以便于调试例如Dropwizard / threads资源或Spring Boot生产端点 。 不要等到出现生产问题后立即测试如何获取堆转储和堆栈跟踪。 更少但更大的任务 JVM的许多功能对每个运行的JVM都有固定的成本例如JIT和垃圾回收。 您的应用程序也可能具有固定的开销例如资源轮询后端数据库连接等。如果运行较少但较大的实例就CPU和RAM而言则可以减少此固定成本从而实现规模经济。 我已经看到Java应用程序拥有的CPU和RAM数量增加了一倍使它每秒能够处理4倍的请求不影响延迟。 但是这对应用程序以多线程方式进行扩展的能力做出了一些假设但是通常垂直扩展比水平扩展容易。 使您的JVM尽可能大。 32位和64位Java 如果您的应用程序使用的RAM不超过4GiB则通常会运行32位JVM。 这是因为32位指针的大小是64位大小的一半这减少了每个Java对象的开销。 但是由于现代CPU是64位的通常具有64位特定的性能改进并且RAM的价格便宜这使得64位JVM无疑是赢家。 使用64位JVM。 减载 还是一般性建议但对Java很重要。 为避免 GC崩溃或任务繁重而导致过载 应用程序应积极减少负载。 也就是说超出某个阈值应用程序应拒绝新请求。 尽早拒绝某些请求似乎很糟糕但是比允许应用程序变得不可恢复并导致所有请求失败都更好。 有许多避免过载的方法但是常见的方法是确保队列有界并且线程池的大小正确 。 此外出站请求应该有适当的截止日期 以确保缓慢的后端不会对您的应用程序造成问题。 尽可能多地处理请求而不再处理。 结论 希望本文使您考虑一下Java生产环境。 尽管不是说明性的但我们重点介绍了一些重点领域。 整个链接都应指导您正确的方向。 如果您有任何疑问或意见请通过TheBramp与我联系或访问我的网站和博客bramp.net了解更多文章。 翻译自: https://www.javacodegeeks.com/2017/12/running-java-production-sres-perspective.html