FME性能调整
原文地址:
https://knowledge.safe.com/content/kbentry/579/performance-tuning-fme.html
要素缓存(或在FME2017及以下版本中使用“全部检查运行”—Run with Full Inspection)允许你存储转换的中间结果并进行检查。这有助于开发和调试你的工作空间。但是在写入缓存时,它会消耗磁盘空间和资源。当允许生产环境中的工作空间时,确保关闭要素缓存。在FME Server中运行工作空间时,要素缓存将自动关闭。
在FME 2015及以上版本,你可以看到动态要素计数。这通常可以提示哪个转换器正在阻塞你的数据。你也可以使用Run with Full Inspection(全部检查运行),将在工作空间的每个链接上显示要素计数和缓存数据。这对于调试工作空间很有用,但是在测试性能时不应使用,因为创建缓存文件会产生开销。
在调整工作空间之前,了解如何读取FME日志文件至关重要。如果没有这方面的知识,用户往往会对转换产生错误的结论,并在错误的地方寻找性能问题。
当尝试对转换加速时,检查日志文件以确定花费时间的确切位置总是有益的。
提示 #1:检查 Tools > FME Options > Translation > Log timestamp information被勾选,这样日志中将显示时间。保存在磁盘中的日志文件通常具有时间信息,但是该选项将在日志窗口中显示时间。
日志文件中首先应注意的是FME处理的时间(精确到秒)——它可能与处理总时间长度不一致。例如,此处经过的时间显示该过程花费了6分钟,但是Total字段中报告FME只用了25秒。
Elapsed Time | Total| Incremental CPU (secs)
2006-07-10 14:43:06| 8.5| 0.0|
2006-07-10 14:43:13| 8.8| 0.3|
2006-07-10 14:46:29| 18.0| 9.1|
2006-07-10 14:49:29| 25.8| 7.9|
提示 #2: 参考FME日志如何记录处理时间了解更多关于为什么记录的FME处理时间不是全部时间,以及为什么重要等内容。
由于FME的工作原理是通过工作空间推送要素(而不是一个组——参考FME如何处理要素及如何影响转换过程了解更多信息),不可能提供每个转换器精确的处理时间。因此很多时间不会单独被记录,而是在下一个支持计时的功能处集中在一起。
日志文件中最重要的一项是临时目录。你会看到报告是这样的(为了清晰起见,删除了时间)...
INFORM|FME Configuration: Temporary directory is `C:\DOCUME~1\xxxx\LOCALS~1\Temp'
你还会看到关于该目录中可用磁盘空间的注释...
INFORM|System Status: 37700MB of disk space available in the FME temporary directory
当FME运行大型转换时,通常需要大量临时磁盘空间。在使用多个写模块或扇出时尤其如此。因此可用磁盘空间数量非常重要。但是在性能问题上,我们更关心这些磁盘活动的速度。
提示 #3: 尽可能将临时目录设置为你可用的最快磁盘。参考设置临时目录关于如何使用FME_TEMP设置其他的临时目录。
提示 #3a: 如果可能,对你的临时目录使用 SSD (固态硬盘) 磁盘。它们将非常快速,使用它们将对FME文件缓存性能产生重大影响。
提示 #3b: 如果可能,不要将你的临时目录设置为操作系统使用的磁盘;操作系统同时写入同一磁盘可能会降低FME的速度。
提示 #3c: 如果可能将临时目录指向具有较大可用空间的磁盘——这样不会提高速度但是可以防止大型转换由于磁盘空间不足而转换失败。.
提示 #3d:作为最后的手段尝试以前的备用品 - RAM驱动器(也称为RAM磁盘)! 将FME临时目录指向RAM驱动器,或将源数据的副本放在RAM驱动器上,与使用SSD具有相同的好处。
即使在SSD计算机上,使用RAM驱动器的工作空间完成时间(在某些情况下为4小时至2小时)也可以有100%的改进。特别的,当在转换中需要多次读取文件时,它非常有用。在Microstation Geographics情况下,Access文件被读取了上百次。这最终成了一个真正的瓶颈。因此,通过将该输入文件放在RAM驱动器上,它可以在转换开始之前有效地将数据输入缓存在RAM中。这对于具有高磁盘I / O的各种格式(例如XML / GML或基于文件的数据库(Esri文件地理数据库)等)非常有用。RAM驱动器可在Windows和Linux上使用。
下面是日志文件中与读取数据相关的部分。前面我们提到过FME的工作原理是在工作空间推送单个要素?一旦从源数据中读取,它就开始处理每个要素。它不是读取所有要素后才开始处理。因此通过查看日志文件并计算读取数据的时间是很困难的,因为工作空间处理时间将与其混为一谈。参考这个例子,此处的'Emptying factory pipeline'标记了数据全部读取完成的节点。
2006-02-03 11:37:47| 342.7| 0.5|INFORM|Emptying factory pipeline
这里花费了342.7秒(约6分钟)读取源数据。但是,如你现在知道的,这里包含了工作空间中处理要素的时间。当删除工作空间中的所有转换器后,我们得到……
2006-02-03 14:44:43| 66.5| 0.3|INFORM|Emptying factory pipeline
哇哦!只花费了1分钟。这告诉我们80%的时间用于处理数据,只有20%的时间用于读取。这种情况下用户刚开始会认为瓶颈在于数据读取,但是这个例子显示瓶颈在于转换。因此他应该检查他的工作空间,确保高效,并删除不必要的转换器。
提示 #4: 如果你担心工作空间读取数据的性能,将Workbench中的读模块与转换器断开连接,并再次运行转换。然后比较日志文件。你认为读取数据花费的时间实际是工作空间转换的时间,这将显示性能效果集中在哪里。
数据库是许多数据集的重要组成部分,日志文件将帮助我们确定数据库性能有多好,以及FME与数据库交互的程度。上面提示2中的链接提供了在Oracle数据库上执行预取查询相关的一个很好的例子……
2004-05-14 17:18:52| 476.1| 0.0|INFORM|Started SQL cache prefetch
2004-05-14 17:25:10| 476.2| 0.1|INFORM|Finished SQL cache
注意左边实际时间的差异;你可以看到我们发出SQL预取直到完成的时间大概是7分钟。但是,FME日志仅记录0.1秒的CPU时间。由此我们可以说,剩下的时间用于Oracle 查询检索数据。为了缩短时间,用户需要了解Oracle 数据库的结构以及查询的编写方式。也许是查询的字段没有建立索引?也可能是提供的查询效率不高?
提示 #5a: 仔细检查日志,找到在FME之外与数据库花费的时间有多少,然后看看是否需要改进你的数据库性能。说到索引(索引?),表是否有索引的问题,将对写入数据的性能产生很大影响。
写入到未建立索引的表很快,因为数据库没有任何开销工作要做。
将数据写入到有索引的表将花费很长时间,因为每提交一行,数据库需要立即对数据建立索引。
如上所示,报告的CPU时间不会改变,因为索引建立的工作是数据库服务器完成,而不是FME。
提示 #5b: 如果可能,在批量加载到表中之前删除索引,加载完成后再重新创建。它通常比在数据加载期间保留索引更快。
与此相关的是截断表(truncating table)和删除表(drop table)之间的区别。FME有设置可以进行这两个操作,但是当你截断表时,索引仍然存在,后续数据加载速度较慢。当你首先删除表,副作用是所有的索引也被删除,因此可以更快的写入数据,因为没有索引。
提示 #5c: 为了批量数据加载时得到更好的性能,考虑使用删除表的选项而不是截断。在提示5a的示例中,你可以看到缓存的预取。Joiner转换器使用缓存。Joiner将记录与图形要素相匹配。当FME读取匹配的数据库记录时,它将把它保存在缓存中。对后续要素,在FME检查数据库之前会检查此缓存是否匹配。优势在于与多个要素匹配的数据库记录将不会导致FME每次执行数据库读取,因为信息已经保存在内存中(缓存)。这使得连接更快并导致更少的网络流量。这里是一个很好的例子……@Relate: 表 `JOINER:MY_TABLE'的数据库查询统计: 进行了7次查询,其中0次顺序重复,1个为3个记录的记录缓存(14%总缓存命中)。
首先这里没有明确说匹配了多少条记录,但是我们可以很好的猜测是4个。3个要素匹配记录,所有记录具有不同的ID,FME将这些记录添加到缓存。第四个匹配要素不用进行数据库查询,因为它与缓存中的一条记录匹配。顺便提一下,这就是14%的来历。一共有7个查询,其中一个匹配了缓存记录(1/7 = 14%)。因此FME自动将此查询的网络流量减少了14%。顺便说一下,顺序重复部分显示多少个要素具有相同的密钥ID。例如……@Relate:表`JOINER:MY_TABLE'的数据库查询统计:7次查询,其中3次顺序重复,2次命中记录缓存的2个记录(71%总缓存命中)。这里有2个命中缓存,还有3个重复的要素。重复要素不需要数据库查询,只要它们是顺序的,所以2(缓存命中)+3(重复)=5且5/7=71%。因此缓存影响性能,但是用户可以做些什么来帮助?有两个设置可以在Joiner中使用。
第一个设置是缓存大小。通常只缓存一部分记录。缓存大小设置指定了子集具有多少条记录。一旦缓存填满,只有删除已有的记录才能添加新的记录。因此,数字越大,记录在内存中的记录越多,数据库读取的次数就越少。
显然,设置的大小取决于你有多少条记录,单个记录匹配的频率以及你的系统具有多少内存。在某个时刻,如果缓存记录太多则导致系统内存溢出,那么读取数据库会更有效。
提示 #5d: 使用Joiner转换器设置与数据集大小匹配的缓存大小以及可能在缓存中进行的匹配数量。
第二个缓存相关的设置是预取。不是在匹配时用记录填充到缓存,而是根据用户发出的预取查询,预先加载缓存(例如,在匹配之前用特定的一组数据进行填充)。预取查询可以选择最可能与要素属性匹配的整个表或者表的一部分。
例如,一些类型(type)为’roads’的FME要素需要数据库匹配。数据库表(myrecords)的字段(record_type)有系列值;roads, highways, avenues, streets。FME要素只会与record_type = roads进行批评,因此如果发出如下的预取,整个连接过程会更有效:
select * from myrecords where record_type = 'roads'
提示 #5e: 如果Joiner转换器只与表中已知子集匹配,在匹配之前预取子集记录则会更高效。
提示 #5f: 增加事务间隔。
你可以通过延长提交事务之间的间隔来加速所有写模块的转换。事务提交是一个“昂贵”的操作,因此推荐你把事务间隔尽可能设置大。在Safe Software进行的速度测试中,将事务间隔从500更改到1000,指定的转换快了2.5%。将事务间隔更改为5000,相同的转换快了5.5%。关闭事务,转换速度提高了12%或19%。更改事务间隔或关闭事务的性能优化在各个数据集间不同。
NB: 如果需要的记录不在预取中也没关系——FME将直接从数据库中进行取出。此外,当预取不够详尽时,缓存大小仅与预取一起使用,例如有一个where语句。因此把'select * from mytable' 作为预取将导致缓存大小被忽略,因为整个记录已经完全存在于FME中。但是'select * from mytable where type=mytype' 将使用缓存,因为预取查询没有获取整个记录集合。
你可以运行FME工作空间的配置文件,以获取每个底层工厂和函数耗费时间的详细日志。使用Tools -> Edit Header添加指令:FME_PROFILE_RESULT_CSV i.e. FME_PROFILE_RESULT_CSV C:\TEMP\profile.csv
注意:在生产环境工作空间中,不要忘记删除配置指令,它对性能有影响!
有时值得使用性能监测工具(例如PerfMon)来记录过程的CPU和内存使用情况。
默认情况,Windows限制了单个进程的内存可用为2GB。FME是单进程线程,因此受到这个限制的影响。当它超过可用内存时,系统将崩溃或FME需要将要素缓存到磁盘,这将对性能有不利影响。
2GB对当前的数据集来说并不大 。但是,你可用通过设置操作开关将可用内存提高到3GB。参考使用3GB开关了解如何进行。显然,你需要安装一台至少3GB RAM的计算机才能使此设置产生任何影响。
你也可以在64位工作站上运行32位FME,可以访问4GB RAM。
你可能也考虑把64位FME运行在64位处理器。在64位FME中,对支持的格式有一些限制。此外,为了实现64位程序的好处,建议你将通常拥有的RAM增加一倍,例如最小8G RAM。
提示 #6: 使用 /3GB开关增加可用内存,将使大型转换更快,并允许一些以前由于缺乏内存而导致的失败。
记得我们说过FME每次推送一个要素到工作空间中?情况并非总是如此。当Workbench中的一些转换每次处理一个要素(基于要素),其他需要对要素组进行操作(参考关于基于组的转换器)。基于组的转换器同时处理多个要素,例如,多个线要素相交以产生拓扑网络。
显然,任何一个基于组的转换器必须在一个时刻将它们全部存储在内存中进行操作。,
因此一个问题是,如果你的工作空间中将有多个基于组的转换器串在一起,尤其它们属于不同的数据流(并行连接)时,你可能一次存储了多个数据副本。因此,您正在耗尽重要的系统资源并可能减慢转换速度,因为它最终会将数据缓存到磁盘。
提示 #7a: 显然如果你需要转换器的特定排列且必须使用该排列时,要注意多个基于组的转换器将很快耗尽内存,并尽可能避免这种情况。
提示 #7b: 坐下,方式,观看FME以最大化性能的方式处理内存!
提示 #7c: 一些基于组的转换器具有features first选项。例如,PointOnAreaOverlay具有一个Areas First选项。FeatureMerger有一个Suppliers first。Clipper有Clippers First。如果你可以对你的要素正确排序,使用这些选项将减少阻塞和内存使用。
六、你的属性真的是必要的吗?
在转换中——如我们多次注意到的——FME将保存数据在内存中或缓存到磁盘。显然,数据集越小使用的内存越少,性能越好,这其中也包括了属性的数量。
一个特殊的问题是将空间数据作为属性携带。空间数据库格式——如Oracle或GeoMedia——通常把几何存储在数据库的字段中;例如GEOM。当FME读取数据时,它把GEOM字段转换为FME样式的几何体,并从数据中删除这个字段。
但是,通常可以将几何存储在多个字段中。有时你希望创建备份副本,有时原始应用程序会位自己的目的创建副本。FME将只转换一个字段为几何体,保留其他的作为属性。非常大且复杂的属性,占用大量的系统资源。
我们协助的一个用户就有这样的问题。他的GIS中的压缩功能,不是简单的压缩原始几何字段,而是创建一个新的字段。当FME读取数据时,它使用压缩字段作为几何,但是同时也读取原始未压缩的数据作为一个普通的属性。这是速度减慢的主要因素,但是通过在转换开始使用AttributeRemover转换器,可以在被基于组的转换器读取前删除多余几何列,转换性能大大增加。
另外一种需要注意的属性是列表。列表可以保存很多很多属性,这对资源来说是一个很大的消耗。例如,使用Joiner将要素连接到1000条记录,然后你得到一个包含1000组记录的列表。这已经够糟糕了,但是如果你将列表炸散并保留所有原始属性,你将得到1000个要素,每个要素具有1000套属性!
提示 #8: 在转换中只携带你希望在输出中可用的几何和属性。在转换过程中尽早删除任何多余的项。
七、让数据库完成工作!
只要可能的情况下让数据库完成工作。FME Oracle和其他数据库读模块支持全部SQL语句和SQL WHERE语句。如果可能,使用SQL连接数据而不是FeatureMerger转换器。创建数据库视图获取更好的性能以简化你的工作空间(虽然有时数据库管理员不允许你这样做)。
对于ArcSDE,SQL语句只支持非空间表。对于空间表使用:sdetable -o create_view 创建包含空间字段的视图用于连接。
ArcSDE帮助提供了如何执行此操作的说明,参考ArcGIS 帮助——快速浏览geodatabase的视图:
http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/A_quick_tour_of_views_in_the_geodatabase/002n000000t0000000/
你可用使用sdetable -o create_view和SQL ALTER VIEW的组合创建复杂的表连接。
提示 #9: 在某些情况下,FME可通过将处理交给数据库来提高性能。
八、写模块顺序:最大化的隐藏性能改进
当你在工作空间中有多个写模块时,第一个写模块的数据可以直接写入,随后的写模块将他们的数据存入缓存中等待写入。这本身有助于性能,也使得导航页面中的第一个写模块(你可通过右键>move up控制顺序)比其他更高效。高级工作空间参数:Order Writers By(写模块顺序),允许你设置工作空间中的要素写入写模块的顺序。
注意: Order Writers By参数自FME 2016起可用。
提示 #10a: 当你在工作空间中有多个写模块时,通常确保具有最大数据的写模块第一个写入。示例?该问答告诉你需要知道的内容。
提示 #10b: 为了达到最佳性能,RasterTiler和WebMapTiler输出的瓦片应按照从这些转换器输出的顺序写出。在这里不要使用数据集扇出,它将对输出重新排序并且会对性能产生负面影响。
九、数学计算:使用TCL进行提速
有时把复杂的数据表达式分解为较小的部分,在单个的ExpressionEvaluator转换器中进行计算会更容易。但是,这种方式将ExpressionEvaluators链接在一起处理数据并不是最有效的方式。
原因在于FME在TCL脚本中使用属性值不是从脚本命令中读取它们,而是通过为每个要素重新创建脚本并嵌入相关值(注意,这是我对于一个非常复杂的问题的宽松的解释)
关键在于,每个ExpressionEvaluator中的每个要素都会重新编译TCL代码,将一系列这些转换器链接在一起只会使问题复杂化。
提示 #11a: 当你在工作空间中有多个ExpressionEvaluator转换器时,考虑将它们压缩成单个ExpressionEvaluator以减少TCL调用和编译。
另外一个选择时使用一个TCL脚本替换所有ExpressionEvaluator转换器。这可能听起来令人生畏,但与先前将棘手的算法压缩成单个表达式的想法相比可能相对简单。
TCLCaller转换器一个很好的方式,但是记住通过专门为此目的提供的FME_GetAttribute和FME_SetAttribute函数操作TCL中的属性来优化性能。
提示 #11b: 当你工作空间中有多个ExpressionEvaluator转换器时,考虑用一个包含所有表达式的TCLCaller转换器替换它们。
十、分解任务
不要咀嚼超过你可以咀嚼的东西。如果要处理大量数据,你可能需要考虑将处理划分为某种分组,例如region。这样,你就不必一次完成整个数据集的连接。
例如,你可以编写一个Where语句脚本,一次性选择加拿大10个省的数据,这样FME引擎一次只处理约10-20%的数据。或者你可以进行连续的空间范围查询。不过,这样最终将允许整个国家得到处理。调用工作空间的脚本只需要调用10次,每次将需要处理的省的名称传递给运行时参数,该参数嵌入在工作空间中的SQL或Where语句中。
十一、控制FME引擎如何消耗内存
注意: 除非你有特殊情况或由Safe Software进行指导,否则不应调整这个参数的值。更改这个值会导致无法预期的结果并降低性能。FME2018及以上版本不再受调整内存红线参数影响
FME_ENGINE_MEMORY_REDLINE
资源管理器会自动决定FME引擎进程应使用的最佳总内存。它还动态的将总内存最优的分配给FME中请求它的算法。
FME_ENGINE_MEMORY_REDLINE提示FME引擎消耗内存的积极程度。它的取值在0到1之间(默认值为0.5)。对于更多的内存使用,应设置大于0.5的值。对于减少内存使用,则设置小于0.5的值。太多内存使用的风险在于处理过程使内存不足或机器崩溃。太保守的内存使用则使得处理过程可能需要更长的时间才能完成。
:: Value = 0.5 (默认值)
资源管理器将位于一个“合理的位置”,目标是尽可能快的运行而不会有稳定性的风险。.
:: Value = 0.0
将立即出现"优化内存使用"。这种做法将导致更长的处理时间,因为将数据写入磁盘比使用内存资源成本更高。
:: Value = 1.0
单个进程没有内存限制。只有当整个系统内存很低时才会出现存储。
注意:可以选择上面列出的值之间的值以进一步调整内存使用量。
请注意:当参数值在0.5以下时,/tmp 或FME_TEMP目录中存在足够临时(物理)空间非常重要。
注意:在 FME 2017.1.0 或更早的版本中,由于性能问题,Linux偏向于永不存储。在FME 2017.1.1中,Linux与Windows协调一致。
在FME Workbench中使用Tools-Edit Header设置该值,输入:
FME_ENGINE_MEMORY_REDLINE 0.5
作为第一行。对于FME Server 引擎,参考 How to Control FME Server Engine Memory Usage.