云服务器内容精选

  • 单模型性能测试工具Mindspore lite benchmark 在模型精度对齐后,针对SD模型性能调优,可以通过AOE工具进行自助性能调优,进一步可以通过profiling工具对于性能瓶颈进行分析,并针对性的做一些调优操作。 可以直接使用benchmark命令测试mindir模型性能,用来对比调优前后性能是否有所提升。 # shell cd /home_host/work benchmark --modelFile=diffusers/scripts/mindir_models/text_encoder.mindir --device=Ascend 上述命令中:modelFile指定生成的mindir模型文件;device指定运行推理的设备。其他用法参考benchmark文档。 测试结果如下所示: 图1 测试结果 父主题: 性能调优
  • 算子二进制调优 PyTorch Adaptor框架提供与算子编译相关的二进制配置参数,可设置模型编译时是否优先在线编译,以此优化模型训练性能。在main函数训练逻辑开始前通过以下函数设置(True为启动优先在线编译、False为取消优先在线编译)。 torch_npu.npu.set_compile_mode(jit_compile=False) 对于固定shape场景和动态shape场景,是否优先在线编译对训练性能带来不同的效果: 固定shape场景:固定shape是指在模型计算过程中,模型的输入和输出的shape是固定的。如果优先在线编译,可根据当前获得的算子信息,进行融合和优化,在线编译出运行性能更优的算子。反之,则编译优化少,性能降低。 动态shape场景:动态shape是指在模型计算过程中,模型的输入和输出存在多种shape。如果对动态shape的算子优先编译,会导致编译时间长训练性能差。如果取消优先编译,会优先查找当前编译好的算子二进制配置文件,如果存在则不在线编译算子;如果不存在,再进行在线编译。此时虽然编译优化少,但是没有编译时间,模型训练性能大概率比配置为优先编译高。 总结: 如果模型中无动态shape,启动优先在线编译,可提高训练性能。 如果模型中只有动态shape(该情况较少),关闭优先在线编译,模型训练性能大概率会更高。 既有动态shape也有固定shape,启动优先在线编译对训练性能是否提升无法确定,因此可以在调整训练代码后,分别尝试开关优先在线编译后根据训练性能的优劣再设置。 Snt9B芯片默认关闭了优先在线编译,可通过以下命令获取当前模式。如果返回为False,代表已启动优先在线编译。 print(torch_npu.npu.is_jit_compile_false()) 算子会根据该开关走不同的代码逻辑,如出现jit_compile切换后,代码运行失败的情况,需要联系昇腾技术支持获取帮助。
  • 多进程绑核 相比于x86服务器,ARM服务器通常CPU核数更多,但单核性能更弱,因此更容易触发内核的负载均衡策略,该策略是通过启用进程迁移来降低繁忙的处理器压力。进程迁移会导致进程上下文切换、降低Cache命中率和跨numa内存访问等,从而影响训练性能。 如果使用docker容器作为训练环境,启动容器的时候,通过cpuset-cpus参数指定当前容器绑定的CPU核(如绑定16个cpu核60~75,命令示例为“docker run -d --cpuset-cpus=60-75 myimage bash”),这样容器中的进程只能在指定的CPU核上运行,达到绑核的效果。
  • NPU融合算子API和亲和优化器 可对训练代码中的部分API替换成NPU融合算子API和亲和优化器,从而提升训练性能。但需要注意的是,在一些场景下,替换后的算子可能会对模型精度有影响,所以适配后,需要验证精度,如果确认有影响,需要在精度和性能之间做取舍。 NPU融合算子API 识别融合算子和亲和优化器请参考工具使用,当前支持识别的融合算子API和亲和优化器请参考昇腾迁移融合算子API替换样例。 NPU亲和优化器替换 PyTorch原生优化器在训练过程中,一般需要下发多个NPU算子完成梯度和参数的更新计算,过多的算子下发,可能造成NPU空等。可将PyTorch优化器替换成NPU亲和优化器提高训练性能,详情请见此处。
  • 操作步骤 用于CarbonData查询的配置介绍,详情请参见表1和表2。 表1 Shuffle过程中,启动Task的个数 参数 spark.sql.shuffle.partitions 所属配置文件 spark-defaults.conf 适用于 数据查询 场景描述 Spark shuffle时启动的Task个数。 如何调优 一般建议将该参数值设置为执行器核数的1到2倍。例如,在聚合场景中,将task个数从200减少到32,有些查询的性能可提升2倍。 表2 设置用于CarbonData查询的Executor个数、CPU核数以及内存大小 参数 spark.executor.cores spark.executor.instances spark.executor.memory 所属配置文件 spark-defaults.conf 适用于 数据查询 场景描述 设置用于CarbonData查询的Executor个数、CPU核数以及内存大小。 如何调优 在银行方案中,为每个执行器提供4个CPU内核和15GB内存,可以获得良好的性能。这2个值并不意味着越多越好,在资源有限的情况下,需要正确配置。例如,在银行方案中,每个节点有足够的32个CPU核,而只有64GB的内存,这个内存是不够的。例如,当每个执行器有4个内核和12GB内存,有时在查询期间发生垃圾收集(GC),会导致查询时间从3秒增加到超过15秒。在这种情况下需要增加内存或减少CPU内核。 用于CarbonData数据加载的配置参数,详情请参见表3、表4和表5。 表3 设置数据加载使用的CPU core数量 参数 carbon.number.of.cores.while.loading 所属配置文件 carbon.properties 适用于 数据加载 场景描述 数据加载过程中,设置处理数据使用的CPU core数量。 如何调优 如果有更多的CPU个数,那么可以增加CPU值来提高性能。例如,将该参数值从2增加到4,那么CSV文件读取性能可以增加大约1倍。 表4 是否使用YARN本地目录进行多磁盘数据加载 参数 carbon.use.local.dir 所属配置文件 carbon.properties 适用于 数据加载 场景描述 是否使用YARN本地目录进行多磁盘数据加载。 如何调优 如果将该参数值设置为“true”,CarbonData将使用YARN本地目录进行多表加载磁盘负载平衡,以提高数据加载性能。 表5 加载时是否使用多路径 参数 carbon.use.multiple.temp.dir 所属配置文件 carbon.properties 适用于 数据加载 场景描述 是否使用多个临时目录存储sort临时文件。 如何调优 设置为true,则数据加载时使用多个临时目录存储sort临时文件。此配置能提高数据加载性能并避免磁盘单点故障。 用于CarbonData数据加载和数据查询的配置参数,详情请参见表6。 表6 设置数据加载和查询使用的CPU core数量 参数 carbon.compaction.level.threshold 所属配置文件 carbon.properties 适用于 数据加载和查询 场景描述 对于minor压缩,在阶段1中要合并的segment数量和在阶段2中要合并的已压缩的segment数量。 如何调优 每次CarbonData加载创建一个segment,如果每次加载的数据量较小,将在一段时间内生成许多小文件,影响查询性能。配置该参数将小的segment合并为一个大的segment,然后对数据进行排序,可提高查询性能。 压缩的策略根据实际的数据大小和可用资源决定。如某银行1天加载一次数据,且加载数据选择在晚上无查询时进行,有足够的资源,压缩策略可选择为6、5。 表7 使用索引缓存服务器时是否开启数据预加载 参数 carbon.indexserver.enable.prepriming 所属配置文件 carbon.properties 适用于 数据加载 场景描述 使用索引缓存服务器过程中开启数据预加载可以提升首次查询的性能。 如何调优 用户可以将该参数设置为true来开启预加载。默认情况,该参数为false。
  • 操作场景 本章节根据超过50个测试用例总结得出建议,帮助用户创建拥有更高查询性能的CarbonData表。 表1 CarbonData表中的列 Column name Data type Cardinality Attribution msname String 3千万 dimension BEGIN_TIME bigint 1万 dimension host String 1百万 dimension dime_1 String 1千 dimension dime_2 String 500 dimension dime_3 String 800 dimension counter_1 numeric(20,0) NA measure ... ... NA measure counter_100 numeric(20,0) NA measure
  • 操作场景 Spark支持两种方式的序列化 : Java原生序列化JavaSerializer Kryo序列化KryoSerializer 序列化对于Spark应用的性能来说,具有很大的影响。在特定的数据格式的情况下,KryoSerializer的性能可以达到JavaSerializer的10倍以上,而对于一些Int之类的基本类型数据,性能的提升就几乎可以忽略。 KryoSerializer依赖Twitter的Chill库来实现,相对于JavaSerializer,主要的问题在于不是所有的Java Serializable对象都能支持,兼容性不好,所以需要手动注册类。 序列化功能用在两个地方:序列化任务和序列化数据。Spark任务序列化只支持JavaSerializer,数据序列化支持JavaSerializer和KryoSerializer。
  • 操作步骤 Spark程序运行时,在shuffle和RDD Cache等过程中,会有大量的数据需要序列化,默认使用JavaSerializer,通过配置让KryoSerializer作为数据序列化器来提升序列化性能。 在开发应用程序时,添加如下代码来使用KryoSerializer作为数据序列化器。 实现类注册器并手动注册类。 package com.etl.common; import com.esotericsoftware.kryo.Kryo; import org.apache.spark.serializer.KryoRegistrator; public class DemoRegistrator implements KryoRegistrator { @Override public void registerClasses(Kryo kryo) { //以下为示例类,请注册自定义的类 kryo.register(AggrateKey.class); kryo.register(AggrateValue.class); } } 您可以在Spark客户端对spark.kryo.registrationRequired参数进行配置,设置是否需要Kryo注册序列化。 当参数设置为true时,如果工程中存在未被序列化的类,则会发生异常。如果设置为false(默认值),Kryo会自动将未注册的类名写到对应的对象中。此操作会对系统性能造成影响。设置为true时,用户需手动注册类,针对未序列化的类,系统不会自动写入类名,而是发生异常,相对比false,其性能较好。 配置KryoSerializer作为数据序列化器和类注册器。 val conf = new SparkConf() conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer") .set("spark.kryo.registrator", "com.etl.common.DemoRegistrator")
  • 操作场景 将datasource表的分区消息存储到Metastore中,并在Metastore中对分区消息进行处理。 优化datasource表,支持对表中分区执行增加、删除和修改等语法,从而增加与Hive的兼容性。 支持在查询语句中,把分区裁剪并下压到Metastore上,从而过滤掉不匹配的分区。 示例如下: select count(*) from table where partCol=1; //partCol列为分区列 此时,在物理计划中执行TableScan操作时,只处理分区(partCol=1)对应的数据。
  • 操作步骤 要启动Datasource表优化,在Spark客户端的“spark-defaults.conf”配置文件中进行设置。 表1 参数介绍 参数 描述 默认值 spark.sql.hive.manageFilesourcePartitions 是否启用Metastore分区管理(包括数据源表和转换的Hive表)。 true:启用Metastore分区管理,即数据源表存储分区在Hive中,并在查询语句中使用Metastore修剪分区。 false:不启用Metastore分区管理。 true spark.sql.hive.metastorePartitionPruning 是否支持将predicate下压到Hive Metastore中。 true:支持,目前仅支持Hive表的predicate下压。 false:不支持 true spark.sql.hive.filesourcePartitionFileCacheSize 启用内存中分区文件元数据的缓存大小。 所有表共享一个可以使用指定的num字节进行文件元数据的缓存。 只有当“spark.sql.hive.manageFilesourcePartitions”配置为“true”时,该配置项才会生效。 250 * 1024 * 1024 spark.sql.hive.convertMetastoreOrc 设置ORC表的处理方式: false:Spark SQL使用Hive SerDe处理ORC表。 true:Spark SQL使用Spark内置的机制处理ORC表。 true
  • 操作场景 对于Spark应用来说,资源是影响Spark应用执行效率的一个重要因素。当一个长期运行的服务(比如JDBCServer),如果分配给它多个Executor,可是却没有任何任务分配给它,而此时有其他的应用却资源紧张,这就造成了很大的资源浪费和资源不合理的调度。 动态资源调度就是为了解决这种场景,根据当前应用任务的负载情况,实时的增减Executor个数,从而实现动态分配资源,使整个Spark系统更加健康。
  • 参考信息 被广播的表执行超时,导致任务结束。 默认情况下,BroadCastJoin只允许被广播的表计算5分钟,超过5分钟该任务会出现超时异常,而这个时候被广播的表的broadcast任务依然在执行,造成资源浪费。 这种情况下,有两种方式处理: 调整“spark.sql.broadcastTimeout”的数值,加大超时的时间限制。 降低“spark.sql.autoBroadcastJoinThreshold”的数值,不使用BroadCastJoin的优化。
  • RDS for MySQL数据库内存使用率过高怎么处理 对于用户核心业务相关的库 请扩容实例规格,具体请参见变更实例的CPU内存规格。 对于非用户核心业务相关的库 查看本地计算机的内存使用率,如果使用率曲线持续平缓,则无需处理。 对于用户核心业务相关但是数据库规格配置很高的库 在业务低峰期,将数据库参数“performance_schema”的值调整为“OFF”,对于RDS for MySQL 5.6及以下版本,需要重启数据库才能生效。 通过智能DBA助手查看实例的内存使用情况,具体请参见查看性能指标。 如果实例的内存使用率仍持续保持较高: 请扩容实例规格。 调整数据库参数“innodb_buffer_pool_size”的值。参数建议值见表1,实际可修改的取值范围以RDS界面为准。 表1 不同内存规格对应的参数建议值 内存(GB) 5.6建议值 5.7建议值 8.0建议值 2 536,870,912 Byte(512 MB) 536,870,912 Byte(512 MB) 536,870,912 Byte(512 MB) 4 1,073,741,824 Byte(1 GB) 1,073,741,824 Byte(1 GB) 1,073,741,824 Byte(1 GB) 8 4,294,967,296 Byte(4 GB) 4,294,967,296 Byte(4 GB) 5,368,709,120 Byte(5 GB) 16 8,589,934,592 Byte(8 GB) 8,589,934,592 Byte(8 GB) 9,663,676,416 Byte(9 GB) 32 22,548,578,304 Byte(21 GB) 22,548,578,304 Byte(21 GB) 21,474,836,480 Byte(20 GB) 64 47,244,640,256 Byte(44 GB) 47,244,640,256 Byte(44 GB) 47,244,640,256 Byte(44 GB) 128 96,636,764,160 Byte(90 GB) 94,489,280,512 Byte(88 GB) 94,489,280,512 Byte(88 GB) 192 146,028,888,064 Byte(136 GB) 146,028,888,064 Byte(136 GB) 146,028,888,064 Byte(136 GB) 256 193,273,528,320 Byte(180 GB) 193,273,528,320 Byte(180 GB) 193,273,528,320 Byte(180 GB) 384 298,500,227,072 Byte(278 GB) 300,647,710,720 Byte(280 GB) 300,647,710,720 Byte(280 GB) 512 412,316,860,416 Byte(384 GB) 412,316,860,416 Byte(384 GB) 412,316,860,416 Byte(384 GB) 768 618,475,290,624 Byte(576 GB) 618,475,290,624 Byte(576 GB) 618,475,290,624 Byte(576 GB) 1024 824,633,720,832 Byte(768 GB) 824,633,720,832 Byte(768 GB) 824,633,720,832 Byte(768 GB) 请根据业务实际情况,调整参数“innodb_buffer_pool_size”的值。 MySQL本身具有内存动态平衡机制,90%以下您可无需关注。 RDS for MySQL的内存分配可划分为Engine层与Server层。 Engine层的内存包括InnoDB Buffer Pool、Log Buffer、Full Text Index Cache,其中InnoDB Buffer Pool为常驻内存,占用内存较大。 InnoDB缓冲池是一个内存区域,用于保存InnoDB表、索引和其他辅助缓冲区的缓存数据,可以通过参数“innodb_buffer_pool_size”定义缓冲池大小。 Server层的内存占用较高的包括Thread Cache、BinLog Cache、Sort Buffer、Read Buffer、Join Buffer等线程缓存,这类缓存非常驻内存,往往会随着连接关闭而释放。 以上内存的分配导致RDS for MySQL实例运行时内存使用率在80%左右。 父主题: 性能调优
  • 吞吐量大场景下使用MiniBatch聚合增加吞吐量 MiniBatch聚合的核心思想是将一组输入的数据缓存在聚合算子内部的缓冲区中。当输入的数据被触发处理时,每个key只需一个操作即可访问状态,可以很大程度减少状态开销并获得更好的吞吐量。但是可能会增加一些延迟,因为它会缓冲一些记录而不是立即处理,这是吞吐量和延迟之间的权衡。默认未开启该功能。 API方式: // instantiate table environmentTableEnvironment tEnv = ... // access flink configuration Configuration configuration = tEnv.getConfig().getConfiguration(); // set low-level key-value options configuration.setString("table.exec.mini-batch.enabled", "true"); // enable mini-batch optimizationconfiguration.setString("table.exec.mini-batch.allow-latency", "5 s"); // use 5 seconds to buffer input recordsconfiguration.setString("table.exec.mini-batch.size", "5000"); // the maximum number of records can be buffered by each aggregate operator task 资源文件方式(flink-conf.yaml): table.exec.mini-batch.enabled: true table.exec.mini-batch.allow-latency : 5 s table.exec.mini-batch.size: 5000
  • 通过表级TTL进行状态后端优化 本章节适用于MRS 3.3.0及以后版本。 在Flink双流Join场景下,若Join的左表和右表其中一个表数据变化快,需要较短时间的过期时间,而另一个表数据变化较慢,需要较长时间的过期时间。目前Flink只有表级别的TTL(Time To Live:生存时间),为了保证Join的准确性,需要将表级别的TTL设置为较长时间的过期时间,此时状态后端中保存了大量的已经过期的数据,给状态后端造成了较大的压力。为了减少状态后端的压力,可以单独为左表和右表设置不同的过期时间。不支持where子句。 可通过使用Hint方式单独为左表和右表设置不同的过期时间,如左表(state.ttl.left)设置TTL为60秒,右表(state.ttl.right)设置TTL为120秒: Hint方式格式: table_path /*+ OPTIONS(key=val [, key=val]*) */ key: stringLiteral val: stringLiteral 在SQL语句中配置示例: CREATE TABLE user_info (`user_id` VARCHAR, `user_name` VARCHAR) WITH ( 'connector' = 'kafka', 'topic' = 'user_info_001', 'properties.bootstrap.servers' = '192.168.64.138:21005', 'properties.group.id' = 'testGroup', 'scan.startup.mode' = 'latest-offset', 'value.format' = 'csv' ); CREATE table print( `user_id` VARCHAR, `user_name` VARCHAR, `score` INT ) WITH ('connector' = 'print'); CREATE TABLE user_score (user_id VARCHAR, score INT) WITH ( 'connector' = 'kafka', 'topic' = 'user_score_001', 'properties.bootstrap.servers' = '192.168.64.138:21005', 'properties.group.id' = 'testGroup', 'scan.startup.mode' = 'latest-offset', 'value.format' = 'csv' ); INSERT INTO print SELECT t.user_id, t.user_name, d.score FROM user_info as t LEFT JOIN -- 为左表和右表设置不同的TTL时间 /*+ OPTIONS('state.ttl.left'='60S', 'state.ttl.right'='120S') */ user_score as d ON t.user_id = d.user_id;