-
【功能模块】惯导数据抽象【操作步骤&问题现象】1、导远570D惯导通过UART连接到MDC300,并启动ins惯导数据抽象进程2、ins惯导数据抽象没有发出数据3、用mdc-tool监控UART确定MCU是有收到惯导发来的串口数据并转发给HOST的4、用MCD Tool工具查看发现InsCmHostProcess进程通过someip接收的是CAN数据而非UART数据问题:ins惯导数据抽象到底是接收CAN数据还是UART数据?(MDC的软件版本为105)【截图信息】【日志信息】(可选,上传日志内容或者附件)
-
【功能模块】【操作步骤&问题现象】1、导远570D惯导通过UART连接到MDC300,并启动ins惯导数据抽象进程2、ins惯导数据抽象没有发出数据3、用mdc-tool监控UART确定MCU是有收到串口数据并转发给HOST的4、用MCD工具查看发现InsCmHostProcess进程通过someip接收的是CAN数据而非UART数据问题:ins惯导数据抽象到底是接收CAN还是UART?【截图信息】【日志信息】(可选,上传日志内容或者附件)
-
缘起TaurusDB是华为云自主研发的最新一代云原生分布式数据库,完全兼容mysql8.0,采用计算与存储分离、日志即数据的架构设计,支持1写15读,性能达到原生Mysql的7倍。Taurus构建在共享分布式存储上,存储空间最高达128T,能跨AZ部署,具有可靠、高性能、易伸缩等特性。华为云TaurusDB性能挑战赛是由华为云主办的数据库领域顶级赛事,大赛将综合科研教学成果及商业领域需求,探索数据库领域的技术问题的可行性,为需求方和开发者提供联接的桥梁;并联合合作伙伴,搭建一个技术交流、人才培养、机遇共创数据库开发者平台和生态。听起来很激动人心吧,关键是奖金也很多, 同时还能刷脸! 最早是听一个同事说起的,恰好本人的工作也是“新一代数据库”开发,看着这么多人工智能的比赛不能参加,只能后悔自己选错了专业,但是机会来了,终于有自己擅长的领域了,心想不能错过这次机会,一边默默加了收藏。比赛内容一句话概括,就是实现一个kvstore,初赛是单机引擎,复赛要求存储计算分离,并且kv都是定长的,如果通用性做得好,可以直接用作块存储。题目初赛和复赛稍有区别,这里只说复赛的题目。存储引擎K,V都是定长的,key 8bytes, value 4K bytes。 测试分为三轮,第一轮, 16个线程写,每个线程写400万次;第二轮,16个线程读,每个线程按顺序读取400万次;第三轮,16个线程读,每个线程逆序读取400万次。第三轮的逆序是局部随机,总体逆序,也即在10M的数据范围内随机读,然后以10M为单位逆序推进。 成绩就是看总时间,时间越短越好。前面已经说过,初赛要实现的是单机引擎,复赛要实现的是存储计算分离的引擎,最大的限制是计算节点不能持久化任何数据。预选赛不得不说,华为可真会玩,这次预选赛竟然还要做题,并且是必须要学习他们的资料才能通过的题目,题目包括数据库的基本常识,但是也有产品介绍,经过深夜两个小时的学习,我算是第一次知道了这么多种不同的产品究竟是干嘛的。第一次答题还错了一道,以防万一,又做了一遍,这次错了两道,算了不玩了,95分也够了,睡觉去。但是心里总是不舒服,究竟是哪错了,又看了一遍,原来是幻读的理解这道题错了。初赛不出意外,预选赛顺利通过,初赛就开始写代码了,初赛只要写对差不多就可以晋级复赛。 当然任何一个程序员都不会满足刚好够用的状态,因此正常能想到的优化都加上了: 比如Direct IO, 多文件做数据分区,引入写buffer,比较频繁修改元数据,读取使用自己实现的page cache,以免4K读不能打满磁盘带宽。复赛复赛要求存储计算分离, 我认真做了一些分析,同时也对他们的硬件做了测试,分析下来,这个比赛比拼的点和我平时在工作中要追求的还是很不一样的。 平时无论做什么系统,都是在延迟差不多的情况下,把吞吐量做高,这次比赛最关键的一个点是:延迟第一,延迟是最重要的,特别是写的阶段,因为并发只有16,想通过聚合换吞吐量都不好使了。首先考虑持久化方法:4K恰好能对齐IO,所以key和value要分开存储, 想使用rocksdb之类的存储引擎即使不被禁止也是没有竞争力的。value非常随机,基本不用考虑压缩,就算有一点点好处,实现起来也太复杂了。再次考虑如何优化IO:SSD的IO吞吐量高于4K * iops, 不管是读还是写,IO聚合是必须的。单文件会遇到文件系统瓶颈,需要多文件, 也即要对数据做partition。关于同步IO还是异步IO的选择, 因为延迟优先,所以应该选同步IO。最后考虑网络框架:首先,我直接放弃考虑任何已有的网络框架,因为这是benchmark, 再小的开销也是开销,都会让程序变慢。其次,实际上任何IO multiplexing的框架都会造成额外的延迟,不仅复杂,也是得不尝失的。综上,我决定就使用最简单的阻塞式IO来做socket通信。总体设计计算节点和存储节点分工, 关键就是索引维护在哪?经过思考, 决定索引维护在计算节点。 索引的内容是: key -> <file_id, pos>, 索引在计算节点的内存中维护为hash表。因为build索引大概需要400ms,写入再读取index比重新构建一遍index时间还长, 所以索引不需要持久化, 这其实是一个反直觉的决定。 计算节点在发送第一个读请求之前,会从存储节点把所有写入的key和pos发送过来, 然后由计算节点构造索引。存储节点起16个线程,listen在16个不同的端口。计算节点也会有16个线程, 每个计算节点的线程只会连接一个存储节点的端口,从而和一个存储节点线程通信。写入请求:写入过程不同的线程完全独立,每个线程负责一部分数据。请求发到存储节点后由接受请求的线程写入。读取过程:读取过程每个存储线程会读取任意一个线程写入的数据。由计算节点指定要读取那个分区的数据。也即写请求发到哪个存储线程,就由那个存储线程写入,每个存储线程实际上就对应了一个数据分区。 读请求发到一个存储线程,它可能要跨线程读取其它分区的数据。存储文件存储节点把数据分为16个partition,每个partition由一个线程负责写入。 每个partition共三个文件: 之所以有三个文件,是因为首先key和value要分开存储,这就要用两个文件;其次为了优化写,额外引入了文件做写入buffer。文件命名规则如下, 以第一个分区为例:00.k: 保存写入的key。 fallocate 4M * 8B, mmap到内存。00.v: 保存写入的value。fallocate 4M * 4K, DIO读写。00.b: 用作写入buffer。fallocate 16K buffer + 4K 元数据,mmap到内存。写入原子性先写key和value,再更新key count。 key count改成功,则写成功;否则写失败,下次重启进程当作这次写没发生过。换句话说,key count改成功实际上表示这次写入commit成功。key count记录在00.k的第一个8字节, 如前所诉, 00.k是mmap到内存的,所以更新key count是没有什么代价的。value先记录到写buffer里,然后批量刷到00.v文件。key file内容如下:key countk1k2k3k4k5k6……value file内容如下:value countv1v2v3v4v5v6……buffer file内容如下:b0b1b2b3…………b15flushed poswrite buffer也是mmap到内存的, 前64K记录数据。 紧跟64K的8个字节记录flushed pos。 因为mmap必须以page为单位,所以实际内存占用64K + 4K。 它实际上是一个mmap持久化的ring buffer。 Ring Buffer的元数据包括filled pos和flushed pos。 filled pos由key count可以算出来, 所以不需要单独再记。build indexbuild index实际上是构造一个key -> offset的hash表。 要在400ms内完成build index,难点是如何并行:基本思路是把key做partition,每个partition内独立构造hash。这本质上是一个MapReduce的过程。map阶段: 并行划分range, 16个线程,每个线程负责处理一个key文件。reduce阶段: 并行构造hash, 16个线程,每个线程处理一个range。线程同步: 第二阶段开始之前要等第一全部完成,也即两个Stage之间是个Barrier, 这个同步过程和map reduce的shuffle是类似的。读取cache的实现cache是value的镜像,value文件分成了16个,cache也对应分成16组。 因为顺序和热点访问模式对cache都很友好,cache不需要特别大,每一组cache大小为64M。为了应对热点读,cache的最小单元设为16M,借用CPU cache的术语,我把它叫cache line,这是一个很大的值。 cache的内存因为是定长的,所以通过mmap一次申请好,不需要动态分配。 cache的索引本质是一个hash,但是不用解决冲突, 用file offset直接计算得到索引的下标。对16组cache中的每一组来说,有4个cache line, 每个cache line有三种状态,用一个uint32_t表示:Invalid: UINT32_MAXLocked: UINT32_MAX - 1Valid: file_offset »12cache line的状态被叫做indexStat,它被单独记在另外一个小数组里。读取不用加锁,使用double check即可:读取之前检查IndexStat有效,并且offset和我要读取的内容匹配。拷贝cache line的内容到私有buffer。拷贝完cache line的内容后再检查IndexStat是否发生过变化, 如果indexStat没有变化过,则说明我们拷贝的cache line内容是对的。为了让上述double check生效, 更新cache的线程需要在写入之前把indexStat改为Locked,更新完成后再把indexStat改为有效值。关于网络通信关于网络框架还有一个问题,就是是否有必要用UDP,犹豫之下,觉得UDP还是会更复杂,稳妥起见,选择了TCP。后来得知在测试环境里UDP是不同的,也就释然了。但是TCP看起来开箱即用,用起来却暗藏机关,至少要调整以下三个参数:tcp_nodelaytcp_quickacksend/recv buf最后为了规避TCP的流控,我们要避免另外两个坑:避免发送太快,超过交换机的队列长度,从而导致丢包,因为TCP的工作方式就是,只要你给它数据,它就会不停的加大,发送窗口,直到发生丢包,然后触发限流。要避免这种情况,本质是要限制TCP的连接数, 因为只要连接数限制住了,发送窗口总长度也就限制住了。避免TCP”冷却”之后重新进入慢启动状态,如果有root权限,是可以通过sysctl关闭slow start的,但是我们没法控制系统参数,这就要求我们一个连接最好要不停的发包,不要停下来。有人定义了packet格式,而我遵循一切从简的原则,没有实现通常RPC要有的功能:没有定义pcode,因为整个通信过程就只有读和写两种request,每一个socket只用来发送一种类型的request,如果要发送不同的request,只需要切换socket即可。没有实现序列化,因为request很简单,只需要把结构体直接发送到socket即可。细节决定性能细节也就是很多关于性能的小点:首先关于文件IO: 同步IO比异步IO延迟要小; open的时候加入O_NOATIME避免读取操作也修改元数据其次关于内存分配: 分配完内后提前触发page fault至少可以让性能更稳定,如果不能提高性能的话; 分配内存可以尝试hugepage, 失败之后再使用4K page; mmap的内存可以不用清零最好关于CPU, 绑核,通用可以让延迟更稳定, 理论上对性能是有提升的。正确性测试如前所属,我基本上是一切从简,但即使如此,提交了好多次,都通不过正确性测试。为了排查问题,专门写了一个随机的验证程序,这个比官方的测试强度高多了。确实发现了一个readv之后更新iovec的bug,还有一处cache的bug。 事后看来,在这个测试上花的时间非常值得,否则我可能到最后都没有成绩。总结这次比赛感觉有点像马拉松,听完大家的分享,感觉每个人的时间都比较有限,大家都是争分夺秒,每个人都有一些优化没来得及试。本人最大的一个遗憾是读预取没有实现。另外一个是写的过程中网络和IO并行化做的不好。最后听了第一名的方案,深有体会,要想拿到最好的成绩,需要把写和读分开考虑,同时把网络传输和本地IO分开考虑。单纯从工程上说,我的代码有一些特有的风格, 简单来说就是总爱重复造轮子,不愿意引入依赖:没有用pthread mutex/cond,全部用atomic ops + futex没有spin,等待的地方都有睡眠和唤醒机制另外,本人虽然工作中用C++, 但是我情愿用plain old C, 所以我很少用高级C++特性。如果未来还做这种系统实现的比赛,希望有可以利用RDMA的和NVM的比赛, 毕竟,新硬件总是有更多的可能。当然比赛的设置要考虑引入更多自由度,这样会更加有趣。
-
【问题来源】星网【功能模块】AICC8.15【操作步骤&问题现象】安装完成CC-CMS后,CMSAPP和SIA进程启动正常,但是SUM启动失败,catalina.out日志截图如下【截图信息】【日志信息】(可选,上传日志内容或者附件)
-
相信大家都有遇见,每当我们杀死Chrome进程后,再次打开Chrome,就会在右上角有一个恢复页面的弹窗,很烦人,有时候还会影响到流程的进行。不用担心,接下来就告诉大家如何永久关闭这个“恢复”弹窗。1.首先我们找到自己磁盘中的appdata目录(一般这个都在C盘User目录下,觉得不太好找的可以试试在路径上直接输入%appdata%,回车,再返回这个目录的上一级就可以了)2.然后我们找到后面的地址 C:\Users\+\AppData\Local\Google\Chrome\User Data\Default 在这个目录下找到Preferences文件3.我们需要右键选择用记事本打开Preferences文件,在里面直接快捷键CTRL+F 去查找exit_type,将"exit_type":"crashed" 改为"Normal"4.然后我们只需要保存关闭Preferences文件,再右键打开Preferences文件属性,将只读这个选项勾上,保存。即可享受永不弹出“恢复页面”的Chrome浏览器了!
-
>摘要:本文将详细介绍GaussDB(DWS)中共享消息队列的实现。本文分享自华为云社区[《GaussDB(DWS)CBB组件之共享消息队列介绍》](https://bbs.huaweicloud.com/blogs/317028?utm_source=csdn&utm_medium=bbs-ex&utm_campaign=ei&utm_content=content),作者:疯狂朔朔。 ## 1)共享消息队列是什么? 在前文中,我们讲解了SysCache的实现原理,GaussDB(DWS)通过SysCache缓存表元数据,以加速查询,然而在并发查询过程中,不可避免地会出现需要同步元数据的情况,举个简单例子,假设存在以下语句执行流程: 1. Create table abc(会话1) 2. Select * from abc(会话1) 3. Drop table abc(会话2) 4. Select * from abc(会话1) 在会话1中,会连续两次执行Select表操作(b和d),在b语句执行后,会话1将对abc的元数据进行缓存,缓存到SysCache中,以备后续使用。然而,在c语句执行后,需要对会话1中的元数据进行失效,否则,会话1将在执行d语句过程中发生错误,读取已删除的数据。 那么,会话2如何“通知”会话1失效哪些数据呢?答案是共享消息队列。 ## 2)共享消息队列存储结构 如图所示,为共享消息队列数据结构  图示中主要包括两部分,下面部分为ThreadLocal结构,主要记录的是每个线程内部的数据,线程间数据是独立的,无法互相访问,上面部分为共享消息队列中的数据,共享消息队列存在于共享内存中,可同时被多个线程访问,共享消息队列的访问场景是典型的一写多读场景。 在共享消息队列中,核心变量有三个,nextMsgNum、minMsgNum、MaxMsgNum,其中nextMsgNum记录了每个线程消息读取到的位置,minMsgNum记录了共享消息队列中最早消息的位置,maxMsgNum记录了共享消息队列中最新消息的位置,对于每个线程而言,需要定期(在表加锁/事务开始/收到信号时触发)从共享消息队列中读取失效消息,利用失效消息(共享消息队列中的每个消息)更新线程内部数据,同时,若线程内部产生失效消息(通常DDL语句在事务提交时产生大量失效消息),则需要向共享消息队列中插入失效数据,供其他线程读取。另外,还有两个参数,hasMessages、resetState,其中hasMessages用于标记对应线程是否存在未读取的失效消息,resetState用于标记对应线程是否需要失效全部消息。 NOTE:失效数据有哪些?失效消息一共有六类(源自PG),有兴趣的同学可以研读PG源码,在此处我们不再展开,仅需知道线程需要从共享消息队列中读取/插入消息,以实现数据同步。 ## 3)共享消息队列接口实现 共享消息队列本质上对于外部接口只需要提供三个功能:读取共享消息队列中消息、向共享消息队列中写入消息、清理共享消息队列。 ### 3.1)读取共享消息队列  如图所示,为失效消息读取过程。在线程同步失效消息过程中,有几个关键点: - 若共享内存中线程对应的hasMessage为True,则表示有失效消息需要读取,否则直接返回,无新的失效消息。 - 读取失效消息过程中,需要持有读共享锁,以保证读取的消息不会被清理掉。 - 若读取失效消息过程中,发现resetState被置为True,说明该线程已经无法使用共享消息队列中的消息进行追增,需要对缓存进行全失效。缓存全失效相当于追增全部数据,需要将nextMsgNum置为maxMsgNum。缓存全失效将严重降低SQL执行性能,尽量减少缓存全失效的发生频率。 - 在追增数据过程中,会推进线程自身的nextMsgNum,以标记数据追增位置。 NOTE:在读取共享消息队列过程中,每个线程推进自己的nextMsgNum位置,以方便记录数据追增情况。 ### 3.2)向共享消息队列中写入消息  如图所示,为失效消息写入过程。有以下几个关键点: - 写入失效消息过程,需要调用清理共享消息队列接口,以保证有足够多的空位写入失效消息。 - 在写入失效消息过程中,会更新maxMsgNum。 - 写入失效消息完毕以后,需要将其他线程的hasMessage标记为True。 - 写入失效消息过程,需要持排他写锁,阻塞其他线程写操作,但不阻塞读。 NOTE:写入失效消息过程实际上是推进maxMsgNum的过程,同时告知其他线程有新的失效消息需要读取。 ### 3.3)清理共享消息队列  如图所示,清理共享消息队列过程中,有以下几个关键点: - 清理共享消息队列需要持有排他读锁和排他写锁,阻塞读过程。其主要原因是,清理共享消息队列会推进minMsgNum,若不持读锁,可能导致nextMsgNum读取过期数据。 - 清理共享消息队列会推进minMsgNum。 - 清理共享消息队列过程,会将所有没有及时追增失效消息的线程执行全失效。 - 在清理共享消息队列最后步骤,会对距离minMsgNum最近的线程,发送追增信号,以确保不会频繁发生全失效。该步骤主要考虑的情况是,若线程长时间处于idle状态,需要外部信号触发其及时追增消息。 NOTE:清理共享消息队列过程,实际上是推进minMsgNum的过程,同时对所有没有及时追增失效消息的线程执行全失效。 根据以上共享消息队列接口可知,读取共享消息队列主要负责推进各个线程自身的nextMsgNum;写入失效消息主要负责推进maxMsgNum;清理共享消息队列主要负责推进minMsgNum。通过共享消息队列,可有效实现各个线程之间的数据同步。
-
>摘要:Docker为什么火,靠的就是Docker镜像。他打包了应用程序的所有依赖,彻底解决了环境的一致性问题,重新定义了软件的交付方式,提高了生产效率。本文分享自华为云社区[《认识容器,我们从它的历史开始聊起》](https://bbs.huaweicloud.com/blogs/285728?utm_source=csdn&utm_medium=bbs-ex&utm_campaign=other&utm_content=content),作者:技术火炬手。 关于容器的历史、发展以及技术本质,在互联网上已经有非常多的文章了。这里旨在结合自身的工作经验和理解,通过一系列的文章,讲清楚这项技术。 # 容器的历史和发展 ### 1、前世 讲到容器,就不得不提LXC(Linux Container),他是Docker的前生,或者说Docker是LXC的使用者。完整的LXC能力在2008年合入Linux主线,所以容器的概念在2008年就基本定型了,并不是后面Docker造出来的。关于LXC的介绍很多,大体都会说“LXC是Linux内核提供的容器技术,能提供轻量级的虚拟化能力,能隔离进程和资源”,但总结起来,无外乎就两大知识点Cgroups(Linux Control Group)和Linux Namespace。搞清楚他俩,容器技术就基本掌握了。 - Cgroups:重点在“限制”。限制资源的使用,包括CPU、内存、磁盘的使用,体现出对资源的管理能力。 - Namespace:重点在“隔离”。隔离进程看到的Linux视图。说大白话就是,容器和容器之间不要相互影响,容器和宿主机之间不要相互影响。 ### 2、少年期起步艰难 2009年,Cloud Foundry基于LXC实现了对容器的操作,该项目取名为Warden。2010年,dotCloud公司同样基于LXC技术,使用Go语言实现了一款容器引擎,也就是现在的Docker。那时,dotCloud公司还是个小公司,出生卑微的Docker没什么热度,活得相当艰难。 ### 3、 成长为巨无霸 2013年,dotCloud公司决定将Docker开源。开源后,项目突然就火了。从大的说,火的原因就是Docker的这句口号“Build once,Run AnyWhere”。呵呵,是不是似曾相识?对的,和Java的Write Once,Run AnyWhere一个道理。对于一个程序员来说,程序写完后打包成镜像就可以随处部署和运行,开发、测试和生产环境完全一致,这是多么大一个诱惑。程序员再也不用去定位因环境差异导致的各种坑爹问题。 Docker开源项目的异常火爆,直接驱动dotCloud公司在2013年更名为Docker公司。Docker也快速成长,干掉了CoreOS公司的rkt容器和Google的lmctfy容器,直接变成了容器的事实标准。也就有了后来人一提到容器就认为是Docker。 总结起来,Docker为什么火,靠的就是Docker镜像。他打包了应用程序的所有依赖,彻底解决了环境的一致性问题,重新定义了软件的交付方式,提高了生产效率。 ### 4、 被列强蚕食 Docker在容器领域快速成长,野心自然也变大了。2014年推出了容器云产品Swarm(K8s的同类产品),想扩张事业版图。同时Docker在开源社区拥有绝对话语权,相当强势。这种走自己的路,让别人无路可走的行为,让容器领域的其他大厂玩家很是不爽,为了不让Docker一家独大,决定要干他。 2015年6月,在Google、Redhat等大厂的“运作”下,Linux基金会成立了OCI(Open Container Initiative)组织,旨在围绕容器格式和运行时制定一个开放的工业化标准,也就是我们常说的OCI标准。同时,Docker公司将Libcontainer模块捐给CNCF社区,作为OCI标准的实现,这就是现在的RunC项目。说白了,就是现在这块儿有个标准了,大家一起玩儿,不被某个特定项目的绑定。 讲到Docker,就得说说Google家的Kubernetes,他作为容器云平台的事实标准,如今已被广泛使用,俨然已成为大厂标配。Kubernetes原生支持Docker,让Docker的市场占有率一直居高不下。如图是2019年容器运行时的市场占有率。  但在2020年,Kubernetes突然宣布在1.20版本以后,也就是2021年以后,不再支持Docker作为默认的容器运行时,将在代码主干中去除dockershim。  如图所示,K8s自身定义了标准的容器运行时接口CRI(Container Runtime Interface),目的是能对接任何实现了CRI接口的容器运行时。在初期,Docker是容器运行时不容置疑的王者,K8s便内置了对Docker的支持,通过dockershim来实现标准CRI接口到Docker接口的适配,以此获得更多的用户。随着开源的容器运行时Containerd(实现了CRI接口,同样由Docker捐给CNCF)的成熟,K8s不再维护dockershim,仅负责维护标准的CRI,解除与某特定容器运行时的绑定。当然,也不是K8s不支持Docker了,只是dockershim谁维护的问题。 随着K8s态度的变化,预计将会有越来越多的开发者选择直接与开源的Containerd对接,Docker公司和Docker开源项目(现已改名为moby)未来将会发生什么样的变化,谁也说不好。  讲到这里,不知道大家有没有注意到,Docker公司其实是捐献了Containerd和runC。这俩到底是啥东西。简单的说,runC是OCI标准的实现,也叫OCI运行时,是真正负责操作容器的。Containerd对外提供接口,管理、控制着runC。所以上面的图,真正应该长这样。  Docker公司是一个典型的小公司因一个爆款项目火起来的案例,不管是技术层面、公司经营层面以及如何跟大厂缠斗,不管是好的方面还是坏的方面,都值得我们去学习和了解其背后的故事。 # 什么是容器 按国际惯例,在介绍一个新概念的时候,都得从大家熟悉的东西说起。幸好容器这个概念还算好理解,喝水的杯子,洗脚的桶,养鱼的缸都是容器。容器技术里面的“容器”也是类似概念,只是装的东西不同罢了,他装的是应用软件本身以及软件运行起来需要的依赖。用鱼缸来类比,鱼缸这个容器里面装的应用软件就是鱼,装的依赖就是鱼食和水。这样大家就能理解docker的logo了。大海就是宿主机,docker就是那条鲸鱼,鲸鱼背上的集装箱就是容器,我们的应用程序就装在集装箱里面。  在讲容器的时候一定绕不开容器镜像,这里先简单的把容器镜像理解为是一个压缩包。压缩包里包含应用的可执行程序以及程序依赖的文件(例如:配置文件和需要调用的动态库等),接下来通过实际操作来看看容器到底是个啥。 ## 一、宿主机视角看容器: **1、首先,我们启动容器。** `docker run -d --name="aimar-1-container" euleros_arm:2.0SP8SPC306 /bin/sh -c "while true; do echo aimar-1-container; sleep 1; done"` 这是Docker的标准命令。意思是使用euleros_arm:2.0SP8SPC306镜像(镜像名:版本号)创建一个新的名字为"aimar-1-container"的容器,并在容器中执行shell命令:每秒打印一次“aimar-1-container”。 - **参数说明:** -d:使用后台运行模式启动容器,并返回容器ID。 --name:为容器指定一个名字。 docker run -d --name="aimar-1-container" euleros_arm:2.0SP8SPC306 /bin/sh -c "while true; do echo aimar-1-container; sleep 1; done" 207b7c0cbd811791f7006cd56e17033eb430ec656f05b6cd172c77cf45ad093c 从输出中,我们看到一串长字符207b7c0cbd811791f7006cd56e17033eb430ec656f05b6cd172c77cf45ad093c。他就是容器ID,能唯一标识一个容器。当然在使用的时候,不需要使用全id,直接使用缩写id即可(全id的前几位)。例如下图中,通过docker ps查询到的容器id为207b7c0cbd81  aimar-1-container容器启动成功后,我们在宿主机上使用ps进行查看。这时可以发现刚才启动的容器就是个进程,PID为12280。  我们尝试着再启动2个容器,并再次在宿主机进行查看,你会发现又新增了2个进程,PID分别为20049和21097。  所以,我们可以得到一个结论。**从宿主机的视角看,容器就是进程。** **2、接下来,我们进入这个容器。** `docker exec -it 207b7c0cbd81 /bin/bash` docker exec也是Docker的标准命令,用于进入某个容器。意思是进入容器id为207b7c0cbd81的容器,进入后执行/bin/bash命令,开启命令交互。 - **参数说明:** -it其实是-i和-t两个参数,意思是容器启动后,要分配一个输入/输出终端,方便我们跟容器进行交互,实现跟容器的“对话”能力。  从hostname从kwephispra09909变化为207b7c0cbd81,说明我们已经进入到容器里面了。在容器中,我们尝试着启动一个新的进程。 `[root@207b7c0cbd81 /]# /bin/sh -c "while true; do echo aimar-1-container-embed; sleep 1; done" &`  再次回到宿主机进行ps查看,你会发现**不管是直接启动容器,还是在容器中启动新的进程,从宿主机的角度看,他们都是进程。** # 二、容器视角看容器: 前面我们已经进入容器里面,并启动了新的进程。但是我们并没有在容器里查看进程的情况。在容器中执行ps,会发现得到的结果和宿主机上执行ps的结果完全不一样。下图是容器中的执行结果。  在Container1容器中只能看见刚起启动的shell进程(container1和container1-embed),看不到宿主机上的其他进程,也看不到Container2和Container3里面的进程。这些进程像被关进了一个盒子里面,完全感知不到外界,甚至认为我们执行的container1是1号进程(1号进程也叫init进程,是系统中所有其他用户进程的祖先进程)。所以,**从容器的视角,容器觉得“我就是天,我就是地,欢迎来到我的世界”。**  但尴尬的是,在宿主机上,他们却是普通得不能再普通的进程。注意,相同的进程,在容器里看到的进程ID和在宿主机上看到的进程ID是不一样的。容器中的进程ID分别是1和1859,宿主机上对应的进程ID分别是12280和9775(见上图)。 # 三、总结 通过上面的实验,对容器的定义就需要再加上一个定语。**容器就是进程=>容器是与系统其他部分隔离开的进程。** 这个时候我们再看下图就更容易理解,容器是跑在宿主机OS(虚机容器的宿主机OS就是Guest OS)上的进程,容器间以及容器和宿主机间存在隔离性,例如:进程号的隔离。  在容器内和宿主机上,同一个进程的进程ID不同。例如:Container1在容器内PID是1,在宿主机上是12280。那么该进程真正的PID是什么呢?当然是12280!那为什么会造成在容器内看到的PID是1呢,造成这种幻象的,正是Linux Namespace。 Linux Namespace是Linux内核用来隔离资源的方式。每个Namespace下的资源对于其他Namespace都是不透明,不可见的。  Namespace按隔离的资源进行分类:  前面提到的容器内外,看到的进程ID不同,正是使用了PID Namespace。那么这个Namespace在哪呢?在Linux上一切皆文件。是的,这个Namespace就在文件里。在宿主机上的proc文件中(/proc/进程号/ns)变记录了某个进程对应的Namespace信息。如下图,其中的数字(例如:pid:[ 4026534312])则表示一个Namespace。  对于Container1、Container2、Container3这3个容器,我们可以看到,他们的PID Namespace是不一样的。说明他们3个容器中的PID相互隔离,也就是说,这3个容器里面可以同时拥有PID号相同的进程,例如:都有PID=1的进程。  在一个命名空间中,那这俩进程就相互可见,只是PID与宿主机上看到的不同而已。  至此,我们可以对容器的定义再细化一层。**容器是与系统其他部分隔离开的进程=》容器是使用Linux Namespace实现与系统其他部分隔离开的进程。**
-
>摘要:云服务环境下,如何解决客户基于大量数据创建索引的性能问题,成为云服务厂商的一个挑战。华为云GaussDB(for MySQL)通过引入并行创建索引技术,很好地解决了批量索引创建和临时添加索引等性能瓶颈问题,帮助用户更快建立好索引。想要进一步了解快速创建索引的秘诀,请不要错过本文。本文分享自华为云社区[《GaussDB(for MySQL)如何快速创建索引?华为云数据库资深架构师为您揭秘》](https://bbs.huaweicloud.com/blogs/300350?utm_source=zhihu&utm_medium=bbs-ex&utm_campaign=database&utm_content=content),作者:华为云数据库资深架构师苏斌。  苏斌,华为云数据库资深架构师,拥有16年数据库内核研发经验,之前作为MySQL官方InnoDB团队主要研发人员,参与和主导了多个重要特性的开发和发布。目前在华为公司负责和参与华为云RDS主要产品RDS for MySQL和GaussDB(for MySQL)内核功能的设计和研发。 # 导读 云服务环境下,如何解决客户基于大量数据创建索引的性能问题,成为云服务厂商的一个挑战。华为云GaussDB(for MySQL)通过引入并行创建索引技术,很好地解决了批量索引创建和临时添加索引等性能瓶颈问题,帮助用户更快建立好索引。想要进一步了解快速创建索引的秘诀,请不要错过本文。 # 关于MySQL索引 我们都知道,数据库使用索引技术加快数据的查询。MySQL数据库也支持若干种索引结构提高查询的性能(参见MySQL文档:https://dev.mysql.com/doc/refman/8.0/en/create-index.html),其中使用最广泛的是B+tree索引,因为B+tree索引在查询和修改的性能之间有很好的平衡,同时其存储和维护的代价也是比较优的。 MySQL的表本身由聚簇索引(必须是B+tree索引)表示,再加上若干个二级索引,包括B+tree索引,共同组成一个MySQL的独立表,可以说MySQL的表是由一组索引共同组成的。我们都知道索引是一把双刃剑,充分的索引可以更好地提升可以适配的查询的性能,但是需要维护这些索引使得其和数据同步,所以在数据修改操作阶段,更多的索引也会带来更高的开销。索引创建与否的权衡通常是动态的,用户不一定能做到在表定义之初就知道需要建立哪些索引,需要随着业务的发展变化而调整索引,这也带来了动态索引创建的一些问题。 # MySQL的索引创建逻辑 我们先看一下MySQL索引创建的逻辑。首先,MySQL索引的创建可以使用两种不同的DDL(Data Definition Language: 数据定义语言)算法来实现。第一种是COPY算法,它非常低效,就是在两个表之间进行数据拷贝,来完成表结构相关的修改,尤其是它要求加表锁,现在基本不使用了。第二种是INPLACE算法,该算法不要求加锁,因此很多DDL操作是不阻塞DML(Data Manipulation Language: 数据操纵语句)操作的,比如创建索引。该算法具体的实现在存储引擎层面完成,可以进行更多的优化。实际上DDL语句还有一种INSTANT算法,但是它无法支持创建索引操作,这里不展开介绍。 对于INPLACE算法,在5.7版本之前,是采用索引记录不断地向建好的空索引插入的方式。由于插入的数据的无序性,该方法导致了明显的性能问题和潜在的空间浪费。在5.7版本以后,MySQL优化了建索引步骤,将其改进为对已排序的索引记录进行自底向上批量插入并且紧凑拼装的创建方式,如果有多个索引要创建,会单独对每个索引执行相同的算法。新的算法会经历读取数据、排序数据和创建索引这几个主要步骤。 总体而言,创建索引这类DDL操作,会比普通的DML等操作要费时,而该类DDL耗时会导致用户在继续动态添加索引加速查询的时候,需要等待很长的时间,极大影响业务;而且用户的MySQL实例开启了Binlog复制,耗时的DDL操作容易引起备库的长时间落后。  MySQL的创建索引流程图 # 云化场景下索引创建的问题 随着越来越多用户把数据托管在云服务上,以及用户数据量的不断增长,前述的动态添加索引导致的问题非常影响用户体验。同时客户的单表数据逐渐达到几TB甚至几十TB,客户对创建索引太慢所带来的性能问题的抱怨越来越多,尤其是创建索引周期如果太长,我们可能很难找到一段合适的业务低峰期来动态创建索引,避免业务的波动。因此,如何在云服务环境下,解决客户基于大量数据创建索引的性能问题,成为云服务厂商的一个挑战。 在云化场景下,还有一个主要场景对客户的体验非常重要。我们知道客户的业务要迁移上云,需要对数据进行大规模的迁移(华为云提供了数据复制服务DRS工具支持各类数据迁移场景),数据迁移比较高效的方式为: 1. 逻辑导出源端数据 2. 在目标端建表(注意,表不含二级索引) 3. 将源端导出的数据插入到目标端 4. 对目标端的表建立二级索引 如果涉及动态数据同步,相关步骤会更复杂一些,由于和该主题无关,这里不展开。以上步骤中,需要重点注意的是步骤2和4,在目标端创建表的时候先不创建二级索引。这个优化对性能影响很大,尤其是一个表有很多二级索引的场景。我们知道Btree索引的插入如果是有序的,对插入性能和结果的空间利用率是最好的,因为Btree索引的分裂会在插入区域的尾部产生,同时由于分裂算法的优化,分裂产生的页面填充率会比较高;相反地,如果是随机插入,尤其是并发地随机插入,很容易导致Btree索引在不同的节点进行分裂,并且分裂后的页面填充率都处于一个半满的状态,导致Btree最终的一个膨胀。 有了这个背景之后,我们就容易理解上面的问题,插入表数据的时候,我们屏蔽了二级索引,等所有数据都准备好了,再采用批量建立索引的方式创建二级索引,这对于二级索引创建效率是最高的。如果不这么做,每插入一条记录,就要去插入相应的二级索引,那么二级索引就是一个无序的随机插入,并发起来性能会变差很多。 虽然在数据同步准备好后,批量创建二级索引是一个有效的方案,但是如果数据量很大,这么创建二级索引还是非常耗时,导致客户在数据迁移完之后需要等待很长时间才能开展业务,这个等待周期可能是小时甚至天级别的。虽然可以考虑表级别的并发创建索引,但是这个方法也有明显的缺点:应用场景有限,要求有多表;以及表和表之间的并发其实不是一个最有效的并发形式,相互影响比较大。 # GaussDB(for MySQL)如何快速创建索引? 综上所述,在创建索引这个点上存在两个性能瓶颈点:一个是用户迁移数据之后的批量索引创建;第二个是用户临时需要添加一个二级索引。无论哪个点,我们都需要更快的建立好索引,提升用户的使用体验。 华为云GaussDB(for MySQL)引入了**并行创建索引的技术**,它改进了社区版MySQL创建索引只用单线程的问题,以此提高创建索引的效率,并一起解决了前述两个痛点。前面提到的社区版创建索引逻辑是单线程的,首先存在资源利用率不够饱满的问题;其次创建索引过程是CPU和IO开销交替进行的过程,在做一个操作的时候,即使不是资源竞争的操作也只有等待。多线程创建索引可以充分利用CPU和IO资源,同时有的线程在做CPU计算时,别的线程可以并发的做IO操作。 GaussDB(for MySQL)使用的并行创建索引,是一个全链路的并行技术。前面提到,创建索引包含了若干个阶段,我们的并行创建算法,对这里的每个阶段都做并行处理,从读取数据、排序、到创建索引,都是并行操作,每一步都由指定的N个线程并发处理。它的逻辑如下图所示:  GaussDB(for MySQL)尤其对数据的归并排序做了多种优化,使得我们常规的归并排序能够充分的并行,充分利用CPU、内存和IO的资源。在并行创建索引之后的合并步骤,也使用了一套简化的算法,正确处理各种索引结构的场景。 # 支持的索引和场景 GaussDB(for MySQL)的并行创建索引功能,目前支持的索引为Btree二级索引。对于virtual index二级索引,将会在不久的将来提供全面的支持,而MySQL的spatial index和fulltext index不在该并行创建索引覆盖范围内。 特别要注意的是,主键索引的创建目前也是不支持并行的,因此如果一个并行创建索引的SQL语句包含创建主键索引,或者前面提及的spatial index与fulltext index,那么客户端将会收到一个告警,提示该操作不支持并行创建索引,同时该语句会采用单线程创建索引的方式执行完成。 从SQL语句的角度,如前所述,创建索引可以采用不同的算法,由于COPY算法(ALGORITHM=COPY)不是采用批量插入的方式,因此不会受益于该并行创建索引优化。而对于INPLACE算法,如果创建索引用的是非rebuild的方式,都可以受益于该优化;一旦需要使用rebuild的方式创建索引,因为涉及到主键索引的建立,将无法使用并行创建索引的算法。 # 示例 下面我们通过几个实例来了解一下如何使用并行创建索引算法加快创建速度,以及我们的条件约束是如何生效的。 1、我们使用sysbench的表,表内有1亿条数据  2、在该表的k字段建索引,采用社区默认单线程,耗时146.82s  3、通过设置innodb_rds_parallel_index_creation_threads = 4启用4个线程建索引,可以看到建索引耗时38.72s,速度提升3.79倍。  4、假设我们要修改主键索引,虽然指定了多线程,但是会收到一个warning,实际上只能通过单线程建索引  # 注意事项 首先对innodb_rds_parallel_index_creation_threads这个参数进行一下说明,它控制了系统中所有并行DDL可以使用的总线程数,取值范围是[1-128]。该参数取值为1表示使用原始的单线程创建索引,取值为N,表示接下来的DDL使用N个线程创建。如果一个DDL使用了100个线程在执行,那么另外一个也要使用并行的DDL且最多只能使用剩下的28个线程;而如果128个线程都被并行DDL语句占用了,新来的DDL只能走原始的单线程创建的逻辑。 虽然该并行创建索引加快了索引的创建速度,但是在具体使用场景下,还是需要有审慎的评估。我们知道在并行算法应用之后,该DDL对硬件资源的使用会尽可能的充分,这也意味着其它操作就得不到太多的资源了。因此,针对不同的场景需要具体地分析,它决定了我们如何创建索引。 对于迁移场景,由于这时候还没有任何业务接入,用户希望尽快完成所有索引的创建,因此可以尽量设置多线程数,比如我们是16核规格的实例,那么我们就可以把并行线程的数量指定为16,加速完成操作。 如果是用户业务运行阶段要创建索引,我们还是不希望DDL操作,对正在运行的业务如DML操作等有太多的影响。因此,这时候创建索引可以指定相对少一些的线程数量,比如2-4(或者根据CPU规格以及负载决定,同时不鼓励并发地执行多个DDL操作)。这样既能相对地加速创建索引的进程,也能保证DML的正常进行。 综上所述,GaussDB(for MySQL)支持了并行创建索引,通过缩短创建索引使用的时间,很好地解决了客户关切的两类问题,提升了客户的体验。但技术无止境,在创建索引领域,还有其它的问题需要我们优化解决,例如如何减少创建索引步骤对IO的影响等等。我们后续会针对这些点进行优化,给客户带来更多的惊喜。 目前,华为云GaussDB(for MySQL) 并行创建索引优化功能已上线,欢迎大家前往华为云官网体验:https://www.huaweicloud.com/product/gaussdb_mysql.html
-
MRS 服务关于Apache log4j远程代码执行漏洞排查及紧急修复声明一、漏洞情况简介Apache Log4j2是一个基于Java的日志记录工具。该工具重写了Log4j框架,并且引入了大量丰富的特性。该日志框架被大量用于业务系统开发,用来记录日志信息。大多数情况下,开发者可能会将用户输入导致的错误信息写入日志中。此次漏洞触发条件为只要外部用户输入的数据会被日志记录,即可造成远程代码执行。该漏洞影响范围广,漏洞危害大,请尽快采取安全措施,阻止漏洞攻击事件的发生。二、MRS服务受影响的大数据组件HiveLoaderFlinkSparkManager(Tomcat)三、MRS集群侧组件修复指引1. 主备节点文件修复1)登录MRS集群主备节点2)在主备节点上分别按照如下步骤进行文件修复 a. 执行如下命令进行修复前状态检查:su - ommfind /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;对应版本的jar包中是否存在引发问题class文件执行备份操作find /opt -name "log4j-core-2.8.2.jar" | while read name;do newname=$(dirname $name) ;cp $name $newname/log4j-core-2.8.2.jar_bak; donefind /opt -name "log4j-core-2.6.2.jar" | while read name;do newname=$(dirname $name) ;cp $name $newname/log4j-core-2.6.2.jar_bak; done查看是否备份成功find /opt -name log4j-core*.jar_bak -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \; b. 执行如下命令进行问题文件修复find /opt -name log4j-core-2.8.2.jar -exec zip -q -d {} org/apache/logging/log4j/core/lookup/JndiLookup.class \;find /opt -name log4j-core-2.6.2.jar -exec zip -q -d {} org/apache/logging/log4j/core/lookup/JndiLookup.class \;出现如图报错无影响,只是表示对应目录的文件不存在异常问题文件 c. 执行如下命令进行修复后文件检查:find /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;所有log4j-core-2.8.2.jar和log4j-core-2.6.2.jar中已不存在问题文件。若出现异常需要进行如下回滚操作 find /opt -name "log4j-core-2.8.2.jar_bak" | while read name;do newname=$(dirname $name) ;mv $name $newname/log4j-core-2.8.2.jar; done find /opt -name "log4j-core-2.6.2.jar_bak" | while read name;do newname=$(dirname $name) ;mv $name $newname/log4j-core-2.6.2.jar; done执行如下命令检查是否回滚成功find /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;3)MRS Manager Tomcat重启生效登录MRS集群主节点查询tomcat进程ps -ef | grep apache-tomcat kill掉进程 kill -9 xxxx,等待自动拉起【启动期间Manager页面无法访问1-3分钟】查询tomcat进程是否被拉起 ps -ef | grep apache-tomcat4) MRS Controller重启生效登录MRS集群主节点查询controller进程ps -ef | grep ControllerServicekill掉进程 kill -9 xxxx,等待自动拉起【启动期间Manager页面无法访问1-3分钟】查询tomcat进程是否被拉起 ps -ef | grep ControllerService5) MRS executor重启生效登录MRS集群主节点查询executor进程ps -ef | grep executorkill掉进程 kill -9 xxxx,等待自动拉起查询tomcat进程是否被拉起 ps -ef | grep executor 2. 大数据组件修复参照第二节涉及组件范围,对当前集群已安装的组件依次进行修复。修复文件后尽量使用滚动重启,以减少对业务的影响,下面以Hive组件为例,其他组件操作方法类似。 1) 集群节点文件修复到主机管理找到集群节点,登陆所有集群节点 a. 执行如下命令进行修复前状态检查:su - ommfind /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;对应版本的jar包中是否存在引发问题class文件执行备份操作find /opt -name "log4j-core-2.8.2.jar" | while read name;do newname=$(dirname $name) ;cp $name $newname/log4j-core-2.8.2.jar_bak; donefind /opt -name "log4j-core-2.6.2.jar" | while read name;do newname=$(dirname $name) ;cp $name $newname/log4j-core-2.6.2.jar_bak; done查看是否备份成功find /opt -name log4j-core*.jar_bak -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \; b. 执行如下命令进行问题文件修复find /opt -name log4j-core-2.8.2.jar -exec zip -q -d {} org/apache/logging/log4j/core/lookup/JndiLookup.class \;find /opt -name log4j-core-2.6.2.jar -exec zip -q -d {} org/apache/logging/log4j/core/lookup/JndiLookup.class \;出现如图报错无影响,只是表示对应目录的文件不存在异常问题文件 c. 执行如下命令进行修复后文件检查:find /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;所有log4j-core-2.8.2.jar和log4j-core-2.6.2.jar中已不存在问题文件。若出现异常需要进行如下回滚操作 find /opt -name "log4j-core-2.8.2.jar_bak" | while read name;do newname=$(dirname $name) ;mv $name $newname/log4j-core-2.8.2.jar; done find /opt -name "log4j-core-2.6.2.jar_bak" | while read name;do newname=$(dirname $name) ;mv $name $newname/log4j-core-2.6.2.jar; done执行如下命令检查是否回滚成功find /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;所有log4j-core-2.8.2.jar和log4j-core-2.6.2.jar中已不存在问题文件完成以后到manager重启各组件服务(除TEZ) 2) 组件服务修复重启生效登录Manager进入服务管理页面,选中所有实例,选择滚动重启。其他服务参考Hive操作进行重启即可
-
MRS 服务关于Apache log4j远程代码执行漏洞排查及紧急修复声明一、漏洞情况简介Apache Log4j2是一个基于Java的日志记录工具。该工具重写了Log4j框架,并且引入了大量丰富的特性。该日志框架被大量用于业务系统开发,用来记录日志信息。大多数情况下,开发者可能会将用户输入导致的错误信息写入日志中。此次漏洞触发条件为只要外部用户输入的数据会被日志记录,即可造成远程代码执行。该漏洞影响范围广,漏洞危害大,请尽快采取安全措施,阻止漏洞攻击事件的发生。二、MRS服务受影响的大数据组件HiveLoaderFlinkSparkManager(Tomcat)Tez三、MRS集群侧组件修复指引1. 主备节点文件修复1)登录MRS集群主备节点2)在主备节点上分别按照如下步骤进行文件修复 a. 执行如下命令进行修复前状态检查:su - ommfind /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;对应版本的jar包中是否存在引发问题class文件执行备份操作find /opt -name "log4j-core-2.8.2.jar" | while read name;do newname=$(dirname $name) ;cp $name $newname/log4j-core-2.8.2.jar_bak; donefind /opt -name "log4j-core-2.6.2.jar" | while read name;do newname=$(dirname $name) ;cp $name $newname/log4j-core-2.6.2.jar_bak; done查看是否备份成功find /opt -name log4j-core*.jar_bak -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \; b. 执行如下命令进行问题文件修复find /opt -name log4j-core-2.8.2.jar -exec zip -q -d {} org/apache/logging/log4j/core/lookup/JndiLookup.class \;find /opt -name log4j-core-2.6.2.jar -exec zip -q -d {} org/apache/logging/log4j/core/lookup/JndiLookup.class \;出现如图报错无影响,只是表示对应目录的文件不存在异常问题文件 c. 执行如下命令进行修复后文件检查:find /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;所有log4j-core-2.8.2.jar和log4j-core-2.6.2.jar中已不存在问题文件。若出现异常需要进行如下回滚操作 find /opt -name "log4j-core-2.8.2.jar_bak" | while read name;do newname=$(dirname $name) ;mv $name $newname/log4j-core-2.8.2.jar; done find /opt -name "log4j-core-2.6.2.jar_bak" | while read name;do newname=$(dirname $name) ;mv $name $newname/log4j-core-2.6.2.jar; done执行如下命令检查是否回滚成功find /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \; 3)MRS Manager Tomcat重启生效登录MRS集群主节点查询tomcat进程ps -ef | grep apache-tomcatkill掉进程 kill -9 xxxx,等待自动拉起【启动期间Manager页面无法访问1-3分钟】查询tomcat进程是否被拉起 ps -ef | grep apache-tomcat4) MRS Controller重启生效登录MRS集群主节点查询controller进程ps -ef | grep ControllerServicekill掉进程 kill -9 xxxx,等待自动拉起【启动期间Manager页面无法访问1-3分钟】查询tomcat进程是否被拉起 ps -ef | grep ControllerService5) MRS executor重启生效登录MRS集群主节点查询executor进程ps -ef | grep executorkill掉进程 kill -9 xxxx,等待自动拉起查询tomcat进程是否被拉起 ps -ef | grep executor 2. 大数据组件修复参照第二节涉及组件范围,对当前集群已安装的组件依次进行修复。修复文件后尽量使用滚动重启,以减少对业务的影响,下面以Hive组件为例,其他组件操作方法类似。 1) 集群节点文件修复到主机管理找到集群节点,登陆所有集群节点 a. 执行如下命令进行修复前状态检查:su - ommfind /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;对应版本的jar包中是否存在引发问题class文件执行备份操作find /opt -name "log4j-core-2.8.2.jar" | while read name;do newname=$(dirname $name) ;cp $name $newname/log4j-core-2.8.2.jar_bak; donefind /opt -name "log4j-core-2.6.2.jar" | while read name;do newname=$(dirname $name) ;cp $name $newname/log4j-core-2.6.2.jar_bak; done查看是否备份成功find /opt -name log4j-core*.jar_bak -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \; b. 执行如下命令进行问题文件修复find /opt -name log4j-core-2.8.2.jar -exec zip -q -d {} org/apache/logging/log4j/core/lookup/JndiLookup.class \;find /opt -name log4j-core-2.6.2.jar -exec zip -q -d {} org/apache/logging/log4j/core/lookup/JndiLookup.class \;出现如图报错无影响,只是表示对应目录的文件不存在异常问题文件 c. 执行如下命令进行修复后文件检查:find /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;所有log4j-core-2.8.2.jar和log4j-core-2.6.2.jar中已不存在问题文件。若出现异常需要进行如下回滚操作 find /opt -name "log4j-core-2.8.2.jar_bak" | while read name;do newname=$(dirname $name) ;mv $name $newname/log4j-core-2.8.2.jar; done find /opt -name "log4j-core-2.6.2.jar_bak" | while read name;do newname=$(dirname $name) ;mv $name $newname/log4j-core-2.6.2.jar; done执行如下命令检查是否回滚成功find /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;所有log4j-core-2.8.2.jar和log4j-core-2.6.2.jar中已不存在问题文件完成以后到manager重启各组件服务(除TEZ) 2) 组件服务修复重启生效 a. 登录Manager进入Hive服务管理页面,选中所有实例,选择滚动重启。 其他服务参考Hive操作进行重启即可(除Tez和Hive的WebHcat实例外) b. Tez服务更新服务配置修复重启生效 i. 在Manager页面Tez组件全部配置中,搜索OPTS配置,在TEZUI_GC_OPTS中内容末尾添加 -Dlog4j2.formatMsgNoLookups=true【注意与前参数有空格】 ii. 点击保存配置,滚动重启Tez。 iii. 在对应实例后台查看进程 ps -ef|grep tez|grep formatMasNoLookups ,查看参数已生效。 c. Hive WebHcat实例修复 i. 从华为maven镜像库https://mirrors.huaweicloud.com/repository/maven/ 中下载如下jar包https://mirrors.huaweicloud.com/artifactory/maven-public/org/apache/logging/log4j/log4j-api/2.10.0/log4j-api-2.10.0.jarhttps://mirrors.huaweicloud.com/artifactory/maven-public/org/apache/logging/log4j/log4j-core/2.10.0/log4j-core-2.10.0.jarhttps://mirrors.huaweicloud.com/artifactory/maven-public/org/apache/logging/log4j/log4j-slf4j-impl/2.10.0/log4j-slf4j-impl-2.10.0.jarhttps://mirrors.huaweicloud.com/artifactory/maven-public/org/apache/logging/log4j/log4j-web/2.10.0/log4j-web-2.10.0.jarhttps://mirrors.huaweicloud.com/artifactory/maven-public/org/apache/logging/log4j/log4j-1.2-api/2.10.0/log4j-1.2-api-2.10.0.jarhttps://mirrors.huaweicloud.com/artifactory/maven-public/com/lmax/disruptor/3.3.6/disruptor-3.3.6.jar登录webhcat所在节点su - ommcd /opt/Bigdata/MRS_1.9.3/install/FusionInsight-Hive-2.3.3/hive/lib/ mv log4j-api-2.6.2.jar log4j-api-2.6.2.jar_bakmv log4j-1.2-api-2.6.2.jar log4j-1.2-api-2.6.2.jar_bakmv log4j-slf4j-impl-2.6.2.jar log4j-slf4j-impl-2.6.2.jar_bakmv log4j-web-2.6.2.jar log4j-web-2.6.2.jar_bakmv disruptor-3.3.0.jar disruptor-3.3.0.jar_bak执行命令修改文件权限chmod 777 log4j-core-2.10.0.jarchown omm:wheel log4j-core-2.10.0.jarchmod 777 log4j-api-2.10.0.jarchown omm:wheel log4j-api-2.10.0.jarchmod 777 log4j-1.2-api-2.10.0.jarchown omm:wheel log4j-1.2-api-2.10.0.jarchmod 777 log4j-slf4j-impl-2.10.0.jarchown omm:wheel log4j-slf4j-impl-2.10.0.jarchmod 777 log4j-web-2.10.0.jarchown omm:wheel log4j-web-2.10.0.jarchmod 777 disruptor-3.3.6.jarchown omm:wheel disruptor-3.3.6.jari. 在Manager页面Hive组件WEBHCAT角色服务配置中,搜索OPTS配置,在WEBHCAT_GC_OPTS中内容末尾添加 -Dlog4j2.formatMsgNoLookups=true【注意与前参数有空格】点击保存配置,滚动重启webHCat。在对应实例后台查看进程 ps -ef|grep webhcat,查看参数已生效。
-
MRS 服务关于Apache log4j远程代码执行漏洞排查及紧急修复声明一、漏洞情况简介Apache Log4j2是一个基于Java的日志记录工具。该工具重写了Log4j框架,并且引入了大量丰富的特性。该日志框架被大量用于业务系统开发,用来记录日志信息。大多数情况下,开发者可能会将用户输入导致的错误信息写入日志中。此次漏洞触发条件为只要外部用户输入的数据会被日志记录,即可造成远程代码执行。该漏洞影响范围广,漏洞危害大,请尽快采取安全措施,阻止漏洞攻击事件的发生。二、MRS服务受影响的大数据组件HiveLoaderFlinkSparkManager(Tomcat)TezImpala三、MRS集群侧组件修复指引1. 主备节点文件修复1)登录MRS集群主备节点2)在主备节点上分别按照如下步骤进行文件修复 a. 执行如下命令进行修复前状态检查:su - ommfind /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;对应版本的jar包中是否存在引发问题class文件执行备份操作find /opt -name "log4j-core-2.8.2.jar" | while read name;do newname=$(dirname $name) ;cp $name $newname/log4j-core-2.8.2.jar_bak; donefind /opt -name "log4j-core-2.6.2.jar" | while read name;do newname=$(dirname $name) ;cp $name $newname/log4j-core-2.6.2.jar_bak; done查看是否备份成功find /opt -name log4j-core*.jar_bak -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \; b. 执行如下命令进行问题文件修复find /opt -name log4j-core-2.8.2.jar -exec zip -q -d {} org/apache/logging/log4j/core/lookup/JndiLookup.class \;find /opt -name log4j-core-2.6.2.jar -exec zip -q -d {} org/apache/logging/log4j/core/lookup/JndiLookup.class \;出现如图报错无影响,只是表示对应目录的文件不存在异常问题文件 c. 执行如下命令进行修复后文件检查:find /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;所有log4j-core-2.8.2.jar和log4j-core-2.6.2.jar中已不存在问题文件。若出现异常需要进行如下回滚操作 find /opt -name "log4j-core-2.8.2.jar_bak" | while read name;do newname=$(dirname $name) ;mv $name $newname/log4j-core-2.8.2.jar; done find /opt -name "log4j-core-2.6.2.jar_bak" | while read name;do newname=$(dirname $name) ;mv $name $newname/log4j-core-2.6.2.jar; done执行如下命令检查是否回滚成功find /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \; 3)MRS Manager Tomcat重启生效登录MRS集群主节点查询tomcat进程ps -ef | grep apache-tomcatkill掉进程 kill -9 xxxx,等待自动拉起【启动期间Manager页面无法访问1-3分钟】查询tomcat进程是否被拉起 ps -ef | grep apache-tomcat4) MRS Controller重启生效登录MRS集群主节点查询controller进程ps -ef | grep ControllerServicekill掉进程 kill -9 xxxx,等待自动拉起【启动期间Manager页面无法访问1-3分钟】查询tomcat进程是否被拉起 ps -ef | grep ControllerService5) MRS executor重启生效登录MRS集群主节点查询executor进程ps -ef | grep executorkill掉进程 kill -9 xxxx,等待自动拉起查询tomcat进程是否被拉起 ps -ef | grep executor 2. 大数据组件修复参照第二节涉及组件范围,对当前集群已安装的组件依次进行修复。修复文件后尽量使用滚动重启,以减少对业务的影响,下面以Hive组件为例,其他组件操作方法类似。 1) 集群节点文件修复到主机管理找到集群节点,登陆所有集群节点 a. 执行如下命令进行修复前状态检查:su - ommfind /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;对应版本的jar包中是否存在引发问题class文件执行备份操作find /opt -name "log4j-core-2.8.2.jar" | while read name;do newname=$(dirname $name) ;cp $name $newname/log4j-core-2.8.2.jar_bak; donefind /opt -name "log4j-core-2.6.2.jar" | while read name;do newname=$(dirname $name) ;cp $name $newname/log4j-core-2.6.2.jar_bak; done查看是否备份成功find /opt -name log4j-core*.jar_bak -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \; b. 执行如下命令进行问题文件修复find /opt -name log4j-core-2.8.2.jar -exec zip -q -d {} org/apache/logging/log4j/core/lookup/JndiLookup.class \;find /opt -name log4j-core-2.6.2.jar -exec zip -q -d {} org/apache/logging/log4j/core/lookup/JndiLookup.class \;出现如图报错无影响,只是表示对应目录的文件不存在异常问题文件 c. 执行如下命令进行修复后文件检查:find /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;所有log4j-core-2.8.2.jar和log4j-core-2.6.2.jar中已不存在问题文件。若出现异常需要进行如下回滚操作 find /opt -name "log4j-core-2.8.2.jar_bak" | while read name;do newname=$(dirname $name) ;mv $name $newname/log4j-core-2.8.2.jar; done find /opt -name "log4j-core-2.6.2.jar_bak" | while read name;do newname=$(dirname $name) ;mv $name $newname/log4j-core-2.6.2.jar; done执行如下命令检查是否回滚成功find /opt -name log4j-core*.jar -exec grep -Rn org/apache/logging/log4j/core/lookup/JndiLookup.class {} \;所有log4j-core-2.8.2.jar和log4j-core-2.6.2.jar中已不存在问题文件完成以后到manager重启各组件服务(除TEZ) 2) 组件服务修复重启生效 a. 登录Manager进入Hive服务管理页面,选中所有实例,选择滚动重启。 其他服务参考Hive操作进行重启即可(除Tez外) b. Tez服务更新服务配置修复重启生效 i. 在Manager页面Tez组件全部配置中,搜索OPTS配置,在TEZUI_GC_OPTS中内容末尾添加 -Dlog4j2.formatMsgNoLookups=true【注意与前参数有空格】 ii. 点击保存配置,滚动重启Tez。 iii. 在对应实例后台查看进程 ps –ef|grep tez,查看参数已生效。
-
打算打造一个比较使用的开发注意事项,请大家一起补充,避免后来的同学掉进去。争取能帮掉进去的同学早点出来。如果开发遇到莫名搞不定的问题了,可以看看这里:1、谨慎杀进程、谨慎杀javaw.exe进程,我们的执行器助手也是javaw进程,如果要杀金蝶但不杀助手,可以采用“wmic process where "Name='javaw.exe' AND CommandLine LIKE %%kingdee%%" delete”2、注意参数是否合法,参数中可能包含了带空格的变量或者带空格的IP地址,导致运行出错。强烈建议密码不使用&符号做密码字符之一(当前已知连接器使用的凭证中不能包含&字符)3、注意参数的引用方式是@{var},@{list[2]}4、调用vba函数的传参需要加引号"@{sheetname}","@{sheetRange}"5、一个eval函数中只写一步运算,返回值注意填写位置,而不是用“=”6、谷歌chrome浏览器需要“扩展程序”里打开“开发者模式”选项,并打开WeAutomate Web插件7、录制chrome或者IE流程时,需要打开UI录制器打开后,点地球来输入网址并回车,这样才能录制到一个openurl8、老版本2.13及以前版本开发者需要熟悉一下新增的命令9、调用子程序callscript,需要传递入参与出参且内部无法改变全局变量的值10、学会使用论坛关键字搜索11、是否需要管理员权限运行,对于管理员权限运行的设计器或者执行器要注意对于共享文件夹是否有访问能力。
This is WeAutomate
发表于2021-12-08 18:53:34
2021-12-08 18:53:34
最后回复
This is WeAutomate
2021-12-08 18:53:34
897 0 -
使用命令查看Linux系统版本、内核版本、CPU型号、硬盘空间、内存信息、网络信息。1、查看系统版本:lsb_release -a2、查看内核版本:uname -a3、查看cpu型号:cat /proc/cpuinfo4、查看硬盘空间情况:df -h5、查看内存信息:free -m 6、查看网络信息:ifconfig常用的查看linux环境信息的命令设进程号为pid,端口号为port。1.CPU占用率命令:top -p pid,%CPU一项,单位为百分比。2.物理内存使用量命令:top -p pid,RES一项,单位为KB。3.虚拟内存使用量命令:top -p pid,VIRT一项,单位为KB。4.进程队列长度命令:top,load average一项,三个值分别代表最近1分钟、5分钟、15分钟进程队列的平均长度。5.打开的socket及其状态命令:netstat -an | grep port,第四列代表源IP,第五列代表目的IP,第六列代表状态(如LISTEN、ESTABLISHED、TIME_WAIT等)。替代命令:ss,需要安装几个内核模块,在连接较多时性能比netstat好很多。安装内核模块命令:insmod /lib/modules/2.6.18-164.el5/kernel/net/ipv4/inet_diag.koinsmod /lib/modules/2.6.18-164.el5/kernel/net/ipv4/tcp_diag.koinsmod /lib/modules/2.6.18-1.2.0.0-xen/kernel/net/ipv4/inet_diag.koinsmod /lib/modules/2.6.18-1.2.0.0-xen/kernel/net/ipv4/tcp_diag.ko6. I/O使用率命令:iostat -x,%util一项,单位为百分比。7.磁盘读写速率命令:iostate -k,kB_read/s表示磁盘每秒读出多少KB数据,kB_wrtn/s表示磁盘每秒写入多少KB数据。8.最近使用的系统调用及其耗费时间命令:strace -f -tt -T -p pid,第一项代表系统调用名称,最后一项代表该调用耗费的时间,单位为秒。9.打开的文件描述符数量命令:ls /proc/pid/fd | wc -l。10.进程地址空间命令:pmap -d pid。11.环境变量命令:cat /proc/pid/environ。12.进程各模块的内存使用情况命令:cat /proc/pid/smaps。13.进程状态信息命令:cat /proc/pid/status,State代表进程状态(运行、睡眠、僵尸等),SleepAVG代表进程睡眠时间的比例,Tgid代表线程组号,PPid代表父进程号,FDSize代表文件描述符的最大个数,VmSize代表进程虚拟地址空间的大小,VLck代表进程锁住的物理内存的大小,锁住的物理内存无法交换到磁盘,VmRSS代表进程正在使用的物理内存的大小,VmData代表进程数据段的大小,VmStk代表进程在用户态的栈的大小,VmExe代表进程拥有的可执行虚拟内存的大小,代码段,不包括使用的库,VmLib代表映射到进程地址空间的库的大小,以上单位均为KB,SigQ代表待处理信号的数量,SigBlk代表被阻塞的信号,SigIgn代表被忽略的信号,SigCgt代表被捕获的信号。14.进程的线程数量命令:ls /proc/pid/task | wc -l。15.启动该进程的命令行命令:cat /proc/pid/cmdline。16.列出当前系统打开了哪些文件以及分别由哪个进程打开命令:sudo lsof -n17.使程序主动生成core dump文件命令:gdb -p pid -batch -ex "generate-core-file"
上滑加载中
推荐直播
-
华为云码道 × 仓颉编程:工程化AI编码探索2026/05/27 周三 19:00-21:00
刘俊杰-华为云仓颉语言专家/李炎-华为云码道技术专家/王智鹏-OpenCangjie开源社区发起人
本场直播围绕华为云仓颉语言与华为云码道的深度结合,展示华为云智能编程从零基础到高效落地的完整生态能力。以华为云码道为引擎,仓颉语言为载体,带给大家日常提效、趣味创新到极速量产的开发体验。
回顾中
热门标签