Transcript 多租户JDK
San Hong Li — Java 多租户项目技术主管 23st July 2013 针对多租户应用程序的 JVM 支持 提高应用程序密集性 © 2013 IBM Corporation 重要免责声明 本演示文稿中包含的信息仅供参考。 我们已尽力验证本演示文稿中所包含信息的完整性和准确性,这些信息按“原样”提供,不带有任何类型的明 示或暗示保证。 本演示文稿中包含的所有性能数据均在受控的环境中收集。由于硬件、软件或基础架构的差异,您自行实施的 测试结果可能会有所不同。 本演示文稿中所包含的全部数据只是用作指南。 此外,本演示文稿中包含的信息基于 IBM 目前的产品规划和战略给出,IBM 随时可能更改,恕不另行通知。 对于由于使用本演示文稿或任何其他文档,或与之相关的其他问题而造成的任何损害,IBM 及其子公司不承 担任何责任。 本演示文稿中包含的任何信息,均不具有以下意图或效果: - 构成 IBM、其子公司或 IBM 及其子公司的供应商和/或许可方的任何保证或表示 2 © 2013 IBM Corporation 演讲人介绍 ■ 8 年 Java 工作经验。 ■ 近期工作重点: ■ ■ ■ Java 虚拟机“云”改进 ■ 多租户技术 ■ JVM(J9) 开发 过往从业经历 ■ Java 安全开发(Expeditor,Lotus Notes 内核) ■ 网络编程 我的联系信息: – 邮件:[email protected] – 微博:sanhong_li 3 © 2013 IBM Corporation 本次演讲能让您有何收获? ■ 本次讲座结束后,您将能够: –理解什么是多租户以及这种模式的优点 –描述多租户 Java 部署面临的挑战 –了解将现有应用程序转换为多租户部署的新 JDK 特性 4 © 2013 IBM Corporation 议题 1. 不要重复自己的劳动:简化可节省时间和金钱 2. 攀登多租户的大山:面临的挑战和登顶路线 3. 守望相助:应对不良行为 4. 风险和回报:我们能实现多高的密集性? 5. 总结:总结及后续步骤 注意:本次演讲具有前瞻性,IBM Java 团队 正在为演讲中提及的许多特性而努力,这些特性可能会包含在未来的版本中。 5 © 2013 IBM Corporation 引言 通过消除所有不必要的部分简化软件体系,从而更好地利用硬件( 以及运行软件的人员)。 简单 == 更廉价 == 可预测 == 强健 6 © 2013 IBM Corporation 不要重复自己的劳动:简化可节省时间和金钱 “每则知识在系统中必须具有唯一、明确、权威的表示” 《程序员修炼之道》(Pragmatic Programmer,Hunt 和 Thomas) (换言之:复制和粘贴容易引发问题) 7 http://www.instructables.com/id/How-To-Create-A-LEGO-Star-Wars-Clone-Army/ © 2013 IBM Corporation 什么是多租户 ■ 多租户指的是软件架构的一种原则,在多租户架构中,在一个服务器上运行的软 件的单个实例同时为多个客户端组织(租户)提供服务。 多租户是相对于多实例架构而言的,在多实例架构中,需要为不同的客户端组织 建立不同的软件实例(或硬件系统)。 在多租户架构中,软件应用程序设计为对数据和配置进行虚拟化分区,每个客户 端组织则使用一个自定义的虚拟应用程序实例。 鸣谢 8 © 2013 IBM Corporation 多租户对于企业的意义 • 多租户 == 简化 • 单一软件实例为多个客户端组织(租户)提供服务 • 软件应用程序设计为对数据和配置进行虚拟化分区,每个客户端组织则使用一 个自定义的虚拟应用程序实例 • PaaS/SaaS 机会 == 效率就是金钱 9 © 2013 IBM Corporation SaaS 租户解决方案演进 10 信息来源:Peter Cousins 和 Jim Colson 白皮书 © 2013 IBM Corporation 多租户的效率 ■ 客户观点 –成本:提供商运行服务 –价值实现时间:快速启动和运行,通常频繁、快速获得升级 –服务质量:需要关注 SLA,但不需要具备运行基础架构的能力 –绕过 IT 积压:简化的部署(由提供商处理) ■ 提供商观点 –成本:尽量减少移动部件/重复 –敏捷性:升级、备份、投入使用 11 © 2013 IBM Corporation 攀登多租户的大山 面临的挑战和一条*相对容易的登顶路线 * 多条路线中的一条 12 © 2013 IBM Corporation 多租户挑战 1:隔离 ■ 同样多的鸡蛋(应用程序),更少的篮子 ■ 您需要精心准备上好的篮子 ■ 并非新问题 http://circa71.wordpress.com/2010/07/ 13 http://bit.ly/e7G1jb © 2013 IBM Corporation 多租户挑战 2:入门成本 合并 合并 简单 == 无应用程序更改 仅共享虚拟机管理程序 端口冲突 文件系统冲突 安全挑战 14 在应用程序之间隔离数据 控制资源独占 JVM 能够提供帮助! JVM 通过 -Xshareclasses 提供帮助 © 2013 IBM Corporation 专用中间件的成本(以 JVM 为中心) Java 堆占用数百 MB 的内存 –JVM 之间不能共享堆对象 –GC 默认具有一个每核心帮助程序线程 即时 (JIT) 编译器占用数十 MB 的内存 –生成的代码专用且量大 –生成的代码具有很高的生成成本 • 窃取应用程序的时间 • 默认具有多个编译线程 JVM 实例之间无编排 –编译或 GC 活动可能会在相同(且糟糕)的时间发生 15 © 2013 IBM Corporation 挑战:降低入门成本 我们需要解决以下问题 在应用程序之间隔离数据 控制资源独占 同时不能强迫人们更改其应用程序! 16 © 2013 IBM Corporation 数据隔离挑战:示例 1 ■ ■ 17 在应用程序的代码中嵌入 URL 模式等部署信息 稍等!如果我们在一个服务器上部署该 Sevlet 的两个副本会发生什么 情况? © 2013 IBM Corporation 数据隔离挑战:示例 2 ■ 静态变量是有害的(由于共享) ■ 大多数库都充斥着静态变量 稍等! What happens if each tenant needs a different default locale? 18 © 2013 IBM Corporation 通过类加载器隔离静态变量 ■ 通过常规类加载器技巧实现隔离 –每当您加载一个租户时,将其放入一个新的类加载器 –现在不再共享静态变量! 主租户 类 加载器 19 租户1 类 类 AA类 X 类 加载器 租户2 类 类 AA类 A 类 加载器 类 类 AA类 A © 2013 IBM Corporation 通过类加载器隔离静态变量 ■ 通过常规类加载器技巧实现隔离 –每当您加载一个租户时,将其放入一个新的类加载器 –现在不再共享静态变量! 主租户 类 加载器 租户1 类 类 AA类 X 租户2 类 类 AA类 A 类 加载器 ■ 类 加载器 类 类 AA类 A 大量重复! – 类数据 – 即时编译代码 – 重复的静态变量,其中大部分可能相同 20 © 2013 IBM Corporation 通过字节码重写隔离静态变量 ■ 让我们只关注静态变量 – 重写字节码! ■ 对每个静态变量使用一个数据结构 租户1 上下文 静态索引 <租户1 值> ■ 使用属性访问风格来获取静态变量 … 21 ■ 仍然容易出错:类加载规则、反射、JNI、其他字节码重写程序 ■ 好了,那么您需要开始将可共享(默认)的内容标记为隔离(新)的内容 © 2013 IBM Corporation 先例和相关工作 ■ Sun/Oracle MVM 和 JSR 121 — 应用程序隔离 API – 是一个多租户 JRE • 允许多个 Java 应用程序在相同 JVM 中运行 • 通过隔离所有静态字段而非使用不同的类加载器实现应用程序间的精细隔离 • 支持共享类字节码和元数据 ■ Google 应用引擎和 JSR 284 — 资源占用管理 API – 是一个多租户中间件服务 • 允许多个 Servlet 应用程序部署到引擎中(以及按需扩展至多个节点) • 显式地控制资源占用(CPU、带宽) • 通过白名单限制 Java SE API 访问 – 为托管应用程序提供基于“命名空间”的多租户编程模型 22 © 2013 IBM Corporation 多租户 JDK:易于隔离和控制 ■ ■ ■ 概念:Add a single argument (–Xmt for multi-tenant) to your Java command-line to opt into sharing a runtime with others. 结果:您的应用程序就好像在专用的 JVM 中运行,而实际上是与其他 应用程序一同运行。 优点:更小、更快且最终更智能 –减少重复:(1 GC、1 JIT),堆对象共享 –快速启动:启动应用程序时,JVM 已经运行并预热 23 © 2013 IBM Corporation 允许多个 Java 应用程序在一个 JVM 中运行 多租户 JDK:组件概述 在 Java API 中实例化“租户”: •管理租户的生命周期 •保持不同租户的“私有”属性。 •按租户实施资源占用策略。 •动态向租户附加/分离线程. 隔离不同租户的运行时状态: •@TenantScope 语义:类的静态字段 按租户存储。 实现 JSR284 兼容 API: • 节流使用者的资源占用 资源可以是 CPU 时间、I/O 带宽等 使用者可以是线程、租户、JVM 24 Tenant Programm ing Model Tenant Scope Field • 模拟 JSR121 隔离 •每个隔离的应用程序都“认为”自己拥有整个 VM •积极且透明地共享元数据: 方法的字节码 GC JIT MultiTena ncy JDK Resource Consumpti on Managem ent (RCM) © 2013 IBM Corporation 多租户 JDK:启动您的应用程序 ■ 25 Opt-in to multitenancy by adding –Xmt © 2013 IBM Corporation 多租户 JDK:注册 javad 后台进程 ■ JVM 将自动定位/启动后台进程 定位 javad 26 © 2013 IBM Corporation 多租户 JDK:创建一个新租户 ■ 在 javad 后台进程中创建新租户 租户1 javad 27 © 2013 IBM Corporation 多租户 JDK:创建第二个租户 ■ 在 javad 后台进程中创建新租户 租户1 租户2 javad javad 进程中存在 通用代码的一份副本。 28 大部分运行时结构 是共享的。 © 2013 IBM Corporation 解决数据隔离挑战 ■ 如果 JVM 了解租户并向每个租户提供不同的静态变量视图会怎样? ■ 来认识一下 @TenantScope 批注。 租户1 … LocaleSettings.setDefaultLocale( LocaleSettings.UK ); … 租户2 … LocaleSettings.setDefaultLocale( LocaleSettings.USA ); … ■ @TenantScope 语义:静态变量值按租户存储 – 借助 JIT 尝试限制一位数吞吐量间接产生的额外成本 29 ■ 每个租户拥有各自的 LocaleSettings.defaultLocale ■ 现在许多租户可以共享一个 LocaleSettings 类 © 2013 IBM Corporation … 让我们提供一些用于管理租户的 API:TenantContext.class ■ 可供中间件使用的基本租户操作(选择加入) –数据隔离 –资源管理(稍后详细介绍) ■ 中间件区分租户的能力 –哪一个引起了问题? ■ 查询租户的状态 –您有多少空闲内存? 创建和查询 数据隔离 资源管理 30 © 2013 IBM Corporation 多租户 JDK:实际共享但“感觉像是”专用的 JVM ■ 在类加载时自动添加 @TenantScope 标记 ■ 租户看到专用的中间件 — 但在幕后实际为共享的类(和 JIT 编译代码) 应用程序 更改 31 合并 © 2013 IBM Corporation 守望相助:应对不良行为 http://bit.ly/ficwkl 图片来自 http://www.rra.memberlodge.org/Neighbourhood-Watch-Reporting http://mcsholding.com/DetailsPage.aspx?Page_Id=42 32 © 2013 IBM Corporation 共享的环境需要资源控制 ■ 您与邻居的关系越紧密,控制能力就越强 ■ 多租户 JDK 可提供对以下资源的控制 –CPU 时间 –堆大小 –线程数量 –文件 IO:读取带宽、写入带宽 –套接字 IO:读取带宽、写入带宽 33 © 2013 IBM Corporation 资源控制工效学 ■ 针对新资源的单命令行开关 – -Xlimit:cpu=10-30 // 最低 CPU 10%,最高 30% – -Xlimit:cpu=30 // 最高 CPU 30% – -Xlimit:netIO=20M // 最高带宽 20 Mbps ■ 无成本映射现有选项 – -Xms8m –Xmx64m ■ // 初始 8M 堆,最高 64M 添加一些 JMX bean 以查看您对每种资源的使用量 – 即,通过包装在租户中,了解您的代码对资源的使用情况 34 © 2013 IBM Corporation JSR-284 资源占用管理 API ■ JSR 284 提供了一个可按“域”管理资源占用的标准化 API。 对于每种资源: 也作为 MBean 公开 资源属性 1 策略 1 N 资源使用者 资源域 1 N 约束 35 N 1 N 通知 © 2013 IBM Corporation JVM 与操作系统 CPU 限制 基准测试设置 时长 • 时长比较:Linux AMD64,运行一个 CPU 配额为 100% 的 10 线程 CPU 密集型应用程序,每个线程 执行相同的斐波纳契计算,对时长进行基准测试 • 准确性比较:Linux AMD64, run two CPU-intensive apps each doing the same Fibonacci calculation, but with different CPU quota:60% vs 30%, benchmark the accuracy 操作系统作为控制器 JVM 作为控制器 1 1362 秒 1267 秒 2 1167 秒 1239 秒 3 1452 秒 1390 秒 4 1094 秒 1122 秒 5 1139 秒 1123 秒 6 1244 秒 1134 秒 平均 1243 秒 1212 秒 准确性 cpu throttling in os controller 较短的时长相信是不 准确的限制所致 cpu throttling in jvm controller 80 90 70 80 60 70 60 cpu% 50 40 30 50 60% throttling 30% throttling 40 time 09:04 09:36 08:32 07:28 08:00 06:24 06:56 05:52 04:48 05:20 03:44 04:16 03:12 02:08 02:40 01:04 01:36 09:58 08:49 09:12 09:35 07:17 07:40 08:03 08:26 05:45 06:08 06:31 06:54 04:36 04:59 05:22 03:04 03:27 03:50 04:13 01:32 01:55 02:18 02:41 0 00:23 00:46 01:09 10 0 00:00 20 10 00:32 30 20 00:00 cpu% 轮次 time 结果:JVM 控制可实现与操作系统相当的性能,但准确性较低。 36 © 2013 IBM Corporation 按租户占用堆 IBM JDK 具有一种新的基于区域的 GC 技术,可良好地映射到租户 (详情请访问 http://ibm.co/JtWfXr) ■ 技术: ■ – 最初给予每个租户足够的 GC 区域,以满足其最低预留 – 在租户范围内运行的代码在其拥有的区域内分配对象 – 可申请新的区域,最多不超过租户的最高预留 租户1 1 1 租户2 1 1 2 2 堆(划分为区域) ■ 详细介绍: –终结需要在适当的租户上下文中运行 –我们必须能够轻松实现从对象 租户的映射 –GC 读/写屏障提供了一个控制租户间引用的机会 37 © 2013 IBM Corporation 风险和回报:我们能实现多高的密集性? 图片来自 http://www.colourbox.com/image/street-post-with-risk-st-and-reward-way-signs-image-1449085 http://www.economist.com/blogs/babbage/2011/11/facebook-and-privacy 38 © 2013 IBM Corporation 目前的状态:探索密集性的极限 ■ 我们仍在为之努力的目标: –扩大规模:目前运行 Liberty 规模的负载,接下来的挑战是扩展应用程序规模和 租户数量 –提高安全性:增强租户间的屏障,强健终结,提供针对“僵尸”租户的检测/纠正 措施 –配额实施:评估停滞和异常抛出选项 –性能:Measuring density, and improving throughput and some new concerns like:idle behavior, idle->busy responsiveness ■ 39 后续步骤 –我们需要您的反馈:我们前进的方向是否正确? –我们旨在通过 Java Community Process 实现标准化 © 2013 IBM Corporation 多租户:目前的性能 40 我们能实现多少节省? – 简单的 ('Hello World') 应用程序,每租户约为 170 KB 的堆大小 – 这相当于在相同硬件上多运行 5-6 倍的应用程序 – Java HelloWorld 启动时间从 375 ms 下降至 25 ms(16 倍) – 积极调优或许能进一步提高该数字 JRuby – 每个租户约 6 MB 的堆和 6 MB 大多为共享的代码 – 密集性改进约 3.8 倍:每 GB 内存 89 个实例 – 启动改进约 12 倍 Liberty 型负载接近 2.2 倍的密集性 – OSGi 类加载器层次结构对共享提出了更大的挑战 – 堆占据的空间 (64 MB) – Liberty 启动应用程序监视器的时间从 13 秒下降到 4 秒 – 吞吐量测量显示出约 15% 的损失,目标为正式发布时小于 10% 第二次运行启动时间显著改善 – 由于 JVM 已经启动并运行,因此启动速度提高了 – 如果我们能够将其降到足够低,就能够避免出现空闲服务器 应用程序平衡点 – 相对较大的类/堆比(JRuby 和其他 JVM 语言) – 需要快速启动:运行并成功 / 批量 – 100% 纯 Java 代码 © 2013 IBM Corporation 多租户:说明和限制 多租户模型的限制(针对正式发布版) JNI 原生库 – 操作系统仅允许共享的 JVM 进程加载共享库的一个副本。只能使用 JVM 的 bootclasspath 中存在的原生库 。 JVMTI – 由于调试和配置活动会影响共享 JVM 后台进程的所有租户,因此这些特性在多租户 JVM 进程模型中不受 支持。注意:我们提供按租户的 -javaagent:支持。 GUI 程序 – 多租户 JVM 进程模型中不支持 Standard Widget Toolkit (SWT) 等库,因为这些库在原生层会保持全局状态 。 41 Java 8 测试版 3 的限制 – 有限的平台覆盖 – 有限的租户数量,目前上限为 256 个租户(将在下个版本中修复) – 许多 RAS 特性展示了 JVM 级的视图(例如,javacore、堆转储等) – 在崩溃情况下,有限的后台进程->启动程序消息传递(将在下个版本中修复) © 2013 IBM Corporation 规划 ■ ■ 关注“零应用程序更改”的日期 – 借助租户感知中间件,我们能做得更好 用于提供隔离和限制的 API 可供体系产品使用 – JSR-284(资源管理) – JSR-121(隔离) – @TenantScope 字段 ■ Java 语言 (EE7) 和框架 (EclipseLink) 正在不断改进,以提供一流的多租户支持 ■ 我们已发布了多租户 JDK,包含于 IBM Java8 B3 ■ 请持续关注未来的进展:拭目以待 IBM Java 727 计划 42 © 2013 IBM Corporation 最后的思考:我应该如何处理现有的代码 性能调优:测量代码的性能并进行优化,以便尽可能减少 GC 花费的时 间和空闲状态占用的周期。 – 成为多租户环境中的“好邻居”,更好地利用现有硬件。 为过量使用做好准备:测量并了解忙碌/空闲时段,以便确切了解需要多 少资源,以及如何安排负载以错开活动“高峰”。 – 43 通过提高应用程序密集性改善利用率 © 2013 IBM Corporation 总结 通过消除所有不必要的部分简化软件体系,从而更好地利用硬件(以及运行软件 的人员)。 多租户能够提高我们的效率: –通过隔离换取空间和敏捷性 –JVM 支持提高了多租户安全性和简易性 –测量资源使用情况和负载模式至关重要 –多租户 JDK 基元为我们提供了未来发展空间 44 © 2013 IBM Corporation 目标回顾 本次讲座已经结束,您现在应该能够: – 理解什么是多租户以及这种模式的优点 • 每个租户的成本可以按一位数的 MB 来衡量 – 描述多租户 Java 部署面临的挑战 • 对于虚拟机技术人员很难,对您应该很容易 • 加载/部署随您编排 – 了解将现有应用程序转换为多租户部署的新 JDK 特性 • 我们前进的方向是否正确?这些特性对您的业务是否有所帮助? 45 © 2013 IBM Corporation 版权和商标 46 © 2013 IBM Corporation …是否还有任何问题? 47 © 2013 IBM Corporation