取消堆集以提高延迟并减少AWS账单

大多数性能问题可以通过几种不同的方式解决。 多数人都容易理解和应用许多适用的解决方案。 一些解决方案,例如从JVM管理的堆中删除某些数据结构,则更为复杂。 因此,如果您不熟悉此概念,我建议您继续学习我们最近如何减少应用程序的延迟,以及如何将Amazon AWS费用减少一半。

我将从解释需要解决方案的上下文开始。 如您所知, Plumbr密切关注每次用户交互。 这是使用部署在处理交互的应用程序节点旁边的代理来完成的。

这样做时,Plumbr代理正在从此类节点捕获不同的事件。 所有事件都发送到中央服务器,并组成我们称为事务的事务。 事务包含多个属性,包括:

  • 交易的开始和结束时间戳;
  • 执行交易的用户的身份;
  • 执行的操作(将项目添加到购物车,创建新发票等);
  • 该操作所属的应用程序;

在我们面临的特定问题的背景下,重要的是概述仅将对实际值的引用存储为事务的属性。 例如,不是存储用户的实际身份(例如电子邮件,用户名或社会保险号),而是在交易本身旁边存储对此类身份的引用。 因此,事务本身可能如下所示:

ID 开始 结束 应用 运作方式 用户
#1 12:03:40 12:05:25 #11 #222 #3333
#2 12:04:10 12:06:00 #11 #223 #3334

这些参考与对应的人类可读值对应。 通过这种方式,可以维护每个属性的键值映射,以便将ID为#3333和#3334的用户分别解析为John Smith和Jane Doe。

这些映射在运行时期间使用,当访问事务的查询将用人类可读的参考数据替换参考时:

ID 开始 结束 应用 运作方式 用户
#1 12:03:40 12:05:25 www.example.com /登录 约翰·史密斯
#2 12:04:10 12:06:00 www.example.com /购买 简·多伊

天真的解决方案

我敢打赌,我们的读者中的任何人都可以在不睁眼的情况下针对这种要求提出简单的解决方案。 选择一个喜欢的java.util.Map实现,将键值对加载到Map并在查询期间查找引用的值。

当我们发现我们选择的基础架构(具有存储在Kafka主题中的查找数据的Druid存储)已经通过Kafka查找开箱即用地支持此类Maps时,感觉容易的事情变得微不足道。

问题

幼稚的方法为我们服务了一段时间。 一段时间后,随着查找映射的大小增加,需要查找值的查询开始花费越来越多的时间。

我们在吃自己的狗粮并使用Plumbr监视Plumbr本身时注意到了这一点。 我们开始看到在Druid Historical节点上,GC暂停越来越频繁,而且更长,服务于查询并解决了查询。

显然,一些最有问题的查询必须从地图中查找超过100,000个不同的值。 这样做时,查询被GC启动打断,并超出了以前的100ms以下查询的持续时间,超过了10秒钟。

在寻找根本原因的同时,我们让Plumbr从此类有问题的节点公开了堆快照,确认长时间的GC暂停后大约70%的已用堆已被查找表完全消耗了。

同样明显的是,该问题还需要考虑另一个方面。 我们的存储层基于节点集群,集群中为查询提供服务的每台计算机都运行多个JVM进程,而每个进程都需要相同的参考数据。

现在,考虑到所讨论的JVM具有16G堆,并有效地复制了整个查找映射,因此这也成为容量规划中的一个问题。 支持越来越大的堆所需的实例大小开始在我们的EC2账单中付出了代价。

因此,我们不得不提出一种不同的解决方案,既减轻了垃圾收集的负担,又找到了降低Amazon AWS成本的方法。

解决方案:编年史地图

我们实施的解决方案基于Chronicle Map构建。 编年史地图在内存键值存储区中处于堆外状态。 正如我们的测试所示,存储的延迟时间也非常长。 但是,我们选择编年史地图的主要优点是它能够跨多个流程共享数据。 因此,除了将查找值加载到每个JVM堆之外,我们只能使用集群中不同节点访问的映射的一个副本:

在进入细节之前,让我为您提供编年史地图功能的高级概述,我们发现它特别有用。 在编年史地图中,数据可以保存到文件系统中,然后由任何并发进程以“查看”模式访问。

因此,我们的目标是创建一个具有“编写者”角色的微服务,这意味着它将将所有必需的数据实时地持久存储到文件系统中,并作为“读取器”的角色(即我们的Druid数据存储)。 由于Druid不支持现成的Chronicle Map,因此我们实现了自己的Druid扩展 ,该扩展能够读取已经保存的Chronicle数据文件,并在查询期间用人类可读的名称替换标识符。 以下代码提供了一个示例,说明如何初始化编年史地图:

ChronicleMap.of(String.class, String.class)
.averageValueSize(lookup.averageValueSize)
.averageKeySize(lookup.averageKeySize)
.entries(entrySize)
.createOrRecoverPersistedTo(chronicleDataFile);

在初始化阶段需要此配置,以确保Chronicle Map根据您预测的限制分配虚拟内存。 虚拟内存预分配不是唯一的优化,如果像我们一样将数据持久化到文件系统中,您会注意到创建的Chronicle数据文件实际上是稀疏文件 。 但这将是一个完全不同的帖子的故事,所以我不会深入探讨这些。

在配置中,您需要为尝试创建的编年史地图指定键和值类型。 在我们的例子中,所有参考数据都是文本格式,因此我们为键和值都指定了String类型。

在指定键和值的类型之后,Chronicle Map初始化还有更多有趣的部分是独特的。 正如方法名称所暗示的, averageValueSizeaverageKeySize都要求程序员指定期望存储在Chronicle Map实例中的平均键和值大小。

使用方法条目,您可以为Chronicle Map提供可以存储在实例中的预期数据总数。 也许有人会怀疑,如果随着时间的推移,记录数量超过预定义的大小会发生什么? 显然,如果超过了配置的限制,则在最后输入的查询上性能可能会下降。

当超出预定义的条目大小时,还要考虑的另一件事是,如果不更新条目大小,则无法从Chronicle Map文件中恢复数据。 由于Chronicle Map在初始化期间会预先计算数据文件所需的内存,因此,如果条目大小保持不变,并且实际上文件中包含的内容(比如说多4倍的条目),则数据将无法容纳到预计算的内存中,因此Chronicle Map初始化将失败。 如果要在重启后正常运行,请务必牢记这一点。 例如,在我们的场景中,当重新启动持久化来自Kafka主题的数据的微服务时,在初始化Chronicle Map实例之前,它会根据Kafka主题中的消息数量动态计算数量条目。 这使我们能够在任何给定时间重新启动微服务,并使用更新的配置恢复已持久保存的Chronicle Map文件。

带走

使Chronicle Map实例能够在微秒内读写数据的各种优化立即开始产生良好的效果。在发布基于Chronicle Map的数据查询后几天,我们已经看到了性能改进:

此外,从每个JVM堆中删除查找映射的冗余副本可以显着减少存储节点的实例大小,从而在我们的Amazon AWS账单中产生明显的凹痕。

翻译自: https://www.javacodegeeks.com/2017/02/going-off-heap-improve-latency-reduce-aws-bill.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/350088.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python 环境常用指令(updating...)

# 配置pip 源 mkdir -p ~/.pip && cat >> pip.conf <<EOF [global] timeout 60 index-url https://pypi.doubanio.com/simple EOF # pyenv 安装 所需依赖&#xff1a; yum install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel…

shell 删除了hdfs 文件,在HDFS上删除超过10天的文件

Is there a way to delete files older than 10 days on HDFS?In Linux I would use:find /path/to/directory/ -type f -mtime 10 -name *.txt -execdir rm -- {} \;Is there a way to do this on HDFS? (Deletion to be done based on file creation date)解决方案Solution…

mysql使用方法_Mysql的常用用法

一、mysql中limit的用法详解[数据分页常用]在我们使用查询语句的时候&#xff0c;经常要返回前几条或者中间某几行数据&#xff0c;这个时候怎么办呢&#xff1f;不用担心&#xff0c;mysql已经为我们提供了这样一个功能。SELECT * FROM table LIMIT [offset,] rows | rows OF…

MTK 移植泰文输入法

1.移植zi输入法 1.1 在文件..\make\XXX_GPRS.mak中 讲输入方式改为MMI_ZI XXX_LANGUAGE EN_SM_THAI INPUT_METHOD MMI_XI 1.2在MMI_feature.h 打开相应的ZI语言输入法的宏开关&#xff0c; #if defined(CFG_MMI_LANG_THAI) && ((CFG_MMI_LANG_THAI __ON__)||(CFG_MM…

java中无法推断类型参数_Java中的推断异常

java中无法推断类型参数借用和窃取其他语言的概念和想法总是很高兴的。 Scala的Option是我真正喜欢的一个主意&#xff0c;因此我用Java编写了一个实现。 它包装了一个可能为null或不为null的对象&#xff0c;并提供了一些可用于某种分类功能的方法。 例如&#xff0c;isDefine…

H3C 三种生成树协议特性的比较

转载于:https://www.cnblogs.com/fanweisheng/p/11153361.html

使用HazelCast进行休眠缓存:基本配置

以前&#xff0c;我们对JPA缓存&#xff0c;机制以及hibernate提供的内容进行了介绍 。 接下来是一个使用Hazelcast作为二级缓存的休眠项目。 为此&#xff0c;我们将在JPA中使用一个基本的spring boot项目。 Spring Boot使用休眠作为默认的JPA提供程序。 我们的设置将非常接…

mysql事务实战_mysql事务隔离级别详解和实战

A事务做了操作 没有提交 对B事务来说 就等于没做 获取的都是之前的数据但是 在A事务中查询的话 查到的都是操作之后的数据没有提交的数据只有自己看得到&#xff0c;并没有update到数据库。查看InnoDB存储引擎 系统级的隔离级别 和 会话级的隔离级别&#xff1a;mysql> sele…

微云 linux_编年史与微云

微云 linux总览 我面临的一个常见问题是&#xff1a; 如果是单个作者&#xff0c;多个读者&#xff0c;如何缩放基于Chronicle的系统。 尽管有解决此问题的方法&#xff0c;但很有可能根本不会有问题。 微云 这是我用来描述单个线程来完成当前由多个服务器完成的工作的术语。 …

H3C 计算子网内可用主机地址数

转载于:https://www.cnblogs.com/fanweisheng/p/11153665.html

mysql中两次排序_MySQL中的两种排序方式: index和filesort

index &#xff1a;通过有序索引顺序扫描直接返回有序数据&#xff0c;不需要额外的排序&#xff0c;操作效率较高。filesort&#xff1a;通过对返回数据进行排序&#xff0c;filesort 并不代表通过磁盘文件排序&#xff0c;而是说明进行了一个排序操作&#xff0c;至于排序操作…

Java命令行界面(第2部分):args4j

在上一篇文章中 &#xff0c;我研究了如何使用Apache Commons CLI在Java应用程序中解析命令行参数。 在本文中&#xff0c;我将使用另一个库args4j进行相同的操作。 args4j采用了一种不同于Commons CLI的方式来指定Java应用程序应期望的命令行参数。 尽管Commons CLI期望代表选…

mysql my.cnf在哪里_my.cnf配置文件在哪

my.cnf配置文件在linux上是位于路径“/etc/my.cnf”下&#xff0c;在window上则位于安装目录的根目录下&#xff1b;可以使用命令“mysql --help”查看关于MYSQL对应配置文件“my.cnf”搜索顺序。一般linux上都放在 /etc/my.cnf ,window 上安装都是默认可能按照上面的路径还是没…

深入学习Mybatis框架(二)- 进阶

1.动态SQL 1.1 什么是动态SQL&#xff1f; 动态SQL就是通过传入的参数不一样,可以组成不同结构的SQL语句。 这种可以根据参数的条件而改变SQL结构的SQL语句,我们称为动态SQL语句。使用动态SQL可以提高代码重用性。 1.2 XML方式的实现 1.2.1 需要使用到的标签 <if> 用于判…

近似线性依靠matlab_不要仅仅依靠单元测试

近似线性依靠matlab当您构建一个复杂的系统时&#xff0c;仅仅测试组件是不够的。 这很关键&#xff0c;但还不够。 想象一下一家汽车厂生产和进口最高质量的零件&#xff0c;但组装好汽车后再也没有启动发动机。 如果您的测试用例套件几乎不包含单元测试&#xff0c;那么您将永…

戏说 .NET GDI+系列学习教程(三、Graphics类的方法的总结)

转载于:https://www.cnblogs.com/WarBlog/p/11157395.html

从关系数据库到Elasticsearch的索引数据– 1

Elasticsearch提供强大的搜索功能&#xff0c;并支持数据的分片和复制。 因此&#xff0c;我们希望将数据库中可用的数据索引到Elasticsearch中。 有多种方法可以将数据索引到Elasticsearch中&#xff1a; 使用Logstash将源设置为DB&#xff0c;将接收器设置为Elasticsearch&…

mysql 求bit 某位为1_mysql按位的索引判断值是否为1

DELIMITER $$DROP FUNCTION IF EXISTS value_of_bit_index_is_true$$/*计算某个数字的某些索引的位的值是否都为1&#xff0c;索引类似1,2,3,4*/CREATE FUNCTION value_of_bit_index_is_true(number INT, idxies VARCHAR(50)) RETURNS INT(11)BEGIN/*将1,2,3,4,5,6这样的字符串…

python math.asin

import mathmath.asin(x) x : -1 到 1 之间的数值。如果 x 是大于 1&#xff0c;会产生一个错误。 #!/usr/bin/pythonimport math print "asin(0.64) : ", math.asin(0.64)print "asin(0) : ", math.asin(0)print "asin(-1) : ", math.asin(-1)p…

消息队列mysql redis那个好_Redis与RabbitMQ作为消息队列的比较

简要介绍RabbitMQRabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种&#xff0c;最初起源于金融系统&#xff0c;用于在分布式系统中存储转发消息&#xff0c;在易用性、扩展性、高可用性等方面表现不俗。消息中间件主要用于组件之间的解耦&#xff0c;消息的发送者无需…