• [容器专区] 【AR502H-CN产品】【app调试】启动java进程时报错
    【功能模块】lxc容器中调试java程序报错【操作步骤&问题现象】1、容器中加载了java环境,登陆容器后执行 java -version 是ok的没有问题;2、但用命令启动程序时,报out of memoryAborted错误;java -Xms64m -Xmx256m  -jar accnode-drive-core.jar【截图信息】这是容器的资源情况这个是错误信息
  • [其他] 【总结】GaussDB常规锁简介
    GaussDB 从轻量到重量定义了三种锁:l  spinLock(自旋锁),系统级共享资源的封锁操作l  LWLock(轻量锁):系统级共享资源的封锁操作,在系统运行期间,系统级的资源需要加锁,操作后,被释放。l  RegularLock(常规锁/重量锁):用于并发保护用户表的数据。常规锁按照被锁对象按照类型可以分为10种:relation,extend,page,tuple,transactionid,virtualxid,object,userlock,advisory,pg_locks视图中第一列locktype的取值就是这些。下面我们主要介绍常见的表锁(relation)和行锁(tuple)。1 表锁当对表进行DDL/DML 操作时,数据库会对表进行加锁操作,在事务结束时释放。常规锁按照粒度可以分为8个等级,各操作对应的锁以及相容性如下表所示:         当两个事务的锁产生冲突时,未拿到锁的线程会等锁,等锁超过系统设置参数lockwait_timeout(默认值20min)就会报错。报错信息会将持锁语句等信息打印出来,例如:ERROR:  Lock wait timeout: thread 140354461361920 on node   coordinator1 waiting for AccessShareLock on relation 16655 of database 14764   after 1200.057 sDETAIL:  blocked by hold lock thread 140354804238080,   statement <drop table aa;>, hold lockmode AccessExclusiveLock.2 行锁2.1 行锁模式GaussDB不支持for key share和for no key update模式的行级锁,支持以下两种模式:l  For share: 使用select for share语句时持有该模式锁,后台会对tuple加5级锁(ShareLock);l  For update: 使用select for update, delete, update等操作时持有该模式的锁,后台会对tuple加7级锁(ExclusiveLock),根据上图中各级锁的相容性可知,并发更新同一条语句时会产生行锁冲突;2.2 并发更新参数当allow_concurrent_tuple_update=false时,并发更新同一条记录不会等锁,直接报错:abort transaction due to concurrent   update当allow_concurrent_tuple_update=true时,并发更新同一条记录会产生锁冲突。等锁超过系统设置参数update_lockwait_timeout(默认值2min)就会报错。报错信息可以分为几种,最重要的标志就是超时时间。2.3 行锁加锁流程行锁等到事务提交才会释放,其他事物如果等待这个行锁,必须等待这个事务锁释放。tuple锁可以保证多个修改事务加锁的顺序问题,原则是先来先拿锁,修改完tuple后,tuple锁会立即释放,而事务锁不会释放。假设有3个事务,A、B、C依次对同一行修改,均未提交:Session ASession  BSession  Cbegin;update t set b=1;set max_query_retry_times=0;begin;update t set b=2;set update_lockwait_timeout='1s';set max_query_retry_times=0;begin;update t set b=3;此时A处于idle in transaction状态,B持有tuple锁但是等待A的事务锁,C等待B持有的tupe锁。如果B和C分别锁超时,那么超时报错信息如下所示:C 先报错:ERROR:    Lock wait timeout: thread 139728477222656 on node datanode3 waiting   for ExclusiveLock on tuple (0,1) of relation 33287 of database 14194 after  2000.096 msDETAIL:    blocked by hold lock thread 139728418502400, statement <UPDATE   public.t SET b = 2>, hold lockmode ExclusiveLock. B报错:ERROR:    Lock wait timeout: thread 139728477222656 on node datanode3 waiting   for ShareLock on transaction 24858 after 120018.206 msDETAIL:    blocked by hold lock thread 139728691128064, statement < update t   set b=1; >, hold lockmode ExclusiveLock.注释:如果此时A事务中又执行了一条select * from t;那么B的报错信息中statement就是<select * from t;>。2.4 其他报错案例如果持锁事务残留或者正处于提交状态,detail信息可能是ERROR:  dn_6005_6006: Lock wait timeout: thread 140354804238080 on node dn_6001_6002   waiting for ShareLock on transaction 867484 fter 12000.453msDETAIL:    blocked by hold lock thread 0, statement <pending twophase   transaction>, hold lockmode (null).此时可以根据事务号查询是否有残留事务:Select * from pg_prepared_xacts;如果确认残留,调用gs_clean清理残留事务即可。3 如何查询锁等待在没有锁等待超时报错的情况下,我们通常会结合pgxc_stat_activity, pgxc_thread_wait_status, pg_locks等视图来定位锁等待问题,这种方法过于繁琐。我们可以采用以下两种简单方式之一来快速定位锁等待问题:方法一:通过设置参数来达到提前报错的目的,具体可以参考案例:https://bbs.huaweicloud.com/forum/thread-82664-1-1.html方法二:         使用附件提供的工具查询锁等待情况.使用方法:1. 创建存储过程2. 在cn上执行SELECT * FROM pgxc_locks_wait;4 锁超时处理办法现场规避:通过以上方法,找到持锁线程,在对应的实例上执行以下sql杀掉持锁线程select pg_terminate_backend(xxxxx);   --xxxxx为找到的持锁线程长期手段:从业务侧避免锁冲突行为。 
  • [维护宝典] HBase经典案例集锦二:读写异常(1-9):读写数据业务侧报IOExceptions to xxx regionserver
    问题分析HBase客户端scan和写失败,具体报错如下:org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException: Failed 110 actions: IOException: 110 times, servers with issues: pdccsbdspapp105,21302,1529524454464查看服务端gc日志确认gc是否正常。如果有full gc,需要确认是否是服务端gc参数配置不合理,如果gc参数配置正常,需要排查业务变化情况。应用端读写都采用线程池策略,当数据量少时,向服务端的并发请求少,数据量大时,并发请求多。应用端出现上述问题时,服务端分为空闲和不空闲两种情况1). 服务端空闲2). 开启hbase.regionserver.wal.durable.sync=true且出现ResponseTooSlow打印如果服务端空闲,需要打印客户端jstack,打印客户端jstack如果发现大部分线程处于ipc等待连接过程。说明客户端连接在等待,此时说明客户端连接不够用,问题在于hbase.client.ipc.pool.size。此参数控制应用端与HMaster和RegionServer的socket连接数,若应用端是多线程并发读写情况,此参数默认值为1,此socket可能不够,需要将该参数调大,一般值为10左右。    java.lang.Thread.State: TIMED_WAITING (on object monitor)    at java.lang.Object.wait(Native Method)    at org.apache.hadoop.hbase.ipc.RpcClientImpl.call(RpcClientImpl.java:1265)    - locked <0x00000000ef0b1bc8> (a org.apache.hadoop.hbase.ipc.Call)    at org.apache.hadoop.hbase.ipc.AbstractRpcClient.callBlockingMethod(AbstractRpcClient.java:224)问题解决参考如果排查到客户端jstack中存在大量的ipc等待线程,对于应用端开说,多线程并发情况下,需要将hbase.ipc.client.pool.size调整为和并发线程数相同,或者降低并发数,如调高每个批次的batch等。如果是业务侧数据量变大导致,需要调小每个批次的batch或者降低并发线程数。如果排查结果为写HLog慢,需要排查HDFS是否为写磁盘或者网络慢导致HBase写入慢。
  • [维护宝典] HBase经典案例集锦二:读写异常(1-1):dn进程处于tl状态导致regionserver查询超时报错
     问题分析由于业务侧没有日志,所以无法在100+rs中定位到哪台RegionServer可能存在问题。但是通过业务监控反馈主机名为37,38节点的活跃handler数量较其他rs高,怀疑请求处于阻塞状态,可能存在异常。所以优先分析这两个节点。以8:50-9:00为例进行分析:查看38节点rs日志(hbase-omm-regionserver-<hostname>.log)发现如下日志打印:怀疑操作系统资源存在不足情况,排查后发现没有特殊异常。检查nodeagent日志发现DataNode健康检查失败(/var/log/Bigdata/nodeagent/agentlog/agent.log),无法连接到DataNode。查看对应节点的dn日志(/var/log/Bigdata/hdfs/dn/hadoop-omm-datanode-<hostname>.log),发现8:45-9:05没有日志打印,9:05打印Jvmpause ,但dn的gc日志无异常,怀疑dn进程存在异常,查看对应时间的osinfo日志(/var/log/osinfo/statistics/ps.txt),发现该时间点dn进程处于tl状态。再排查37节点dn日志,发现大量jvmpause打印以及对应时间点进程tl状态。同时排查5号两个时间点的dn日志,发现37节点该时间点dn处于tl状态。hbase查询超时失败,是由于部分节点dn进程处于tl状态,导致dn不工作,影响hbase查询。         问题解决参考      去掉jinfo命令采集监控信息,jinfo 命令在监控DataNode 的最大直接内存时使用(651版本已修改为从配置文件中获取)。建议修改监控指标配置后停止该监控项的信息采集,避免jinfo命令调用。     具体操作步骤如下:omm用户登录到节点,备份监控信息的配置文件cd /opt/huawei/Bigdata/adapters/current/HDFS/monitor/controllercp monitor_basic_info.xml /tmp/monitor_basic_info.xml.bak打开文件后删除监控指标dn_memdirectmaxm相关的配置,为1423-1442行内容。备份YARN监控信息的配置文件:cd /opt/huawei/Bigdata/adapters/current/YARN/monitor/controllercp monitor_basic_info.xml /tmp/monitor_basic_info.xml.bak打开文件后删除监控指标dn_memdirectmaxm相关的配置,为1423-1442行内容。重启nodeagent使配置生效:sh /opt/huawei/Bigdata/om-agent/nodeagent/bin/stop-agent.shsh /opt/huawei/Bigdata/om-agent/nodeagent/bin/start-agent.sh执行命令检查是否还有jinfo 调用,观察5分钟左右,没有输出则没有jinfo调用。while true; do ps -ef|grep jinfo |grep proc_datanode; done
  • [PLC专区] 【IMOD-PLC121/PLCce-Power产品】【主任务阻塞功能】主任务在VOS_Ev_Write阻塞
    【功能模块】【PLCe_POWER-1/iMod尾端模块】demo源码工程【操作步骤&问题现象】1、主任务运行到VOS_Ev_Write后无法向下运行,如截图处,运行日志已经上传第一部分。2、如果用LOS_TASK里面的接口新建一个优先级比较低的线程和一个10ms定时器,定时器和线程均只能运行几次,出现EC-IoT APP Init end的运行日志,就结束了日志上传的第二部分。3、如果用LOS_TASK里面的接口新建一个优先级比较高的线程和一个10ms定时器,定时器和线程都能正常运行,但是运行一段时间以后,会出现重启现象,日志为第三部分。4、如果3中的线程每次执行完输出日志挂起,在定时器中恢复,日志为第四部分,可以看到只能进入定时器四次,就结束。出现EC-IoT APP Init end的日志输出,之后就无任何执行信息。5、更新hbin程序后没有3秒的等待除了以上问题,这个工程版本的I2C和SPI等硬件接口均能正常使用,也能被头端发现设备工程版本为:MSDK-COMMON-V200R020C00SPC100,原始工程已经上传【截图信息】【日志信息】(可选,上传日志内容或者附件)mini-boot v200 0.0.8                                                            2019-06-06 11:11:11                                                                                                                                             board id:0x14                                                                   Hit Ctrl+B to stop autoboot:0                                                                                                                                   Flash Id:                                                                        0xC2 0x20 0x17 0xC2 0x20 0x17Block:0x4                                         Chip:0x8                                                                        MX25L64                                                                         env_relocate                                                                    L:gd->env_addr1 & addr20xE000 0xF000                                            spi_flash_read0x0                                                               crc begin 0x0                                                                   crc end 0x0                                                                     spi_flash_read 0x0                                                              L:crc:0x0 0x1                                                                   L:read size:0xFFC                                                               Env ctmax:0x3                                                                   Env mode:0x0                                                                    Env rstcnt:0x0                                                                  Loadaddr:0x10000                                                                L:ulDataSize:0xA870D                                                            L:addr:0x10000                                                                  L:crc:0xCD31C6EB                                                                L:ulChecksum:0xCD31C6EB                                                         L:ulMagic:0x69736948                                                            L:s_sfc_new:0x7040E25C                                                          Uncompresed size: 0x1E5C68                                                      Compresed size: 0xA7B8F                                                                                                                                         Kernel at 0x10000                                                                                                                                                                                                                               EC-IoT APP Init start                                                                                                                                            IOT_RegAllApp unlock                                                           udp_bind(ipaddr = 0.0.0.0, port = 60103)                                        udp_bind: bound to 0.0.0.0, port 60103)                                         sn: 21500302788YL7000515                                                        PLC MAC: 00:a4:02:18:88:31                                                      RF MAC: 00:a4:02:18:88:31                                                       version: V200R020C00SPC100B508                                                  gwmgr_task_entry ID=16                                                          set type(board name): CM-TestType                                               version: V200R020C00SPC100B508                                                  MSDK_DfxOpen success                                                            gwtask init success                                                             GWMGR Init success                                                              EC-IoT APP Init end 第二部分mini-boot v200 0.0.8                                                            2019-06-06 11:11:11                                                                                                                                             board id:0x14                                                                   Hit Ctrl+B to stop autoboot:0                                                                                                                                   Flash Id:                                                                        0xC2 0x20 0x17 0xC2 0x20 0x17Block:0x4                                         Chip:0x8                                                                        MX25L64                                                                         env_relocate                                                                    L:gd->env_addr1 & addr20xE000 0xF000                                            spi_flash_read0x0                                                               crc begin 0x0                                                                   crc end 0x0                                                                     spi_flash_read 0x0                                                              L:crc:0x0 0x1                                                                   L:read size:0xFFC                                                               Env ctmax:0x3                                                                   Env mode:0x0                                                                    Env rstcnt:0x0                                                                  Loadaddr:0x10000                                                                L:ulDataSize:0xA87EF                                                            L:addr:0x10000                                                                  L:crc:0xC58EB054                                                                L:ulChecksum:0xC58EB054                                                         L:ulMagic:0x69736948                                                            L:s_sfc_new:0x7040E25C                                                          Uncompresed size: 0x1E5C68                                                      Compresed size: 0xA7C71                                                                                                                                         Kernel at 0x10000                                                                                                                                                                                                                               EC-IoT APP Init start                                                                                                                                           Start Timer                                                                                                                                                     LOS_TaskLock() Success!                                                                                                                                                                                                                         Example_TaskHi create Success!                                                                                                                                   IOT_RegAllApp unlock                                                                                                                                           Enter TaskHi Handler.                                                                                                                                           udp_bind(ipaddr = 0.0.0.0, port = 60103)                                        udp_bind: bound to 0.0.0.0, port 60103)                                         sn: 21500302788YL7000515                                                        PLC MAC: 00:a4:02:18:88:31                                                      RF MAC: 00:a4:02:18:88:31                                                       version: V200R020C00SPC100B508                                                  gwmgr_task_entry ID=17                                                          set type(board name): CM-TestType                                               version: V200R020C00SPC100B508                                                  MSDK_DfxOpen success                                                            gwtask init success                                                             GWMGR Init success                                                              EC-IoT APP Init end第三部分timecount:313                                                                                                                                                   timecount:314                                                                                                                                                   timecount:315                                                                                                                                                   timecount:316                                                                                                                                                   timecount:317              //运行到这里重启                                                     reg_val:0xE000                                                                                                                                                  mini-boot v200 0.0.8                                                            2019-06-06 11:11:11                                                                                                                                             board id:0x14                                                                   Hit Ctrl+B to stop autoboot:0                                                                                                                                   Flash Id:                                                                        0xC2 0x20 0x17 0xC2 0x20 0x17Block:0x4                                         Chip:0x8                                                                        MX25L64                                                                         env_relocate                                                                    L:gd->env_addr1 & addr20xE000 0xF000                                            spi_flash_read0x0                                                               crc begin 0x0                                                                   crc end 0x0                                                                     spi_flash_read 0x0                                                              L:crc:0x0 0x1                                                                   L:read size:0xFFC                                                               Env ctmax:0x3                                                                   Env mode:0x0                                                                    Env rstcnt:0x0                                                                  Loadaddr:0x10000                                                                L:ulDataSize:0xA8840                                                            L:addr:0x10000                                                                  L:crc:0x688FB5E2                                                                L:ulChecksum:0x688FB5E2                                                         L:ulMagic:0x69736948                                                            L:s_sfc_new:0x7040E25C                                                          Uncompresed size: 0x1E5C68                                                      Compresed size: 0xA7CC2                                                                                                                                         Kernel at 0x10000  第四部分                                                                                mini-boot v200 0.0.8                                                            2019-06-06 11:11:11                                                                                                                                             board id:0x14                                                                   Hit Ctrl+B to stop autoboot:0                                                                                                                                   Flash Id:                                                                        0xC2 0x20 0x17 0xC2 0x20 0x17Block:0x4                                         Chip:0x8                                                                        MX25L64                                                                         env_relocate                                                                    L:gd->env_addr1 & addr20xE000 0xF000                                            spi_flash_read0x0                                                               crc begin 0x0                                                                   crc end 0x0                                                                     spi_flash_read 0x0                                                              L:crc:0x0 0x1                                                                   L:read size:0xFFC                                                               Env ctmax:0x3                                                                   Env mode:0x0                                                                    Env rstcnt:0x0                                                                  Loadaddr:0x10000                                                                L:ulDataSize:0xA88D0                                                            L:addr:0x10000                                                                  L:crc:0xC957827                                                                 L:ulChecksum:0xC957827                                                          L:ulMagic:0x69736948                                                            L:s_sfc_new:0x7040E25C                                                          Uncompresed size: 0x1E5C68                                                      Compresed size: 0xA7D52                                                                                                                                         Kernel at 0x10000                                                                                                                                                                                                                               EC-IoT APP Init start                                                                                                                                           Start Timer                                                                                                                                                     LOS_TaskLock() Success!                                                                                                                                                                                                                         Example_TaskHi create Success!                                                                                                                                                                                                                   IOT_RegAllApp unlock                                                                                                                                           Enter TaskHi Handler.                                                                                                                                           udp_bind(ipaddr = 0.0.0.0, port = 60103)                                                                                                                        TaskHi ID=7                                                                     udp_bind: bound to 0.0.0.0, port 60103)                                         sn: 21500302788YL7000515                                                        PLC MAC: 00:a4:02:18:88:31                                                      RF MAC: 00:a4:02:18:88:31                                                       version: V200R020C00SPC100B508                                                                                                                                  timecount:1                                                                                                                                                     TaskHi ID=7                                                                                                                                                     timecount:2                                                                                                                                                     TaskHi ID=7                                                                                                                                                     timecount:3                                                                                                                                                     TaskHi ID=7                                                                     gwmgr_task_entry ID=17                                                          set type(board name): CM-TestType                                               version: V200R020C00SPC100B508                                                  MSDK_DfxOpen success                                                            gwtask init success                                                                                                                                             timecount:4                                                                                                                                                     TaskHi ID=7                                                                     GWMGR Init success                                                              EC-IoT APP Init end 
  • 一场由fork引发的超时,让我们重新探讨了Redis的抖动问题
    背景介绍华为云数据库GaussDB(for Redis) 是一款基于计算存储分离架构,兼容Redis生态的云原生NoSQL数据库;它依靠共享存储池实现了强一致,支持持久化落盘存储,保证数据的安全可靠。其核心特点是:存算分离、强一致、低成本、超大容量。GaussDB(for Redis)服务团队在支撑某客户业务上云的过程中,发现一次由fork引发的时延抖动问题,本着对客户负责任的态度,我们详细探究了fork这个系统调用的性能影响,并且在最新的GaussDB(for Redis)版本已解决了这个抖动问题,清零了内部的fork使用,与原生Redis相比,彻底解决了fork的性能隐患。问题焦点1)     华为云GaussDB(for Redis) 服务在某客户上云线调测过程中发现,系统上量后规律性的出现每5分钟1次的时延抖动问题。2)     华为云GaussDB(for Redis)团队经过攻关,最终确认抖动原因是fork导致并解决了这个问题。而fork是开源Redis的一个重要依赖,希望通过本文的分享,能够帮助大家在使用开源Redis的时候,充分认识fork的影响,从而选择更优的方案。问题现象某客户业务接入GaussDB(for Redis)压测发现,每5分钟系统出现一次规律性的时延抖动:1)     正常情况消息时延在1-3ms,抖动时刻时延达到300ms左右。2)     通常是压测一段时间后开始出现抖动;抖动一旦出现后就非常规律的保持在每5分钟1次;每次抖动的持续时长在10ms以内。下图是从系统慢日志中捕获到的发生抖动的消息样例(对敏感信息进行了遮掩):问题分析        1.     排查抖动源:1)     由于故障的时间分布非常规律,首先排除定时任务的影响,主要包括:l  agent:和管控对接的周期性统计信息上报任务l  内核:执行引擎(Redis协议解析)和存储引擎(rocksdb)的周期性操作(包括rocskdb统计,wal清理等)屏蔽上述2类定时任务后,抖动依然存在。2)     排除法未果后,决定回到正向定位的路上来。通过对数据访问路径增加分段耗时统计,最终发现抖动时刻内存操作(包括allocate、memcpy等)的耗时显著变长;基本上长出来的时延,都是阻塞在了内存操作上。                                              (截图为相关日志,单位是微秒)3)     既然定位到是系统级操作的抖动,那么下一步的思路就是捕获抖动时刻系统是否有异常。我们采取的方法是,通过脚本定时抓取top信息,分析系统变化。运气比较好,脚本部署后一下就抓到了一个关键信息:每次在抖动的时刻,系统中会出现一个frm-timer进程;该进程为GaussDB(for Redis)进程的子进程,且为瞬时进程,持续1-2s后退出。4)     为了确认该进程的影响,我们又抓取了perf信息,发现在该进程出现时刻,Kmalloc, memset_sse,memcopy_sse等内核系统调用增多。从上述信息推断,frm-timer进程应该是被fork出来的,抖动源基本可锁定在fork frm-timer这个动作上。2.     确定引发抖动的代码:1)     分析frm-timer的来历是下一步的关键。因为这个标识符不在我们的代码中,所以就需要拉通给我们提供类库的兄弟部门联合分析了。经过大家联合排查,确认frm-timer是日志库liblog中的一个定时器处理线程。如果这个线程fork了一个匿名的子进程,就会复用父进程的线程名,表现为Redis进程创建出1个名为frm-timer的子进程的现象。2)     由于frm-timer负责处理liblog中所有模块的定时器任务,究竟是哪个模块触发了上述fork?这里我们采取了一个比较巧妙的方法,我们在定时器处理逻辑中增加了一段代码:如果处理耗时超过30ms,则调用std:: abort()退出,以生成core栈。3)     通过分析core栈,并结合代码排查,最终确认引发抖动的代码如下:上述代码是用来周期性归档日志的,它每5分钟会执行1次 system系统调用来运行相关脚本,完成归档日志的操作。而Linux system系统调用的源码如下,实际上是一个先fork子进程,再调用execl的过程。4)     分析至此,我们还需要回答最后一个问题:究竟是fork导致的抖动,还是脚本内容导致的抖动?为此,我们设计了一组测试用例:l  用例1:将脚本内容改为最简单的echo操作l  用例2:在Redis进程里模拟1个类似frm-timer的线程,通过命令触发该线程执行fork操作l  用例3:在Redis进程里模拟1个类似frm-timer的线程,通过命令触发该线程执行先fork,再excel的操作l  用例4:在Redis进程里模拟1个类似frm-timer的线程,通过命令触发该线程执行system的操作l  用例5:在Redis进程里模拟1个类似frm-timer的线程,通过命令触发该线程执行先vfork,再excel的操作最终的验证结果:l  用例1:有抖动。l  用例2:有抖动。l  用例3:有抖动。l  用例4:有抖动。l  用例5:无抖动。用例1结果表明抖动和脚本内容无关;用例2、3、4的结果表明调用system引发抖动的根因是因为其中执行了fork操作;用例5的结果进一步佐证了抖动的根因就是因为fork操作。最终的故障原因示意图如下:3.     进一步探究fork的影响:1)     众所周知,fork是Linux(严格说是POSIX接口)创建子进程的系统调用,历史上看,主流观点大多对其赞誉有加;但近年间随着技术演进,也陆续出现了反对的声音:有人认为fork是上个时代遗留的产物,在现代操作系统中已经过时,有很多害处。激进的观点甚至认为它应该被彻底弃用。(参见附录1,2)2)     fork当前被诟病的主要问题之一是它的性能。大家对fork通常的理解是其采用copy-on-wirte写时复制策略,因此对其的性能影响不甚敏感。但实际上,虽然fork时可共享的数据内容不需要复制,但其相关的内核数据结构(包括页目录、页表、vm_area_struc等)的复制开销也是不容忽视的。附录1、2中的文章对fork开销有详细介绍,我们这回遇到的问题也是一个鲜活的案例:对于Redis这样的时延敏感型应用,1次fork就可能导致消息时延出现100倍的抖动,这对于应用来说无疑是不可接受的。4.     原生Redis的fork问题:4.1 原生Redis同样被fork问题困扰(参见附录3,4,5),具体包括如下场景: 1)数据备份                                                                            备份时需要生成RDB文件,因此Redis需要触发一次fork。2)主从同步全量复制场景(包括初次复制或其他堆积严重的情况),主节点需要产生RDB文件来加速同步,同样需要触发fork。3)AOF重写       当AOF文件较大,需要合并重写时,也会产生一次fork。4.2 上述fork问题对原生Redis的影响如下:1)业务抖动原生Redis采用单线程架构,如果在电商大促、热点事件等业务高峰时发生上述fork,会导致Redis阻塞,进而对业务造成雪崩的影响。2)内存利用率只有50%Fork时子进程需要拷贝父进程的内存空间,虽然是COW,但也要预留足够空间以防不测,因此内存利用率只有50%,也使得成本高了一倍。3)容量规模影响为减小fork的影响,生产环境上原生Redis单个进程的最大内存量,通常控制在5G以内,导致原生Redis实例的容量大大受限,无法支撑海量数据。解决方法1.      修改日志库liblog中的周期性归档逻辑,不再fork子进程。2.      系统排查并整改GaussDB(for Redis)代码(包括使用的类库代码)中的fork调用。3.      最终排查结果,实际只有本次的这个问题点涉及fork。当前修改后即可确保GaussDB(for Redis)的时延保持稳定,不再受fork性能影响。注:GaussDB(for Redis)由华为云基于存算分离架构自主开发,因此不存在原生Redis的fork调用的场景。总结本文通过分析GaussDB(for Redis)的一次由fork引发的时延抖动问题,探究了fork这个系统调用的性能影响。最新的GaussDB(for Redis)版本已解决了这个抖动问题,并清零了内部的fork使用,与原生Redis相比,彻底解决了fork的性能隐患。希望通过这个问题的分析,能够带给大家一些启发,方便大家更好的选型。   附: 1.[是时候淘汰对操作系统的 fork() 调用了] https://www.infoq.cn/article/BYGiWI-fxHTNvSohEUNW2.[Linux fork那些隐藏的开销] https://www.mdeditor.tw/pl/29L03.[Redis官方文档] https://redis.io/topics/latency4.[Redis的一些坑] https://www.jianshu.com/p/03df6fd516eb5.[Redis 常见问题之-fork操作]https://blog.csdn.net/longgeqiaojie304/article/details/894072146.[GaussDB(for Redis)官网链接]https://www.huaweicloud.com/product/gaussdbforredis.html
  • [赋能学习] 【场景案例】xx银行日志信息检查业务场景(HBase Rowkey设计)
    ### 一、业务背景 xx银行的手机银行将埋点日志实采集到,传回服务端存入了HBase集群原始表。现在需要检查原始表日志信息完整性,字段是否缺失,是否有异常数据。结果用于反馈给前端开发,检查日志抓取业务是否有问题。 #### 1.1 数据类型及数据量 **原始日志包含:** 打开日志 点击日志 页面加载日志 **HBase****字段:** 含13个必填字段, 其一为[behaviour](https://www.baidu.com/link?url=t_AlPPVDYRKzDDS4d4iamNpy8OJojY2pq9njDqT1TdWtHfru8kBC-XG44clh3LerNRO-4D_03QtT5TCUb-EUOsSwzPvtMiU4j0pnlqH6g4a&wd;=&eqid=9b58d2770001fdfa000000065d70c53c)字段,为json,不同日志类型字段数量不同。 **HBase****数据量及region****数目:** 目前有17个HBase节点,单日数据量700G,TTL 为3天,Major_compaction触发间隔为7天,保守估计要存储7T数据(10天) #### 1.2 业务查询类型—范围查询 查询十分钟内所有日志数据 #### 1.3 平台选型 支持MRS-302版本和651版本,其他版本需要根据实际情况修改配置。 ### 二、 现状及诉求 #### 2.1 现状 当前rowkey设计: (一位随机数0~9) | (时间戳精确到天)|uuid 例: 0|20190905|uuid 1. 每天的数据量700G,保守估计要存储7T数据,数据量很大,所以rowkey高位使用一位随机数0~9细分的还不够,很容易出现时间相近的数据依然存在同一region的情况。数据检索的时候负载会集中在个别的RegionServer上,造成热点问题,查询效率太低。 2. 时间戳精确到天不能满足查询十分钟范围的数据 #### 2.2 诉求 需要重新设计Rowkey, 优化查询方案 ### 三、优化方案 #### 3.1 rowkey设计 ##### **3.1.1** rowkey高位散列字段与region: 估计要存储7T数据(10天) ,按每个region 5G 计算, 需要1400个region。每个RegionServer建议管理20-200活跃region,目前有17个HBase节点,分1400个region完全够用,在建表时就预分Region,例如: 1: -xxx ~ 1001 2: 1001 ~ 1002 3: 1002 ~ 1003 … 1400: 2399 ~ +xxx 那么插入数据时就可以使用1000~2399四位随机数作为rowkey的高位,尽可能的把数据均匀分布在每个Region中,以实现负载均衡率。 ##### 3.1.2 rowkey中间时间字段 因为查询需要细化到分、秒,设计为yyyyMMddHHmmss ##### 3.1.3 rowkey尾部uuid 使用32位uuid,用于区别出同一时刻的大量数据 综上:重新设计后的Rowkey规则: (四位随机数1001~2399) -yyyyMMddHHmmss-uuid 例: 1988-20190912152344-uuid #### 3.2 查询设计 扫描数据时,使用基于spark on hbase 调用scan 接口,底层会根据region数进行并发查询,提升效率 ### 四、样例代码 #### 4.1 代码说明 ##### 4.2.1 com.huawei.bigdata.spark.examples.TableCreationJava:创建HBase表 ``` 1. 本demo默认使用表名“RowkeyCase”。 2. 因开发环境限制,本demo预分只200 region 。 请根据自己情况修改。 ``` ##### 4.2.2 com.huawei.bigdata.spark.examples.option2. ProduceData:生成测试数据 ``` 1. 测试数据共50W条,每条0.12KB,共58.6M。 2. 每条数据Rowkey:(本样例200region) 三位随机数100~299) -yyyyMMddHHmmss-uuid,数据共7个字段。 请根据自己情况在启动命令中配置输出文件路径和数据量。 ``` ##### 4.2.3 com.huawei.bigdata.spark.examples.option2.TableInputData:读取HDFS上文件中的测试数据,插入HBaseb表(方法一) ``` 1. puts.size每次数据量建议为2M,本案例设置为20000条。 请根据自己情况酌情修改。 ``` ##### 4.2.4 com.huawei.bigdata.spark.examples.option3.TableInputData:读取HDFS上文件中的测试数据,插入HBaseb表(方法二) ``` 方法一、方法二效率差不多,方法二使用spark saveAsNewAPIHadoopDataset算子,代码更简洁。 ``` ##### 4.2.5 com.huawei.bigdata.spark.examples.option2.TableOutputDataJava:查询数据 ``` 基于spark on hbase 调用scan 接口查询 1. 请根据自己情况酌情修代码中起始region、region数量、表名 2. 请根据自己的业务需要对RDD中的数据进行map、filter等处理 ``` #### 4.2 代码获取 代码获取见附件 ### 五、运行步骤及结果 #### 5.1 准备工作 ##### 1. 修改spark-defaults.conf中的配置: - spark.kryoserializer.buffer.max 调大到 1024MB; - spark.yarn.security.credentials.hbase.enabled修改为true - spark.hbase.obtainToken.enabled 修改为true - spark.inputFormat.cache.enabled修改为false ##### 2. 使用idea代码打包生成SparkHBaseRowkeyCase.jar,上传服务器某路径如/opt/xhk/目录下 ![image.png](https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/attachment/forum/202012/22/170307xlhilk30hkmmgh2a.png) ##### 3. 认证使用的user.keytab 和 krb5.conf,上传服务器某路径如/opt/xhk/目录下 ![image.png](https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/attachment/forum/202012/22/170328w3lpg6lgku7e4jva.png) #### 5.2 创建表 1. Kinit认证后,source配置环境变量。 2. 进入spark2x客户端 3. 执行如下命令 ``` bin/spark-submit --class com.huawei.bigdata.spark.examples.TableCreationJava --master yarn --deploy-mode client /opt/xhk/SparkHBaseRowkeyCase.jar wxb /opt/xhk ``` - TableCreationJava :运行创建表类 - /opt/xhk/SparkHBaseRowkeyCase.jar:类所在jar包 - wxb:user.keytab 和 krb5.conf对应的用户名 - /opt/xhk:user.keytab 和 krb5.conf所在路径 结果如下: ![image.png](https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/attachment/forum/202012/22/170429xirqpx9ogsoooqyq.png) #### 5.3 插入数据 ##### 5.3.1 生成数据 执行命令: ``` java -cp /opt/xhk/SparkHBaseRowkeyCase.jar com.huawei.bigdata.spark.examples.option2.ProduceData /opt/xhk/test0925.txt 500000 ``` - ProduceData :数据生成类 - /opt/xhk/SparkHBaseRowkeyCase.jar:类所在jar包 - /opt/xhk/test0925.txt:测试数据输出文件,名字可自定义 - 500000:50W条数据,因虚拟机内存不足,大家可以设置500W以上数据 ##### 5.3.2 上传HDFS 执行命令: ``` hdfs dfs -mkdir -p /user/xhk cd /opt/xhk mv test0925.txt test09251440.txt hdfs dfs -put test09251440.txt /user/xhk/ ``` ##### 5.3.3 插入表 执行命令: ``` bin/spark-submit --executor-cores 2 --num-executors 10 --executor-memory 4G --driver-memory 2G --conf spark.default.parallelism=1000 --class com.huawei.bigdata.spark.examples.option2.TableInputData --master yarn --deploy-mode client /opt/xhk/SparkHBaseRowkeyCase.jar wxb /opt/xhk /user/xhk/test09251440.txt ``` - executor-cores :用于设置Spark作业总共要用多少个Executor进程来执行 - num-executors:用于设置每个Executor进程的CPU core数量 - executor-memory:用于设置每个Executor进程的内存 - driver-memory:用于设置Driver进程的内存 - conf spark.default.parallelism:用于设置每个stage的默认task数量 - option2.TableInputData:运行插入数据类(方式一) - /opt/xhk/SparkHBaseRowkeyCase.jar:类所在jar包 - wxb:user.keytab 和 krb5.conf对应的用户名 - /opt/xhk:user.keytab 和 krb5.conf所在路径 结果如下: ![image.png](https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/attachment/forum/202012/22/170608qvsc65vynqxt117r.png) #### 5.3.4 查询数据 执行命令: ``` bin/spark-submit --executor-cores 2 --num-executors 20 --executor-memory 2G --driver-memory 5G --conf spark.default.parallelism=1000 --class com.huawei.bigdata.spark.examples.option2.TableOutputDataJava --master yarn --deploy-mode client /opt/xhk/SparkHBaseRowkeyCase.jar wxb /opt/xhk 20201222113639 20201222113647 ``` - executor-cores :用于设置Spark作业总共要用多少个Executor进程来执行 - num-executors:用于设置每个Executor进程的CPU core数量 - executor-memory:用于设置每个Executor进程的内存 - driver-memory:用于设置Driver进程的内存 - conf spark.default.parallelism:用于设置每个stage的默认task数量。 - TableOutputDataJava:运行查询数据类 - /opt/xhk/SparkHBaseRowkeyCase.jar:类所在jar包 - wxb:user.keytab 和 krb5.conf对应的用户名 - /opt/xhk:user.keytab 和 krb5.conf所在路径 - 20201222113639:查询起始时间yyyyMMddHHmmss - 20201222113647:查询结束时间yyyyMMddHHmmss,数据量大时可以选择10分钟间隔的数据 结果如下: ![image.png](https://bbs-img-cbc-cn.obs.cn-north-1.myhuaweicloud.com/data/attachment/forum/202012/22/170642o2vcts2rwigfu7qr.png)
  • [维护宝典] HBase日志说明
    日志存储路径:HBase相关日志的默认存储路径为“/var/log/Bigdata/hbase/角色名”。HMaster:“/var/log/Bigdata/hbase/hm”(运行日志),“/var/log/Bigdata/audit/hbase/hm”(审计日志)。RegionServer:“/var/log/Bigdata/hbase/rs”(运行日志),“/var/log/Bigdata/audit/hbase/rs”(审计日志)。ThriftServer:“/var/log/Bigdata/hbase/ts”(运行日志),“/var/log/Bigdata/audit/hbase/ts”(审计日志)。日志归档规则:HBase的日志启动了自动压缩归档功能,缺省情况下,当日志大小超过30MB的时候(此日志文件大小可进行配置,详情请参见“配置日志级别与文件大小”),会自动压缩,压缩后的日志文件名规则为::“<原有日志名>-<yyyy-mm-dd_hh-mm-ss>.[编号].log.zip”。最多保留最近的20个压缩文件,压缩文件保留个数可以在FusionInsight Manager界面中配置。运行日志说明:1. HMaster日志:hbase-omm-matser-<hostname>.logmaster运行日志,记录master实例启动和运行信息、region迁移的详细和regionserver的宕机日志信息。hbase-omm-matser-<hostname>.outmaster运行环境信息日志,启动时如果加载的JVM参数异常会在日志中打印。matser-omm-<DATE>-<PID>-gc.logmaster GC日志。checkServiceDetail.log服务和实例的健康检查结果日志。hbase.log健康检查脚本以及部分告警检查脚本执行产生的详细日志。stop.logmaster进程停止操作记录日志。hbase-audit-master.logmaster审计日志,记录表的创建、删除、disable操作。2. regionserver日志:hbase-omm-regionserver-<hostname>.logregionserver运行日志,记录regionserver实例启动和运行的信息,region的flush、compaction、split、open、close操作记录,WAL日志的落盘情况、responseTooSlow详细信息等。hbase-omm-regionserver-<hostname>.outregionserver运行环境信息日志,启动时如果加载的JVM参数异常会在日志中打印。regionserver-omm-<DATE>-<PID>-gc.logregionserver GC日志。checkServiceDetail.logregionsever实例的健康检查结果日志hbase.log健康检查脚本以及部分告警检查脚本执行所产生的日志。stop.logregionserver进程停止操作记录日志。hbase-audit-regionserver.logregionserver审计日志。
  • [技术干货] 几款Java开发者必备常用的工具,准点下班不在话下
     摘要:一问一答的形式轻松学习掌握java工具。以一问一答的形式学习java工具Q:检查内存泄露的工具有?A: jmap生成dump转储文件,jhat可视化查看。Q:某进程CPU使用率一直占满,用什么工具可以排查?A:top -Hp pid找到最占CPU的线程然后jstack来查找那个线程此时所处的堆栈,确定问题发生位置。§ 各工具详细介绍§ jstack全称: JVM Stack Trance作用: 查看某个java进程的堆栈情况, 可用于确认死锁、IO等待、死循环等问题。命令用法:jstack pid查看死锁例子如下图,找到wait的lock和已被锁的lock                                                            查看等待IO例子:§ jstat全称:作用:查看进程中内存使用情况,但只能给出一些简单统计数据统计加载了多少类以及占用空间 jstat -class pid统计编译了多少文件 jstat -compiler 10Q: jstat -gcutil {pid} 2000 可以每隔2秒,对pid进程打印内存使用统计信息。gcutil的输出如下里面哪个百分比如果长期处于99%-100%会有OMM风险?(OutOfMemoryError)A:如果E和O即新生代、老年代内存区一直都处于满的状态,则很有可能会引发OMM风险。就像下面这个。§ jmap全称: JVM Memory Map作用:生成进程的内存堆快照当需要看一下进程里是什么东西占用了过多内存时, 可以用jmap打印一下堆快照。命令用法:打印堆快照: jmap -dump:file=./dumpfile.dump 进程pid查看特定类所占用的情况: jmap -histo:live 进程pid | grep 类名Q: 用jmap检查内存泄漏实例我分了3次,每个1h调用jmap查看进程的内存实例,查看该时刻各对象数量第一次查看情况如下:第二次隔了2各小时,查看情况如下:请问哪个对象可能有内存泄漏风险?A:ObjectA可能有泄露, 因为他的对象数量增加最快,说明对象一直在增加且很多无法进行gc释放。§ jhat全称: JVM Heap Analysis Tool和jmap配合, 可以解析jmap生成的堆快照, 支持生成1个web进程供我们分析和查看。命令用法:jhat -J-Xmx515M dumpfile.dump此时就会启动1个webServer,然后我们去访问就行了§ jdb全称:Java Debugger作用:用来对core文件和正在运行的Java进程进行实时地调试,类似于c++里的gdb常见用法:启动进程并调试: jdb -classpath . Test至二级调试某进程: jdb -attach 8000 -sourcepath /Users/wefit/Development/study/java/jtest/src/§ jcmd作用:多功能的工具,可以用它来导出堆、查看Java进程、导出线程信息、执行GC、还可以进行采样分析,可以理解为1个性能调优时用的工具。常见命令:查看 当前机器上所有的 jvm 进程信息: jcmd -l查看指定进程的性能统计信息: jcmd pid PerfCounter.print列出当前运行的 java 进程可以执行的操作: jcmd PID help查看线程堆栈信息: jcmd PID Thread.print查看堆内存信息: jcmd PID GC.heap_dump FILE_NAME§ jps简单记法: JVM process status全名:Java Virtual Machine Process Status Tool作用: 显示 当前系统用户 的 所有 Java进程情况及其进程号常用命令:查看进程jvm参数: jps -v输出程序main class的完整package名或程序的jar文件完整路径名: jps -l输出传递给main方法的参数: jps -m§ jinfojvm infomation作用:和jps功能类似, 但是支持根据指定pis查看指定进程可以查看JVM参数、系统参数、调整jvm参数但不支持查看java程序的内存使用情况§ javap把java字节码文件反汇编为Java源码文件。§ javacjava编译工具javac的执行过程:
  • [调优工具] 【Hyper Tuner调优实践 04】基于系统性能分析工具的网络IO调优实践
    调优介绍背景:在鲲鹏服务器下测试网络性能指标,网络流量只能达到最大流量的10%,将3个网口做了bond后,理论应该达到30Gbps,但实际只能达到3Gbps,且不稳定。解决方法:华为鲲鹏性能优化工具Hyper Tuner是一款针对鲲鹏平台的性能调优工具,包含系统性能优化工具和Java性能优化工具。本文使用系统性能分析工具,从全景分析,进程线程分析和C/C++性能分析模块对网络IO从整体到深入函数级别的问题点定位,找到性能瓶颈点,并根据分析结果进行优化修改,从而实现系统的性能增强并降低系统资源的消耗。组网环境1、服务器型号 TaiShan 200 服务器(型号2280)2、CPU HiSilicon Kunpeng 920-4826 2.60GHz (96 cores)3、内存 384G4、硬盘 SATA HDD: 1.1T+43.7T5、网卡 SP580万兆网卡6、系统 CentOS7.6(内核版本:4.14.0-115.el7a.0.1.aarch64)7、华为鲲鹏性能优化工具 Hyper Tuner 2.2.T3 性能调优工具前提条件1、SP580网卡上的所有网口以bond模式4做bond处理2、安装 Hyper Tuner 2.2.T3 性能调优工具3、在SERVER端服务器进行网络压测。调优思路通过华为鲲鹏性能优化工具Hyper Tuner系统性能分析工具中的全景分析,进程线程分析和C/C++性能分析模块对网络IO从整体到深入函数级别的问题点进行定位。操作步骤问题一:通过系统全景分析,发现SMMU开启,进行关闭操作问题原因:SMMU开启1. 通过Hyper Tuner 2.2.T3 性能调优工具,创建系统“全景分析”任务,创建方式如下图所示。分析对象:系统;分析类型:全景分析;采样时长:10秒;采样间隔:1秒。2. 查看采集分析结果通过全景分析任务,在“总览”页签中,可以获取运行时环境信息,查看到当前“SMMU”配置处于开启状态,在“性能”页签的CPU利用率的图表中可以看到图形化界面的top5 %cpu对应的CPU核在采集时间内的利用率变化,点击右上角的按钮,可以看到在采集时间内的各项数据的平均值。从中可以看出当前CPU内核态利用率(%sys)很高。在“网络IO”下拉菜单中,观察到网络IO的流量很低,为3.4Gb/s左右。结果如下图所示。因为SMMU用于外设在读写内存时,将虚拟地址转为物理地址。如果关闭SMMU,则由内核将虚拟地址转为物理地址后传给外设。如果打开SMMU,那么外设收到的是虚拟地址,每次读写内存时,需要通过SMMU才能读取实际的物理地址。因为外设通过SMMU访问内存时,都要通过SMMU进行一次虚拟地址和物理地址的转换,从而多了一次地址转换的过程,导致性能变慢,所以建议关闭。但在虚拟化场景下,必须打开SMMU。SMMU在虚拟化场景中主要支持虚拟地址(VA)到中间物理地址(IPA)以及中间物理地址(IPA)到物理地址(PA)的地址转换。如果关闭SMMU,三级地址转换需要使用纯软件进行转换,性能较低。解决方案:通过BIOS关闭SMMU修改后结果:网络流量有一定性能提升再次运行网络压测程序,并重新运行全景分析任务如以上步骤,查看到当前“SMMU”配置已经处于关闭状态。查看“性能”页签下,CPU利用率和网络流量,发现内核态的负载还是很高,从“网络IO”中发现网络流量有一定的提升,从3.4Gb/s提升至5.4Gb/s,提升58%。问题二:通过C/C++性能分析,发现内核函数“queued_spin_lock_slowpath”占比高问题原因:Bond模式4的外出流量的slave选举是基于传输hash策略,该策略可以通过xmit_hash_policy选项从缺省的XOR策略改变到其他策略。需要注意的 是,并不是所有的传输策略都是802.3ad适应的,尤其考虑到在802.3ad标准43.2.4章节提及的包乱序问题。从“全景分析”任务发现内核态负载很高的问题后,进一步深入至内核函数级别。1. 通过Hyper Tuner 2.2.T3 性能调优工具,创建“C/C++性能分析”任务采样范围:内核态(采样范围分用户态,内核态,所有。因为我们这里发现绝大部分CPU消耗都在内核态,所以只采集内核态的数据。)2. 查看采集分析结果运行“C/C++性能分析”任务,从“总览”页签,Top 10热点函数中观察到内核函数“queued_spin_lock_slowpath”占比很高,达到96%。在“函数”页签下,进入函数“queue_spin_lock_slowpath”的调用栈,观察到“bond_start_xmit”的调用,如下图。解决方案:修改为bond 0 模式修改后结果:queued_spin_lock_slowpath占比高问题得到了优化,但是出现了新的内核函数“ip_idents_reserve”;网络流量大幅提升;CPU负载有一定程度下降重新运行压测程序,运行“C/C++性能分析”任务,Top 10热点函数中ip_idents_reserve内核函数占比达到76%。运行“全景分析”任务,观察到CPU内核态负载有一定程度下降,从接近100%下降至60%左右,网络流量从5.4Gb/s提升至18.1Gb/s,提升幅度235%。问题三:通过C/C++性能分析,内核函数“ip_idents_reserve”调用占比升高问题原因:ip_idents_reserve对p_id读和修改分两次原子操作,在多进程环境中会造成循环多次执行。该现象在linux官方已发布优化方案:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a6211caa634da39d861a47437ffcda8b38ef421b 解决方案:升级内核基于CentOS 7.6 4.14.0版本内核进行重新编译,在内核源代码路径下,找到/net/ipv4/route.c文件,并对route.c源文件进行修改,具体修改信息参考linux官方发布的优化方案。修改后结果:对“ip_idents_reserve”占比高问题得到了优化。但是出现软中断占比升高。;CPU负载有大幅度下降,但是牺牲了网络流量。使用编译过后的内核重新运行网络压测程序,检查热点函数问题是否得到解决同时系统性能是否得到提升。运行“C/C++性能分析”任务,观察到内核函数“ip_idents_reserve”和“queued_spin_lock_slowpath”不再是Top 10热点函数。运行“全景分析”任务,在“性能”页签下,观测到内核态CPU利用率(%sys)大幅下降,但是软中断(%soft)占比升高, 网络流量有一定程度下降,从18.1Gb/s下降至14.4Gb/s,下降20%。问题四:通过进程/线程性能分析,发现软中断占比升高问题原因:触发了TaiShan服务器的SP580(IN200)网卡驱动已知的缺陷:软中断多-增加驱动poll weight从问题3的修改后现象我们发现软中断占比升高,究竟是哪个进程导致了软中断?1.通过Hyper Tuner 2.2.T3 性能调优工具,创建“进程/线程性能分析”任务分析对象:系统;采样时长:10秒;采样类型:全部勾选;选择采集线程信息。2. 查看采集分析结果运行“进程/线程性能分析”任务,在“总览”页签下观察到系统有很多的ksoftirqd进程占用CPU资源趋近100%,如下图所示。解决方案:重新编译网卡驱动编译安装驱动操作方式(推荐和内核一起编译):1. 获取高版本(如2.3.2.14版本)SP580网卡驱动源码,放到编译环境上并解压,解压后得到一个hinic目录。2. 基于CentOS 7.6 4.14.0版本内核进行重新编译,在内核源代码路径下,找到/net/ipv4/route.c文件,并对route.c源文件进行修改,具体修改信息参考linux官方发布的优化方案。(重复在问题二中的修正)3. 将解压得到的hinic目录下的所有.c和.h文件,以及Makefile文件复制到内核源码路径下/drivers/net/ethernet/huawei/hinic目录下进行替换。4. 修改Makefile文件,修改KERNELDIR为内核源码所在路径,完成对内核+网卡驱动编译修改后结果:软中断问题解决,系统负荷降低,流量逼近理论值。再次运行网络压测程序,运行“全景分析”任务,系统负荷降低,观察到网络IO流量达到预期 - 每个网口的流量均在9.6Gb/s,达到了网卡的最大吞吐量,总流量从14.4Gb/s提升至29Gb/s,提升101%,性能得到了明显的提升。运行“进程/线程性能分析”任务,软中断进程情况消失。总结通过华为鲲鹏性能优化工具Hyper Tuner的系统性能分析中的全景分析,进程线程分析和C/C++性能分析模块,抓取到了内核函数ip_idents_reserve以及queued_spin_lock_slowpath热点问题,网卡驱动引起的软中断升高等问题,由此通过修改Bond模式,内核代码,升级网卡驱动等一系列的调优手段,使得每张网卡的吞吐量均在9.6Gb/s,逼近理论最大值10Gb/s,总流量从3.4Gb/s提升至29Gb/s,提升750%,逼近理论最大值30 Gb/s,同时内核态CPU占比下降至40%以下,软中断占比下降至30%,性能得到了明显的提升。
  • [其他] 【OS】suse 12.3 操作系统问题导致cn卡死或频繁重启
    在suse12.3操作系统上,存在已知问题,线程加上mutex锁后,_data._owner字段不会被赋值为本线程号,而是赋值为0(suse 11上会赋值为本线程号),导致数据库线程对mutex锁状态判断错误,重复加锁,陷入死循环如何识别该问题:堆栈有elision lock查看操作系统的CPU模块cat /proc/cpuinfo在FLAGS中如果存在rtm,说明存在此问题如何规避此问题:在每台机器的/opt/huawei/Bigdata/mppdb/.mppdbgs_profile最后增加一行环境变量export LD_LIBRARY_PATH=/lib64/noelision/:$LD_LIBRARY_PATH,然后依次重启om_monitor进程,cm_agent进程,实例进程使环境变量生效SUSE官网参考:https://www.suse.com/support/kb/doc/?id=000019071
  • [技术干货] 2020-12-13:用最少数量的线程,每个线程执行for的空循环,把cpu打满了。如果在for的空循环里添加打印输出函数,会把
    2020-12-13:用最少数量的线程,每个线程执行for的空循环,把cpu打满了。如果在for的空循环里添加打印输出函数,会把cpu打满吗?为什么?#福大大架构师每日一题#
  • [技术干货] 2020-12-11:多个线程同时写同一个日志文件,为什么相互写的内容不会被覆盖?
    2020-12-11:多个线程同时写同一个日志文件,为什么相互写的内容不会被覆盖?#福大大架构师每日一题#
  • [其他] 【故障】【通信】外部连接报错:too many clients already, active/non_active: x/x
    1.1         问题描述客户端连接数据库、查询语句等,报错连接已满:too many clients already, active/non_active: xxxx/xxxx.图1. dn上连接满1.2         原理分析max_connections决定了进程内的线程数量上限。1.2.1        DN上连接满DN上连接满通常是由于CN与此DN的连接数(一条连接即在DN上开启一个线程)和此DN上启动的Stream线程数量之和达到max_connections所致,报错信息一般会指明具体DN,如图1。当客户端与CN建连后,CN会根据连接的database、username和options匹配到pooler中对应的pool,pool中会保留与其他DN的连接。当需要执行query时,pool会根据执行计划选择与对应DN的保留的连接,若没有,则进行建连。当query执行结束或客户端断开与CN连接后,CN与DN间连接直接归还给相应的pool,便于其他query直接使用,节省建连所需的时间、资源成本。然而,如果user1访问database1执行了100条并发语句后全部退出,那么相应的pool1中就会保留与其他每个DN的100条连接,user2访问database1执行100条并发语句后,又会在pool2中保留100条连接,随着不同pool保留的累积,最后在DN上的连接数达到了max_connections,连接报错。图2. pooler通信框架为此,数据库设计了pooler复用技术,即客户端连接数据库只根据database进行匹配pool,不同的user可以访问同一个pool,从而减少pool的数量,进而减少了保留的连接。然而,随着database数量的增加,相应的pool数量同样也会增加,保留的连接数依然可能达到max_connections。8.0版本增加自动clean connection功能,当CN与DN建连时发现DN连接已满,会清理所有pool中四分之一的空闲连接,不足四个则清理一个,从而保证空闲连接不会产生影响。影响DN上此参数的另一方面是Stream线程数量,其与相应业务的执行计划相关,在定位该问题时,优先排查CN与DN间的连接数量,若数量偏差较大,再进一步考虑业务Stream情况。1.2.2        CN上连接满CN上连接满与DN上有着较大差别,是指CN与CN之间(同DN,也是和pooler相关)和客户端与CN的连接数之和达到max_connections,通常此报错与业务侧相关。对于CN与CN之间的连接,如果更多的是active状态,可能是业务中包含很多DDL操作;如果更多的是idle状态,那么则为pooler中保留的连接,可使用clean connection清理。对于客户端的连接,active状态表示正有业务运行,如果大部分连接都是此状态,那么很有可能是业务并发太高(存在特殊情况),需要降低并发。如果更多的是idle状态的话,则很有可能是对于idle状态连接管控的问题(详见2.3.2)。1.3         定位方法1.3.1        DN上连接满1.     clean connection to [node (dn_xxxx_xxxx/cn_xxxx)] [all] for database dbname;CN上提供了pg_pooler_status视图可以看到当前CN与所有DN的连接情况,对于某个报错的DN,需要分别在所有CN上执行:1.        select in_use, count(*) from pg_pooler_status where node_name = 'dn_xxxx_xxxx' group by 1;  可查看此DN的连接情况,其中in_use为f表示此连接没有被占用,即保留在pool中,为t即为正在使用。使用clean connection操作可清理in_use为f的连接,指定node (dn_xxxx_xxxx)即清理指定DN的连接,指定node (cn_xxxx)即清理指定CN与所有DN的连接,指定all则清理集群所有的in_use为f的连接。当指定all的时候可添加关键字force,这样in_use为t的连接也同样会进行清理,详见产品文档。                2.       如果开启了persistent_datanode_connections,释放掉CN上的idle连接或关闭此参数;当无可执行的query时,CN和DN的连接将归还pool,即in_use由t变为f,但是若此参数开启,则会一直保留连接。关闭此参数或清理CN上idle状态的连接(详见2.3.2)是一种有效的手段。                3.       GUC参数max_connections;CN和DN上的max_connections设置是有依据的,理论上,DN上应设置为CN上的值 * CN的个数。这是由于不同的CN都会与同一个DN进行建连,DN的连接上限要满足大于所有CN连接上限之和。核查一下,说不定真的是DN上不够了!                4.       神级视图:pgxc_thread_wait_status;1.  查询当前DN上所有线程数量:select count(*) from pgxc_thread_wait_status where thread_name like 'cn%' and node_name = 'dn_xxxx_xxxx';  2.  查询当前DN上所有Stream线程数量:select count(*) from pgxc_thread_wait_status where thread_name like 'cn%' and tlevel <> 0 and node_name = 'dn_xxxx_xxxx';  3.  查询所有DN上的线程数量:select node_name, count(*) from pgxc_thread_wait_status where thread_name like 'cn%' and node_name like 'dn%' group by 1 order by 2 desc;  4.  查询所有DN与CN的连接和Stream线程数量:select node_name, sum(level0) cnt0, sum(level1) cnt1, cnt0 + cnt1 sum from (select node_name, case tlevel when 0 then 1 else 0 end as level0, case tlevel when 0 then 0 else 1 end as level1 from pgxc_thread_wait_status where thread_name like 'cn%' and node_name like 'dn%') group by 1 order by 1, 2, 3 desc;  5.  查询所有query在每个DN上的Stream线程数量:select query_id, node_name, count(*) from pgxc_thread_wait_status where query_id <> 0 and tlevel <> 0 and thread_name like 'cn%' and node_name like 'dn%' group by 1, 2 order by 1, 3 desc;  6.  ... 使用-rm工程模式登录数据库,根据pgxc_thread_wait_status视图查看所需信息。然而,存在一些情况是场景丢失、连接数已恢复正常,此时可以部署脚本等待问题再次复现。(脚本文件无法上传,附件中需改回.sh后缀)图3. general脚本用法                5.       gstack打堆栈;若前几种方案均无法排查出问题,可以使用gstack收集堆栈信息,逐一线程分析为何没有正常退出(线程数量可能很庞大,建议打印的堆栈重定向至文件中)。                6.       kill dn_xxxx_xxxx;(应急)1.        找DN目录:cm_ctl query -Cvd | grep dn_xxxx_xxxx  2.        找DN进程:ps ux | grep 上一步找到的目录  3.        统计连接数量:netstat -anpt | grep pid | wc -l  4.        Kill DN进程:kill -9 pid  kill连接数满的DN进程是一种快速、有效的规避手段,然而此方法会对正在执行的业务有短暂影响,且不利于定位根因,使用时需慎重考虑。                7.       cm_ctl switchover –n 备机序号 –D 备机目录;(应急)对于一些特殊情况,例如仅在个别节点应急后连接数仍频繁涨满、其他节点均正常且暂时无法定位根因,使用主备切换方法可进行应急。1.3.2        CN上连接满1.     设置session_timeout;当业务侧未配备连接池管控idle连接时,需要数据库进行管控,否则idle连接一直不释放,很容易造成连接满的问题。对此,设置session_timeout不为0,当达到此时间没有任何操作,则数据库会自动断开连接。值得注意的是,若业务侧有进行对idle的管控,数据库同时设置session_timeout,当超时后数据库自动断开连接,业务侧再获取idle状态的连接,此时连接已断开,会报错:An I/O error occurred while sending to the backend.2.     排查业务侧哪些连接没有释放;1.        select usename, application_name, client_addr, count(*) from pgxc_stat_activity where state = 'idle' and coorname = 'cn_xxxx' group by 1, 2, 3 order by 4 desc;  2.        select usename, application_name, query_start from pgxc_stat_activity where state = 'idle' and coorname = 'cn_xxxx' group by 1, 2, 3 order by 3 desc;  3.        ...  根据pgxc_stat_activity视图可以看到报错CN上的所有连接情况,按照相应的客户端IP地址、用户名、应用名称等信息可定位到连接来源,从而分析根因。此视图可在任意CN上查询,根据需求选择字段查询,详见产品文档。3.     神级视图:pgxc_thread_wait_status;1.  select * from pgxc_thread_wait_status where node_name = 'cn_xxxx';  同DN连接满,此视图可查每个连接对应的线程状态,进而分析根因。4.     gstack打堆栈;若所有CN均出现此报错、无法正常登录数据库或前几种方案均无法排查出问题,可以使用gstack收集堆栈信息,逐一线程分析为何没有正常退出(线程数量可能很庞大,建议打印的堆栈重定向至文件中)。5.     kill连接线程;(应急)1.        select pid, state from pgxc_stat_activity;  2.        select pg_terminate_backend(pid);  对于CN上的每一条连接,都有一个线程相对应,将对应线程kill则会将连接断开。然而此方法同样不利于分析根因,日后还是容易复发。不过尝试kill少量空闲连接对定位影响较小,且也有助于业务恢复。6.     kill cn_xxxx;(应急)同样,kill CN进程应急快、效果好,但是难以分析根因,且执行中的业务会受到影响。
  • [技术干货] 性能之巅:定位和优化程序CPU、内存、IO瓶颈(下)
    ## 进程、线程、协程在linux内核中,进程和线程是同样的系统调用(clone),进程跟线程的区别:线程是共享存储空间的,每个执行流有一个执行控制结构体,这里面会有一个指针,指向地址空间结构,一个进程内的多个线程,通过指向同一地址结构实现共享同一虚拟地址空间。通过fork创建子进程的时候,不会马上copy一份数据,而是推迟到子进程对地址空间进行改写,这样做是合理的,此即为COW(Copy On Write),在应用开发中,也有大量的类似借鉴。协程是用户态的多执行流,C语言提供makecontext/getcontext/swapcontext系列接口,很多协程库也是基于这些接口实现的,微信的协程库libco(已开源)通过hook慢速系统调用(比如write,read)做到静默替换,非常巧妙。## 链接C/C++源代码经编译链接后产生可执行程序,其中数据和代码分段存储,我们写的函数将进入text节,全局数据将进入数据段,未初始化的全局变量进入bss,堆和栈向着相反的方向生长,局部变量在栈里,参数通过栈传递,返回值一般通过eax寄存器返回。想要程序运行的更快,最好把相互调用,关系紧密的函数放到代码段相近的地方,这样能提高icache命中性。减少代码量、减少函数调用、减少函数指针同样能提高i-cache命中性。内联既避免了栈帧建立撤销的开销,又避免了控制跳转对i-cache的冲刷,所以有利于性能。同样,关键路径的性能敏感函数也应该避免递归函数。减少函数调用(就地展开)跟封装是相违背的,有时候,为了性能,我们不得不破坏封装和损伤可读性的代码,这是一个权衡利弊的问题。## 常识和数据CPU拷贝数据一般一秒钟能做到几百兆,当然每次拷贝的数据长度不同,吞吐不同。一次函数执行如果耗费超过1000 cycles就比较大了(刨除调用子函数的开销)。pthread_mutex_t是futex实现,不用每次都进入内核,首次加解锁大概耗时4000-5000 cycles左右,之后,每次加解锁大概120 cycles,O2优化的时候100 cycles,spinlock耗时略少。lock内存总线+xchg需要50 cycles,一次内存屏障要50 cycles。有一些无锁的技术,比如CAS,比如linux kernel里的kfifo,主要利用了整型回绕+内存屏障。#四、怎么做性能优化(TODO)两个⽅向:提⾼运⾏速度 + 减少计算量。性能优化监控先⾏,要基于数据⽽⾮基于猜测,要搭建能尽量模拟真实运⾏状态的压⼒测试环境,在此基于上获取的profiling数据才是有⽤的。方法论:监控 -> 分析 -> 优化 三部曲。##工具:perf是linux内核自带的profiling工具,除之之外还有gprof,但gprof是侵入式的(插桩),编译的时候需要加-pg参数,会导致运行变慢(慢很多)。perf采集的数据,可以用来生成火焰图,也可以用gprof2dot.py这个工具来产生比火焰图更直观的调用图,这些工具就是我经常用的。gprof2dot.py链接:https://github.com/jrfonseca/gprof2dot/blob/master/gprof2dot.py性能优化一个重要原则就是用数据说话,而不能凭空猜测。瓶颈点可能有多个,如果不解决最狭窄的瓶颈点,性能优化就不能达到预期效果。所以性能优化之前一定要先进行性能测试,摸清家底,建立测试基线。例子:之前做SIP协议栈,公司的产品需要提高SIP性能。美国的一个团队经过理论分析,单凭理论分析认为主要是动态内存分配是主要瓶颈,把内存申请成一大块内存,指针都变成的一大块内存的偏移量,非常难于调试,最后效果也不好。我们又通过测试分析的方式重构了程序,性能是它们的五倍。另外,性能优化要一个点一个点的做,做完一点,马上做性能验证。这样可以避免无用的修改。#五、几个具体问题(TODO)##1. 如何定位CPU瓶颈?CPU是通常大家最先关注的性能指标,宏观维度有核的CPU使用率,微观有函数的CPU cycle数,根据性能的模型,性能规格与CPU使用率是互相关联的,规格越高,CPU使用率越高,但是处理器的性能往往又受到内存带宽、Cache、发热等因素的影响,所以CPU使用率和规格参数之间并不是简单的线性关系,所以性能规格翻倍并不能简单地翻译成我们的CPU使用率要优化一倍。至于CPU瓶颈的定位工具,最有名也是最有用的工具就是perf,它是性能分析的第一步,可以帮我们找到系统的热点函数。就像人看病一样,只知道症状是不够的,需要通过医疗机器进一步分析病因,才能对症下药。所以我们通过性能分析工具PMU或者其他工具去进一步分析CPU热点的原因比如是指令数本身就比较多,还是Cache miss导致的等,这样在做性能优化的时候不会走偏。##2. 如何定位IO瓶颈?系统IO的瓶颈可以通过CPU和负载的非线性关系体现出来。当负载增大时,系统吞吐量不能有效增大,CPU不能线性增长,其中一种可能是IO出现阻塞。系统的队列长度特别是发送、写磁盘线程的队列长度也是IO瓶颈的一个间接指标。对于网络系统来讲,我建议先从外部观察系统。所谓外部观察是指通过观察外部的网络报文交换,可以用tcpdump, wireshark等工具,抓包看一下。比如我们优化一个RPC项目,它的吞吐量是10TPS,客户希望是100TPS。我们使用wireshark抓取TCP报文流,可以分析报文之间的时间戳,响应延迟等指标来判断是否是由网络引起来的。然后可以通过netstat -i/-s选项查看网络错误、重传等统计信息。还可以通过iostat查看cpu等待IO的比例。IO的概念也可以扩展到进程间通信。对于磁盘类的应用程序,我们最希望看到写磁盘有没有时延、频率如何。其中一个方法就是通过内核ftrace、perf-event事件来动态观测系统。比如记录写块设备的起始和返回时间,这样我们就可以知道磁盘写是否有延时,也可以统计写磁盘时间耗费分布。有一个开源的工具包perf-tools里面包含着iolatency, iosnoop等工具。##3. 如何定位IO瓶颈?应用程序常用的IO有两种:Disk IO和网络IO。判断系统是否存在IO瓶颈可以通过观测系统或进程的CPU的IO等待比例来进行,比如使用mpstat、top命令。系统的队列长度特别是发送、写磁盘线程的队列长度也是IO瓶颈的一个重要指标。对于网络 IO来讲,我们可以先使用netstat -i/-s查看网络错误、重传等统计信息,然后使用sar -n DEV 1和sar -n TCP,ETCP 1查看网路实时的统计信息。ss (Socket Statistics)工具可以提供每个socket相关的队列、缓存等详细信息。更直接的方法可以用tcpdump, wireshark等工具,抓包看一下。对于Disk IO,我们可以通过iostat -x -p xxx来查看具体设备使用率和读写平均等待时间。如果使用率接近100%,或者等待时间过长,都说明Disk IO出现饱和。一个更细致的观察方法就是通过内核ftrace、perf-event来动态观测Linux内核。比如记录写块设备的起始和返回时间,这样我们就可以知道磁盘写是否有延时,也可以统计写磁盘时间耗费分布。有一个开源的工具包perf-tools里面包含着iolatency, iosnoop等工具。##4.如何定位锁的问题?大家都知道锁会引入额外开销,但锁的开销到底有多大,估计很多人没有实测过,我可以给一个数据,一般单次加解锁100 cycles,spinlock或者cas更快一点。使用锁的时候,要注意锁的粒度,但锁的粒度也不是越小越好,太大会增加撞锁的概率,太小会导致代码更难写。多线程场景下,如果cpu利用率上不去,而系统吞吐也上不去,那就有可能是锁导致的性能下降,这个时候,可以观察程序的sys cpu和usr cpu,这个时候通过perf如果发现lock的开销大,那就没错了。如果程序卡住了,可以用pstack把堆栈打出来,定位死锁的问题。##5. 如何提⾼Cache利用率?内存/Cache问题是我们常见的负载瓶颈问题,通常可利用perf等一些通用工具来辅助分析,优化cache的思想可以从两方面来着手,一个是增加局部数据/代码的连续性,提升cacheline的利用率,减少cache miss,另一个是通过prefetch,降低miss带来的开销。通过对数据/代码根据冷热进行重排分区,可提升cacheline的有效利用率,当然触发false-sharing另当别论,这个需要根据运行trace进行深入调整了;说到prefetch,用过的人往往都有一种体会,现实效果比预期差的比较远,确实无论是数据prefetch还是代码prefetch,不确定性太大,我们和无线做过一些实践,最终以无线输出预取pattern,编译器自动插入prefetch的方案,效果还算可以。剩下的,下次我们接着说!
总条数:813 到第 页
上滑加载中