-
观察内存使用方法: top -c 按住shift+m会根据进程的内存使用情况排序; 若观察到cepd、pms、高斯DB占用了节点大部分内存,其他业务进程没占多少,内存又不够,可以选择进行调整。调整方法修改 cepd 和 pms 的启动和占用内存,并重启 1.1. pmsd 用于集群监控,可使用jps查看对应的进程名为 PMSMain,可根据VM的内存情况修改文件中 pms.mem 的值来合理调整。 /opt/Bigdata/OMSV100R001C00x8664/workspace/conf/pms/application.properties pmsMemXmx="-Xmx3096m"pmsMemXms="-Xms3096m"重启pmsd生效,命令为:/opt/Bigdata/OMSV100R001C00x8664/workspace/bin/omm_s_pm_ctl.sh restart 1.2. cepd 可使用jps查看对应的进程名为 EsperMain,可根据VM的内存情况修改文件中cep.Xmx 的值来合理调整。/opt/Bigdata/OMSV100R001C00x8664/workspace/conf/cep/application.properties重启命cepd生效,命令为:/opt/Bigdata/OMSV100R001C00x8664/workspace/bin/omm_s_cep_ctl.sh restart 2. 高斯DB连接数修改: 修改主备节点/opt/Bigdata/OMSV100R001C00x8664/workspace0/conf/pms/DBConfig.xml中的配置,将pool-maxsize的值修改为20. <item name="pool-maxsize" value="20" /> 重启命令:/opt/Bigdata/om-0.0.1/sbin/restart-oms.sh
-
作者|Costinel Madularea摘要:我是一个罗马尼亚人,我想,我的祖国的文化似乎正好处于两者的中间位置。就我自己而言,我似乎可以完全理解两边的团队到底是怎么想的,为什么这么想。所以很多时候,我在两家公司之间进行协调、传达和解释两边认知上的差异,我想我是客户和华为之间的一座“桥梁”。华为,我又来了!2018年的11月,我十分荣幸地参加了在意大利罗马举行的西欧服务十年颁奖晚会“10 Years Achieving Together”,当我和其他获奖同事并肩站在舞台上,感受这舞台上炫目的灯光,手里捧着纪念奖牌,心里十分满满感动和骄傲。但其实,我和华为缘分可远远不止十年。这是一个复杂而有趣的故事。我来自罗马尼亚,2004年入职罗马尼亚华为公司,成为一名工程师。当时华为在罗马尼亚的业务量并不大,工作了三年,我突然想去追寻生活的更多可能,于是我便离职开始旅行。而当我结束旅行,重新回归职场的时候,我毫不犹豫地再次选择了华为,这一次我来到华为荷兰代表处。我在罗马尼亚出生长大,当我成为荷兰代表处的一名员工的时候,我需要搬家来到荷兰。因此,也可以这么说,我再次成为华为人的第一天,也是我在荷兰这个新国家的第一天。这个有着特殊意义的一天的确非同凡响,我直接从罗马尼亚来到了荷兰,直接在客户的办公室里见到了我的主管和我的同事们。至于原因,我想大家也应该知道,因为当时海牙办事处刚成立不久,所以还没有办公室呢!那时候我们整个团队总共有十几个人,大部分都是中国人,因为我之前在罗马尼亚工作的时候,曾经来荷兰出差过,对这边的项目和同事们也比较熟悉,现在又加入了荷兰代表处,大家工作在一起,吃饭也在一起,每天朝夕相处,关系特别好。对于我来说,中国同事不仅仅只是工作上的同伴,同时也是我生活上的好朋友,我刚到荷兰的时候,是他们帮我找公寓,陪我去家具店买家具,帮我组装家具。我十分喜欢我的中国小伙伴,喜欢中国!联接两边刚开始的时候,我们在客户的公司租了一个办公室办公,离客户距离这么近的好处也显而易见:可以第一时间响应客户的需求。经过几个月和客户肩并肩的工作,我们逐渐和他们建立了良好的合作关系,开始得到他们的信任。我的大多数工作都是和K客户的核心网相关,该项目是华为在西欧一个重大的突破,是欧洲最早的核心网络项目之一,随着合作的深入,我们团队与客户之间的不同点逐渐显露出来。造成差异的原因主要在于华为与荷兰公司的工作文化是非常不同的。我们的工作文化,或者说中国的工作文化,是“垂直”的,这体现在,你的部门做了一个决策,主管传达了之后,大家就分头领任务,开始执行。但是荷兰的公司则完全不是这样的,他们的决策链是分散的,因而更加“水平”,当需要做决定的时候,每个人都会有自己的想法和意见,无论这个人的职位高或者低,都愿意表达出来自己的观点,最后大家再形成统一的意见。这种“垂直”和“水平”的差异,造成的结果就是华为这边经常无法理解——为什么客户做一个决定需要这么长时间?我们有时候和坂田总部这边反馈“项目决定时间需要2年”,总部的同事们百思不得其解。这背后,就映射着荷兰工作的文化,他们非常注重决定的过程,每个人都需要被确信,每个人都要为这个决定而努力。最值得注意的是,由于这个决定是经过每一个人赞成的,后续推进起来也相对会顺利很多。但这样形式对于我们华为是比较陌生的,在大家的认知里,只要和客户主管达成一致了,这个事情应该就没有问题了,大家难以想到这个主管回去之后,还需要得到每一个人的支持才可以进行这个项目。我是一个罗马尼亚人,我想,我的祖国的文化似乎正好处于两者的中间位置。就我自己而言,我似乎可以完全理解两边的团队到底是怎么想的,为什么这么想。所以很多时候,我在两家公司之间进行协调、传达和解释两边认知上的差异,我想我是客户和华为之间的一座“桥梁”。过程与结果的平衡作为“桥梁”,我的任务不仅仅是沟通。一方面我要向自己内部解释为什么K公司那边做出决定需要这么长时间,一边还需要推动组织分享有关进展和计划的信息,并让K公司参与任何升级的故障排除进程,而不仅仅是提供最后结果给到他们。因为,在与客户合作的这段时间,如何做到过程与结果的平衡也是我最大的收获。有这样的收获是因为,我们和客户看问题的角度不一样。华为更注重在结果,但客户对过程的关注程度更高。遇到问题的时候,我们这边集中力量快速解决问题,排除故障,恢复通讯设备的正常运营。但是客户这边十分看重在解决问题的过程中,双方的交流情况,到底是怎么解决了,我们的进程到了哪一步了,更关注如何解决这个问题的具体细节方面。我还记得,2010年K公司的内部话费体系出现了问题,项目组这边集中全部精力,想要尽快恢复计费系统的正常运营。大家一直闷头干活,觉得把问题解决了才是当务之急,忽视了和客户的及时沟通,对齐进度。但是客户和我们想的不一样,他们认为首先应该找到Root Case,然后再解决其他的问题。客户认为,这样才能更好地确定后续不会再发生这样的问题。但是,如果要找到最最底层的原因,为此需要多一两天的工期,这样客户的业务恢复就会被延期,出乎我们的意料,对于这样的结果,客户表示愿意等,并且在我们寻找Root Case的过程中,客户明确提出希望我们可以时时沟通,无论我们这边有什么想法,取得了什么进展,都第一时间让他们知道。他们希望华为提供的不仅仅是一个解决方案,而是能让他们也参与到整个问题解决过程中,了解问题解决的进度。我们常说“以客户为中心”,此刻我也理解到,尊重理解客户的所想,就是“以客户为中心”。我们虽然追求最后结果,但是过程也是不容忽视的,两者需要做到平衡。收获满满的十年成为一名华为人十年有余,常有人问我最大的成就是什么?这个问题可难倒了我,因为我认为任何成就,无论大小,对于我来说,都是一个个令我印象深刻的时刻。就拿数据迁移来说,我就有上千个印象深刻的时候,有的非常顺利,一切都按照计划圆满完成,我们内心喜悦,这样的高兴时刻在脑海里是抹不去的;有的在迁移的过程中出了问题,没有按照既定的计划顺利进展,但是我们克服了所有的困难,找到了解决的方法,避免了数据的倒回,这样柳暗花明的故事也让我铭记于心。这些大大小小的故事,都是我们津津乐道的成就。这十年里,我还有一个重要的收获,那就是改变了思维方式:我不再关注问题是怎么发生的,我更愿意去思考,这个问题应该怎么解决。每当出现问题时,我都会先寻找可能的解决方案,而不是考虑引发特定问题的潜在原因。我确信,只要你坚持不懈,你就一定会找到最好的解决方案,一切皆有可能。在华为工作的日子里,我也离不开家人的支持。忙碌工作之余,我十分珍惜和家人在一起的温馨时刻。平日里,我会尽量抽出时间来陪家人和孩子。为此我还有个小窍门,每天早上早起几个小时,把这段时间用来工作,我很享受这段安静没有人打扰的时刻,这段清晨的时间里,我的工作效率也非常的高。我的幸福家庭当然,与其他公司一样,华为并非一切都是完美的,但如果我用一个词来形容华为,那就是:激情。有人曾经说过,为我们不关心的事努力,这就是所谓的压力,但是为我们喜欢的事情而努力,这就是所谓的激情!我认为用这个词形容我的华为旅程,真的再适合不过了!西欧十年颁奖典礼(左一为作者)本文为《华为人》版权所有,未经允许不得转载。如需转载请联系编辑部hwrb@huawei.com
-
1. 功能概述Envoy启动时,会启动一个进程,并在这个进程中启动很多线程,这样,可以启动很多worker线程,一般worker线程数与核心数相同,每个worker线程处理所有已配置的listener上的请求,管理连接并处理filterchain,非阻塞;同时,在这个进程中会启动一个主线程,它负责启动和停止envoy,也是通过API提供配置管理的线程,同时它收集不同的指标,管理其它线程,也是非阻塞的。2. 重要数据结构定义2.1 Filter过滤器,包括listener filter、network filter和http filter。Listener filter可以用于操作连接元数据,在新接收的套接字上进行操作,例如获取原始目的地址,重定向连接等;network filter主要负责数据读写;http filter主要负责数据处理。2.2 Listener监听器,envoy中支持在每个线程中配置任意数量的监听器,每个监听器独立配置一定数量的network filter,也可以选择性的配置listener filter,listener filter在连接建立之前处理,network filter在连接建立之后处理。2.3 Worker一个worker对应一个envoy的执行线程,将listener绑定在worker上,worker负责监听、过滤和转发,每个连接的生命周期会绑定在一个单独的worker上,通常情况下,envoy实现了100%的非阻塞。3. 代码流程3.1 流程概述Envoy启动时,首先启动主线程,在主线程中对listener和filter进行初始化操作,然后将listener绑定到worker上,并由主线程拉起worker线程,由worker线程负责监听新连接。3.2 初始化3.2.1 main入口main函数是envoy启动的总入口,首先生成main_common,用于后面的初始化。3.2.2 初始化main_common在main_common里面会生成maincommonbase,它会做server instance的初始化,一个instance是一个服务的实例.3.2.3 Instance初始化在maincommonbase里调用InstanceImpl函数后,首先对启动携带的配置信息进行注册,然后执行instance的初始化。Instance的初始化包括两部分:① 将当前instance注册到ListenerManager,来管理更新;② 创建并初始化MainImpl,MainImpl用来初始化监听listener;MainImpl根据配置文件获取静态监听listener列表,将它们实例化并注册到ListenerManager。3.2.4 初始化listener对于每个静态listener,根据配置文件为它创建ListenerFilterFactoryList,并根据配置为它添加ListenerFilterFactory。listener filter有三个:original dst filter,proxy protocol filter, TLS inspector filter,一一按照配置判断是否加入ListenerFilterFactoryList。配置ListenerFilterFactoryList的同时,也会根据配置为这个listener创建NetworkerFilterFactoryList,供后续建立在这个listener上的连接使用。3.3 启动3.3.1 启动入口在main_common初始化正常完成后,执行main_common→run()启动,从而后续执行instance的run()方法,在instance的run()方法,会执行网络级别上的listener初始化。3.3.2 启动worker,将listener绑定到worker上此处,会将从配置文件读取的所有listener绑定到所有的worker上,worker是服务的并发线程,数目一般和核心数相同,将listener绑定到worker上后会通过connectionhandler模块将其初始化。3.3.3 Listener初始化Listener的初始化过程首先生成ActiveListener,通过ActiveListener调用network包内的创建函数来对listener进行网络级别的初始化。3.3.5 启动worker线程,进入监听Listener绑定在worker上,当listener初始化完成后,需要启动worker服务才能真正进入监听流程。此处,为每个worker启动新线程,并调用libevent的event_base_loop进入监听,等待连接事件到达触发后,回调onAccept进入处理流程。4. 总结本文从程序入口main函数开始,分析了envoy如何启动,以及如何对listener、worker这些核心数据结构进行初始化,并详细阐述了从envoy主线程启动到worker线程进入监听行为的全过程。相关服务请访问https://support.huaweicloud.com/cce/index.html?cce_helpcenter_2019
-
代码最后https://github.com/apache/servicecomb-java-chassis/blob/master/core/src/main/java/org/apache/servicecomb/core/executor/GroupExecutor.java为什么只是shutdown了,而没有awaitTermination,这样不就无法保证线程池里面的任务一定能执行完成了吗?@Override public void close() { for (ExecutorService executorService : executorList) { executorService.shutdown(); } executorList.clear(); }
-
华为开源镜像站产品体验官评测 测试环境网络:WiFi(峰值1.7M/s,平均峰值1.5M/s)系统:Centos 7测试地点:深圳隔壁前言 最近了解华为在公测镜像站,我抱着试试的态度报名了评测,下面是我的一些测试数据和体验。首先,进入华为官方镜像站,映入眼帘的是50+的镜像,系统镜像,系统源和软件源,范围之广令人惊喜,最令我意外的是华为镜像有一些开源的软件镜像和EPEL;网站提供了快捷方便的系统下载,也提供了一些脚本方便用户替换。 速度测试(按首字母排序) 结果令人惊喜,不知道是不是开了个物理外挂,ε=ε=ε=┏(゜ロ゜;)┛ 在接下来的使用中,我尝试下载一些大包(准确的来说是一堆包),速度可以到达平均峰值(1.5M/s),但是也会出现掉速(700K/s+),我很满意这个速度,某些源能掉到200K+,更有的掉到20K+,慢到怀疑人生。槽点 1.刚开始登陆这个网站,试了试华为的账号以及相关账号,到后面才发现,要重新注册。。。。。。 2.换软件源代码:刚开始我用网站上提供的命令去替换我的源,结果失败,后来检查发现我用的不是官方的源,我之前换过,后来换回官方的源再次敲命令才成功生效。建议 1.建议打通账号信息,方便用户上手。 2.换关键字可能会出现错误,建议官方提供源文件直接让用户下载替换文件,或提供一键替换的脚本降低上手难度和出错概率。 3.既然来了镜像站,又了解了相关操作方式,买台服务器玩玩?总结 通过这次的评测,我挺惊喜的,这个速度就不用让我们浪费更多的时间在下载安装包上面,也让我看到了华为云的应用与实力,这个源我也会推荐给我的同学以及考了华为认证的小伙伴,希望华为能给我们带来更多的惊喜,也祝华为云越来越好。
-
很对开发者测试的时候,发现CSE SDK的CPU占用率很多时候只能够到1CPU,这是因为servicecomb.rest.server.thread-count默认值为1。 官网文档将这个配置项含义解释为“服务端线程数”(参考: https://docs.servicecomb.io/java-chassis/zh_CN/build-provider/protocol/rest-over-vertx.html),这个解释其实不怎么准确,容易和event-loop线程数混淆,开发者理解不了,而且提升这个值,CPU的利用率确实会增加,但是通过jstack查看线程数,却不会增加。 servicecomb.rest.server.thread-count实际上的含义是Vertical的一个概念: vertical instances count。 他是一个非常抽象的概念, 涉及到资源分配和线程绑定关系。比如当值为1的时候,服务端每收到一个请求,就会将请求丢到一个event-loop线程去执行,然后这个绑定关系就确定下来了,不会发生改变。 单纯的从服务端来看,缺省值为1,而event-loop线程是2 * CPU个,无法修改,那么实际上被使用的event-loop线程只有1个,其他线程都是永远空缺着的。 vertical instances count和操作系统资源是紧密绑定的,对于服务端而言,CPU核数就是资源,因此servicecomb.rest.server.thread-count大于CPU核数就显得毫无意义了。但是操作系统还有其他的资源和处理,一个进程里面还会处理客户端网络调用, servicecomb.rest.client.thread-count增加,会分配更多的连接资源(句柄)。客户端的一个vertical instance和服务端一样,绑定到一个event-loop线程执行,不会改变。 Vertx就是利用了极小的线程池(2 * CPU),处理大量的并发请求(网络适配器、CPU、磁盘等)。着也就理解了为什么通常event-loop线程数固定不变,但是单纯看一个点,存在线程池冗余的情况。 总体来看,线程池是被合理的利用到其他地方了。
-
使用Mind Studio自带的脚本卸载,存在一堆残留进程
-
CSE JAVA SDK的线程池模型比较复杂,对于tomcat场景,以及Edge Service的vert.x场景,都有一个业务处理线程池(Edge Service的场景默认在reactive模式,是没有业务线程池的)。CSE设置的默认线程池的线程个数为2 * CPU个数。如果部分服务处理比较慢(比如评价时延>50ms),那么建议要设置一个较大的业务线程池,以提升吞吐量。如果所有接口都处理的很快,则不需要设置非常大的业务线程池,过多线程反而会因为线程调度,增加处理时延。如果一个微服务,有少量的几个接口处理非常耗时,需要考虑将这些接口放到独立的线程池执行(线程池隔离),防止访问慢的接口,影响访问快的接口。 线程池配置 (可以适当的抽时间学习下线程模型: https://bbs.huaweicloud.com/blogs/0a1a862f412611e89fc57ca23e93a89f) 通过配置项servicecomb.executors.default给业务接口制定执行线程池。配置项的的缺省值为servicecomb.executor.groupThreadPool,这个值是Bean的ID,CSE缺省的几个Bean ID如下: <bean id="cse.executor.groupThreadPool" class="org.apache.servicecomb.core.executor.FixedThreadExecutor"/> <alias name="cse.executor.groupThreadPool" alias="cse.executor.default"/> <alias name="cse.executor.groupThreadPool" alias="servicecomb.executor.groupThreadPool"/> <bean id="cse.executor.reactive" class="org.apache.servicecomb.core.executor.ReactiveExecutor"/> <alias name="cse.executor.reactive" alias="servicecomb.executor.reactive"/> 2. 通过servicecomb.executors.Provider.[servicename.schemaid.operationId]给某个具体的接口指定不同的线程池。
-
Google Chrome 中目前发现了一个新的 Bug,使用 JavaScript 创建一个循环,最终导致 Google Chrome 耗尽计算机上的所有 CPU 并使浏览器卡死。Google Chrome 错误报告中报告了这个 Bug,该报告指出,一旦用户访问该页面,CPU 利用率很快就会达到100%。这使得无法关闭 Google Chrome 选项卡、浏览器或正在使用计算机,直到 Chrome 进程结束。Google Bug报告访问下列的网址时,您将被带到这个 Bug 的页面,其标题为“Internet Security Alert! Code: 055BCCAC9FEC”。此页伪装成 Windows 错误标题“Internet Security Alert!代码:055BCCAC9FEC”,表明您的计算机已被感染,您应该拨打列出的电话号码以获取帮助。此页面包含的 JavaScript 将导致浏览器重复转到一个网址,然后 Google Chrome 返回按钮转到浏览器历史记录,然后再转到前进按钮返回原始页面。Javascript循环此循环让浏览器使用了计算机的所有 CPU 资源,如下面的 Chrome 任务管理器中所示。** CPU 利用率**这种高 CPU 利用率最终会导致浏览器冻结,计算机几乎无法使用。此时,关闭浏览器的唯一方法是 Windows任务管理器等工具,关闭 Chrome.exe 进程。问题在于,在关闭流程后重新打开 Chrome 后,它会提示你打开之前的页面。这将 Bug 页面重新打开,再次导致浏览器/计算机出现问题。重新打开Chrome因此,当 Bug 影响并终止浏览器进程时,请你不要允许 Chrome 恢复之前打开的页面。在 BleepingComputer 的测试中,同样的技术支持骗局不会影响Firefox。在 Firefox,遇到此 Bug 只需关闭选项卡和浏览器即可。原文链接: 开源中国
-
作者叶子是一位90后,天秤座,大数据&人工智能美女讲师。钟情创作,相信一切感受皆是生命的体验,坚持在朴素的文字中寻找生活的出路。是一位集才气于一身的大美女。【技术分享】我学习大数据有这样一个感悟:IT的智慧体现在算法上,而算法的灵感就来源于生活。什么意思,我们一起来看看MapReduce做离线计算到底是怎么一回事儿!要理解这个过程,我们先请出一个秘密武器:大家都玩过扑克牌吧?没有玩过至少见过吧?现在有两幅扑克牌无序的堆成一摞放在桌子上。四个人玩牌,玩牌之前呢,他们要看看每一种花色的牌是否完整?请问大家,用什么方式最快?——正确答案:把牌分成4摞,每个人拿一摞,拿到牌之后每个人把自己手里的牌按照红黑花梅的花色分堆,大家都分好之后再按照花色把四个人手中的牌整合到一起。红桃一摞,黑桃一摞,以此类推。到此为止,我们就已经成功的将两幅混乱的扑克牌按花色分成四摞了。然后呢,每个人去这四摞牌里面拿到一种花色,从最小排到最大,去清点自己手里的花色是否完整!哈哈,其实这就是一个离线计算的过程。离线计算的过程分为两个阶段,首先是Map的阶段,就是我们最开始的时候把混乱的扑克牌分成4摞,每个人去拿一摞将其一张一张的分开的过程就是Map。分开之后,我们检查花色,并且按照花色将其分堆,这就是一个Partition的过程。Partition完成之后呢?我们每个人的手上保存了4摞分好了花色的牌,这时候就进入了我们的Reduce阶段,进入Reduce阶段之后做些什么呢?首先要把每个人手里分好的牌按照花色整合到一起,然后再对整合好的每一摞牌进行检查。最后分别输出检查结果。我们具体拿一些数据来分析一下这个过程。OK,看这里,input是我们要处理的数据,这是一个文本文档。我们需要做什么呢?我们把它送到MapReduce模块里边,需要得到如右边所示的结果。统计出来每个单词出现的词数。MapReduce怎么做呢?既然是集群模式,我肯定要把任务分配给不同的服务器对吧?假设我现在把文件分成3块(文件怎么划分呢?),文件分成几个块,就会在集群当中启动几个Map进程。每个进程拿到一块数据,接下来它会怎么做呢?——正确答案:Map要对拿到的数据做一个处理,然后每个Map把处理结果交给Reduce,让Reduce去做一个统计,对吧?那么,Map先会将一行数据按空格键切分,变成若干个单词,然后单词每出现一次,计数为1,用一个键值对装起来。图片解析奉上~~~计算好之后呢Map还要做一件事情,在数据量很多的情况下,我们一般还会让Map做一个单词的统计。因为如果不做单词统计的话,它就会把这一堆<hello,1>,<world,1>,直接交给Reduce,所有Map的统计结果都要通过网络传输给特定的起Reduce进程的服务器,这样子的话会造成不同服务器之间数据传输的量很大。所以Map会把每一个单词出现了多少次统计出来,比如hello出现了1次,world出现了2次这样子。最后每一个Map都把自己手头的任务计算完毕了,就把结果存储起来,接下来就轮到Reduce上场啦!在Map存储结果的过程当中,Reduce就会被启动,Reduce启动以后会去拿Map处理的结果,当有多个Reduce的时候,Reduce不会把全部的结果都读取回来,而是只读取属于自己的分区,即分区Partition。什么叫做分区呢?分区就是对Map计算的结果做的一个分类,有多少Reduce,我就把结果分成多少类,也就是多少个分区。这是通过一个算法来完成的,这个算法是怎么回事,我们后面会做一个细节补充。我们先以4个Reduce为例(一般情况下Reduce的个数少于Map的个数),假设每一个不同的单词刚刚好对应一个不同的分区。那么Reduce拿到的数据就是我们图中所示的样子。Reduce对多个Map的计算结果做了一个整合,它还是一个一个的键值对,键是我们的单词,但是值呢变成了由每一个Map提交的计算结果组成的集合。Reduce要做的就是把这些集合里面的值加起来,得到最后的结果,也就是在整个文档里面,每个单词出现了多少次。这样说起来是不是很简单呢?因为还有很多的细节我留在了<下集>中跟大家补充哦!大家是否对MapReduce的具体执行流程开始感兴趣啦?个人订阅号“叶子的浅浅时光”,集文学作品和技术文章于一体。读者叹之:才学傲须眉,妙笔若行云。欲知详情如何,请听下回分解!
-
环境: 单板stm32F103VC keil5问题:现在编译和烧录都是好的,但是进程没有调度到,代码如下,如果正常的话,count的值会不停的累加,但是貌似没有进程没有调度起来。 有大神帮忙看看吗?(头文件不粘贴了)UINT32 g_TestTskHandle;int count = 0;VOID task1(void){ UINT32 uwRet = LOS_OK; while(1) { count++; uwRet = LOS_TaskDelay(1000); if(uwRet !=LOS_OK) return; }}UINT32 create_task1(void){ UINT32 uwRet = LOS_OK; TSK_INIT_PARAM_S task_init_param; task_init_param.usTaskPrio = 1; task_init_param.pcName = "task1"; task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)task1; task_init_param.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; uwRet = LOS_TaskCreate(&g_TestTskHandle,&task_init_param); if(uwRet !=LOS_OK) { return uwRet; } return uwRet;}int main(void){ UINT32 uwRet = LOS_OK; uwRet = LOS_KernelInit(); if (uwRet != LOS_OK) { return LOS_NOK; } uwRet = create_task1(); if (uwRet != LOS_OK) { return LOS_NOK; } LOS_Start();}上图中,已经走到了LOS_Strart了,表示create_task1的返回结果是正常的,然后count的值没有变化,跟踪了一下代码,发现los_dispatch_keil.S这个文件里面的两个函数有一个没有走到,如下图,走完了osTaskSchedule之后就跑飞了,(只知道汇编的位置,不知道对应的C代码是哪里见图中汇编部分),然后后面的osPendSV一直没有进来,请问有啥好方法可以快速定位到代码是在哪里卡主了吗?
-
MySQL 5.7 GA(wwwqsfanlicom)已经有很长一段时间了,经过测试评估,在5.7.16版本release之后,我们开始在生产线上规模部署,一个多月相安无事,心中窃喜,在部署了大约200+实例之后,天有不测风云,故障开始接二连三。某日,一个从库报OOM。该实例的innodb_buffer_pool_size = 40G,而系统内存是64G,怎么就能OOM了呢,先下线该实例,再看情况:1、机器内存: 基本快要跪了 total used free shared buffers cached Mem: 65808000 65492564 315436 0 1648 247284 -/+ buffers/cache: 65243632 564368 Swap: 2088952 2087852 11002、看谁是元凶:确认是mysqldPID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 28086 mysql 20 0 87.3g 61g 5192 S 21.2 97.7 28226:23 mysqld3、看MySQL监控:com_delete/innodb_rows_deleted : 29/9340 com_update/innodb_rows_updated : 155/9740 com_select/innodb_rows_selected : 299/39400该业务正常情况下是不可能出现这么大的innodb_rows值的,先stop slave,com_delete/com_update/com_select的值变0,但是innodb_rows值并没有降低,什么!!!现在已经没有任何写入了,怎么可能,诡异了。4、再看看LSN: 还在涨?5、再看看是否有事务在回滚(wwwqsfanlicom):确实有线程在rollback,但是该实例也没有什么大事务,stop slave都已经好久了,为什么还在回滚呢?6、pstack $mysqldpid看看线程都在干什么:从下图能看出都是在compress_gtid_table()里,难道和gtid compress有关系?**一段关于gtid compress的介绍: MySQL 5.7中新增了一个mysql.gtid_executed表,用于记录当前执行过的gtid,在binlog开启的情况下,当binlog retation的时候会唤醒一个内部线程对这个表的数据进行压缩合并。7、看下mysql.gtid_executed表的情况:果然是没有压缩,看来是在压缩这个表数据的时候出错了,然后产生了回滚操作。8、经过对比,最后确认是这个参数引起的:我们为了防止有DBA不小心在从库上执行SQL,给gtid_mode=on的复制模式留下隐患,将super_read_only设置成了on,为此,还特意修改了MHA的源码,以便检测和支持这个设置,结果人算不如天算,踩上了这个坑。将super_read_only 设置成0,当binlog retation后可以看到mysql.gtid_executed的compress恢复正常了,innodb_rows也正常了:
-
一、概要近期,出现一种新型挖矿病毒(ProtectionX),该病毒利用永恒之蓝安全漏洞,首次发现具备自我保护功能,与普通挖矿病毒有很大差异。感染主机主要是被用于挖矿,多表现为异常卡顿,严重影响主机性能和业务正常运行。该病毒使用了驱动保护,无法通过任务管理器中止病毒进程,查杀难度较高。请涉及威胁的租户根据自身业务情况,采取防护措施。二、威胁级别威胁级别:【严重】(说明:威胁级别共四级:一般、重要、严重、紧急。)三、影响范围开启了445端口SMB网络共享协议,未及时更新系统补丁或未采取终端安全防护措施的Windows系统(包括个人版和服务器版)。四、排查和处置方法排查方法:1.检查系统是否安装了最近系统漏洞补丁包;2.检查系统是否开启了445端口的SMB网络共享协议或者不必要的系统服务端口;3.检查内网是否有主机访问pool.minexmr.com:7777;4.检查系统是否存在异常运行的1sass.exe、wuauc1t.exe和win1ogon.exe进程;5.检查系统是否存在注册表项HKLM\software\microsoft\windows\CurrentVersion\Run\Registered font。处置方案:1.隔离感染主机:已中毒计算机尽快隔离,关闭所有网络连接,禁用网卡;2.切断传播途径:关闭潜在终端的SMB 445等网络共享端口,关闭异常的外联访问;3.查找攻击源:手工抓包分析或借助态势感知类产品分析,确认全网感染数量;4.查杀病毒:可使用以下工具进行查杀(http://edr.sangfor.com.cn/tool/SfabAntiBot.zip),或者可使用华为云防病毒工具进行查杀(推荐使用华为云市场软件);5.强制删除病毒程序:可以尝试使用PC Hunter强制删除并结束进程1sass.exe、wuauc1t.exe、win1ogon.exe;6.删除注册表项:HKLM\software\microsoft\windows\CurrentVersion\Run\Registered font;7.设置复杂密码:如果主机账号使用简单密码,建议重置为高强度的密码。五、安全建议1. 不从不明网站下载相关的软件,不要点击来源不明的邮件以及附件;2. 及时给电脑打补丁,修复漏洞;3. 修改密码:设置主机账号密码为高强度的密码;4. 对重要的数据文件定期进行非本地备份;5. 安装专业的第三方反病毒软件(推荐使用华为云市场软件);6. 关闭不必要的文件共享权限以及关闭不必要的端口,如: 135、139、445等。注意:修复漏洞前请将资料备份,并进行充分测试。
-
目录前言... 1从一次页面请求说起... 3浏览器运行机制... 3浏览器是多进程的... 3浏览器内核是多线程的... 4HTTP缓存... 6强制缓存... 7对比缓存... 7运行流程... 8DNS域名解析... 10TCP连接... 12HTTP请求与响应... 12页面渲染... 15关闭TCP连接... 16结束语... 17 前言 经常听到有人说,前端很简单,就是画画界面。好像也不无道理,只是还没有真正的去了解它,就像跑步一样,也确实很简单,但是你百米跑进十秒试试。只有对每一个动作都充分了解,才能把速度提上去,而且每进步一秒,都要付出更大的努力。简单的事情做到极致,就不简单了。其实前端并非想象中的简单,也有自己的一套庞大生态体系。下面是一张最新的前端知识体系图,长路漫漫,还需要潜心修炼才行。本文旨在带领大家进入前端的世界,不会讲解具体的HTML/CSS/JS的语法,也不涉及前端框架,而是帮助大家了解前端的运行机制,准确的说是浏览器页面加载的机制。只有充分的了解了前端,才能更好的优化我们的Web系统。对前端不感兴趣也没关系,就当是了解一下,后续还有《Web之旅-后端篇》带给大家。本文中部分内容参考《WebKit技术内幕》一书,感兴趣的童鞋可以研究一下。从一次页面请求说起先考大家一个问题:从打开一个URL到看到页面,中间都经历了什么?输入URL,加载资源,显示页面?没毛病,不过从前端角度来说,一般会经历下面几个过程:1) 在浏览器中输入URL并回车(当然,也可以直接点击URL超链接打开)2) 浏览器查找当前URL是否存在缓存,并比较缓存是否过期3) DNS解析URL获取对应IP4) 根据IP建立TCP连接(三次握手)5) 发送HTTP请求6) 服务器处理请求,浏览器接收HTTP响应7) 渲染页面8) 关闭TCP连接(四次挥手)那么这里的每一步又是怎么实现的呢?作为一名IT工作者,可能有些过程大家已经耳濡目染了,那就可以选择性的跳过啦。如果还不太了解,那也没关系,下面就开始我们的Web之旅-前端篇。首先第一步,输入URL?不不不,是打开浏览器。是的,你没看错,作为此次Web之旅的主办单位及赞助商,在发车之前,浏览器的运行机制,确定不先了解一下么。浏览器运行机制首先申明,下面要讲述的是Chrominum浏览器的架构模型,不排除个别浏览器特立独行哦。浏览器是多进程的 当我们启动浏览器的时候,默认就启动了一个进程(进程和线程的概念就不再科普了),作为主进程,并从系统中获取资源(CPU、内存)。每当我们打开一个tab页签,就会另起一个新的进程(某些情况下多个tab会合并进程)。那么浏览器到底包含哪些进程呢?下面列举了一些主要进程:1) Browser进程:浏览器的主进程(负责协调、主控),只有一个。a. 负责浏览器界面显示,与用户交互。如前进,后退等b. 负责各个页面的管理,创建和销毁其他进程c. 将Renderer进程得到的内存中的Bitmap,绘制到用户界面上d. 网络资源的管理,下载等2) 第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建3) GPU进程:最多一个,用于3D绘制等4) 浏览器内核(渲染进程)(Renderer进程,内部是多线程的):默认每个Tab页面一个进程,互不影响。主要用来进行页面渲染、脚本执行以及事件的处理那么Browser进程和浏览器内核(Renderer进程)的通信过程是怎样的呢?引用Chromium浏览器的代码层次结构图:从WebKit接口层到用户界面的路径1) Browser进程收到用户请求,首先需要获取页面内容(比如通过网络下载资源),随后将该任务通过RendererHost接口传递给Render进程。2) Renderer进程的Renderer接口收到消息,简单解释后,调用相应的WebKit接口层,进行渲染,并将Webkit处理后的结果发送回去3) Browser进程接收到结果并将结果绘制出来作为前端开发,我们需要重点关注一下浏览器内核进程,也是渲染页面所需要的。浏览器内核是多线程的 每一个tab页面可以看作是一个浏览器内核进程,内核进程是多线程的,主要包含下面几大类线程:1) GUI渲染线程a. 负责渲染浏览器界面,解析HTML(SVG/XHTML)和CSS,构建DOM树和Render树,并进行布局和绘制等操作。b. 当界面需要重绘(Repaint)或由于某种操作引发重排(Reflow)时,该线程就会执行c. 注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。2) JS引擎线程a. 也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)b. JS引擎线程负责解析Javascript脚本,执行代码。c. JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(Renderer进程)中无论什么时候都只有一个JS线程在运行JS程序d. 同样注意,GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染阻塞。3) 事件触发线程a. 归属于浏览器而不是JS引擎,用来控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)b. 当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件线程中c. 当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理d. 注意,由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行)4) 定时触发器线程a. 传说中的setInterval与setTimeout所在线程b. 浏览器定时计数器并不是由JS引擎计数的,因为JS引擎是单线程的,如果处于阻塞线程状态就会影响计时的准确性。因此通过单独线程来计时并触发定时任务(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)c. 注意,W3C在HTML标准中规定,要求setTimeout中低于4ms的时间间隔算为4ms。5) 异步http请求线程a. XMLHttpRequest在连接后是通过浏览器新开一个线程进行异步请求b. 当检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件放到JS引擎的处理队列中等待处理。c. 在发起了一个异步请求时,http请求线程则负责去请求服务器,有了响应以后,事件触发线程再把回调函数放到事件队列当中。d. 大部分浏览器支持6个左右的并发请求(并发数是针对同一域名的),超过限制数目的请求会被阻塞。浏览器这块先介绍到这里,至于浏览器内核(渲染进程)具体是怎么工作的,各线程之间是怎么配合的,我们到页面渲染那一章节再详细介绍。好了,参观完浏览器,现在是不是可以出发了呢?还不行,下面我们要验票了,已经参加过web之旅的童鞋可能就不需要再次参加了。HTTP缓存 HTTP缓存有多种规则,根据是否需要向服务器发起请求,可以分为两大类:强制缓存和对比缓存。强制缓存如果生效,不再需要和服务器发生交互,而对比缓存不管是否生效,都需要与服务端发生交互。两类缓存规则可以同时存在,而强制缓存优先级高于对比缓存,也就是说,当执行强制缓存的规则时,如果缓存生效,直接使用缓存,不再执行对比缓存规则。和缓存规则相关的配置信息均存在于Http报文的请求头里。强制缓存强制缓存规则主要通过Cache-Control字段进行描述,而早先的HTTP1.0中使用的是Expires字段,以及古老的IE中支持的Pragma字段(这里就不细说了),为了保证兼容性,这些旧的字段还是会用到的。1) Expires:值为服务端返回的到期时间,是一个绝对时间。浏览器检查当前时间,如果还没到失效时间就直接使用缓存文件。估计大家已经想到了一个问题:当服务器时间与客户端时间不一致时,这种方式就会产生误差。所以从HTTP1.1版开始,使用Cache-Control来代替Expires。2) Cache-Control:用于定义所有的缓存机制都必须遵循的缓存指示,这些指示是一些特定的指令,包括public、private、no-cache、no-store、max-age、s-maxage以及must-revalidate等。其中的max-age保存一个相对时间。例如Cache-Control: max-age = 484200,表示浏览器收到文件后,缓存在484200s内均有效。当同时设置了上述三种规则时(包括Pragma),浏览器按照Cache-Control、Expires、Pragma的顺序进行覆盖处理。对比缓存强制缓存决定客户端是否向服务器发送请求,缓存判断生效,则直接从本地缓存读取数据,缓存失效,则需要向服务器发送请求。那么这时的资源是否真的已经发生了变化呢?如果没有变化,再把数据重传一遍岂不是会浪费带宽和时间。为了让客户端与服务器之间能实现缓存文件是否更新的验证,提升缓存的复用率,HTTP1.1新增了两种规则:Last-Modified以及ETag。一个是对比最后更新时间,一个是对比内容变化(如MD5值)。1) Last-Modifie:服务器将资源传递给客户端时,会将资源最后更改的时间以“Last-Modified: GMT”的形式加在响应头上一起返回给客户端。客户端会为资源标记上该信息,下次再次请求时,会把该信息附带在请求报文中一并带给服务器去做检查,若传递的时间值与服务器上该资源最终修改时间一致,则说明该资源没有被修改过,返回304状态码知会客户端直接使用本地缓存即可。否则以常规GET 200回包形式将新的资源(包括新的Last-Modified时间)返回给客户端。相关报文头字段:If-Modified-Since 和 If-Unmodified-Since。可能细心的小伙伴又要问了,如果只是更新了时间,内容没有发生变化呢?为了解决这个困扰,HTTP1.1还增加了ETag规则。2) Etag:服务器会通过某种算法,给资源计算出一个唯一标志符(比如md5值),在把资源返回给客户端的时候,会在响应头加上“ETag: 唯一标识符”一起返回给客户端。客户端保留该 ETag 字段,并在下一次请求时将其一并带给服务器。服务器只需要比较客户端传来的ETag跟自己服务器上该资源的ETag是否一致,就能很好地判断资源相对客户端而言是否被修改过了。如果服务器判断ETag是一致的,直接返回304状态码知会客户端直接使用本地缓存即可。否则以常规GET 200回包形式将新的资源(当然也包括了新的ETag)发给客户端相关报文头字段:If-None-Match 和 If-Match3) 如果同时指定了Last-Modifie和ETag字段,那么需要同时校验这两个规则。运行流程讲了这么多概念,是不是有点大脑缺氧呢,这到底是怎样一个运行流程呢?下面就通过一张图来回顾一下HTTP的缓存机制: 到这里,大家对HTTP的缓存机制应该有了清晰的认识了吧,下面我们放松一下,探讨一个比较有趣的话题:你知道浏览器里的回车(转到)和刷新(F5)有什么区别么?对,按键不同,还有呢?简单的说:1) 回车保证了原有的缓存规则不变,即在 强制缓存有效的时候,是不会去请求服务器的,打开调试看到的请求也只是伪造的,比如 谷歌浏览器可能显示 200(from cached),其实并没有发起实际的请求,而是直接读取了本地缓存。2) F5则会跳过 强制缓存,只有Last-Modified/ETag起作用,如果服务器比较后返回 304,再去本地缓存中读取,返回200则使用服务器返回的资源。但是浏览器依然会保留之前的一些变量的值,所以可能会造成页面刷新后,网页出现错误,甚至打不开的情况。3) 那么如果想完全抛弃本地缓存怎么办?Ctrl+F5!此时请求头会发送 Cache-Control: no-cache,告诉浏览器,我不要缓存中的文件了,直接从服务器获取文件,此时缓存完全失效。是不是很有意思呢,一般人我都不告诉他的。好了,那些已经参加过Web前端之旅的乘客,你已经被浏览器的强制缓存检测到了,请前往浏览器工作室进行页面的渲染。剩下的乘客请前往候车室,并耐心在座位等待。什么?为什么还不出发?因为导游要确定一下行程,你说去www.webzhilv.com ,除非是老司机,要不怎么知道具体在哪呢?没关系,我们正在查询线路网系统:DNS域名解析。DNS域名解析 关于域名解析,想必大部分童鞋都有所了解的,我们在地址栏输入的域名并不是最后资源所在的真实位置,域名只是与IP地址的一个映射。网络服务器的IP地址那么多,我们不可能去记一串串的数字,因此域名就产生了,域名解析的过程实际是将域名还原为IP地址的过程。 域名解析的过程,大体会经历下面几个步骤:1) 浏览器检查自身的缓存中有没有这个域名对应的解析过的IP地址,如果有,就使用这个IP。浏览器域名缓存在数量和时间(TTL)上都是有限制的,合理的设置才能保证域名的正常解析。小窍门:在浏览器中输入chrome://net-internals/#dns可以查看当前缓存的域名信息哦。2) 查找操作系统缓存即本地hosts文件,如果hosts文件中有相应的域名映射记录,则使用对应的IP地址。温馨提示:要当心恶意程序修改你的hosts文件来把特定的域名解析到它指定的IP地址上,导致这些域名被劫持。3) 当前面步骤都无法完成域名解析时,就要请求本地域名解析器(LDNS)来解析了。那么怎么知道域名服务器在哪呢?这个就是操作系统网络配置中的DNS服务器地址了。4) 如果LDNS仍然没有解析到,就直接到Root Service域名解析器请求解析。5) 根域名服务器返回给本地域名服务器一个所查询余的主域名服务器(gTLDServer)地址。gTLD是国际顶级域名服务器,如:.com/.cn/.org等,全球只有13台左右。6) 本地域名服务器再向gTLD服务器发送请求。7) 接收请求的gTLD服务器查找并返回此域名对应的Name Server域名服务器的地址,这个Name Server通常就是你注册的域名服务器(如你的域名供应商)。8) Name Server域名服务器会查询存储的域名和IP的映射关系表,正常情况下都根据域名得到目标IP记录,连同一个TTL值返回给DNS Server域名服务器。9) 返回该域名对应的IP和TTL值,本地域名服务器会缓存这个域名和IP的对应关系,缓存的时间有TTL值控制。10) 把解析的结果返回给用户,用户根据TTL值缓存在浏览器缓存中,域名解析过程结束。经过这么一系列查询,总算知道目的地在哪了,可以出发了吧。什么?还不行?奔溃中...为了大家安全着想,我们需要先向目的地发信息确认一下,路线是否畅通,是否有工作人员接站,要不然就有去无回了。先来个三次握手(TCP连接)吧。TCP连接在获取到服务器的IP地址后,便会开始建立一次连接,这是由TCP协议完成的,主要通过三次握手的方式建立连接:1) 第一次握手: 建立连接时,客户端发送SYN包(syn=i)到服务器,并进入SYN_SENT状态,等待服务器确认。2) 第二次握手: 服务器收到SYN包,必须确认客户的SYN(ack=i+1),同时自己也发送一个SYN包(syn=j),即SYN+ACK包,此时服务器进入SYN_RECV状态。3) 第三次握手: 客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=j+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。经过三次握手之后,我们就可以放心的出发了。NO NO NO,还要稍等片刻(估计大家已经崩溃了吧),先检查下火车头及车厢是否准备就绪(也就是封装HTTP消息头和消息体)。HTTP请求与响应 先来科普一下:HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW)服务器传输超文本到本地浏览器的传送协议。HTTP基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件,查询结果等),是一个属于应用层的面向对象的协议。 HTTP请求报文由三部分组成:请求行、请求报文头、请求报文体。下面是一个实际的请求报文: HTTP请求行包括请求方法、请求URL和HTTP协议及版本。1) GET和POST是最常见的HTTP请求方法,除此以外还包括DELETE、HEAD、OPTIONS、PUT、TRACE。2) 请求URL和报文头里的HOST属性拼接组成完整的请求URL。3) 当前使用的协议是HTTP/1.1版本,在此之前还有HTTP/0.9和HTTP/1.0。那么HTTP/1.1和HTTP/1.0有哪些区别呢?a. HTTP/1.1则默认支持长连接,HTTP/1.0中每对请求/ 响应都使用一个新的连接。b. HTTP/1.1在请求消息头多一个Host域,HTTP/1.0则没有这个域。c. HTTP/1.1增加了带宽优化的一些字段:比如range头域、100响应码、Content-Encoding等,具体细节在后续的优化篇中再详细介绍。d. HTTP1.1增加了OPTIONS、PUT、 DELETE、TRACE、CONNECT请求方法。e. HTTP/1.1中新增了24个状态响应码。HTTP请求报文头,以明文的字符串格式传送,是以冒号分隔的键/值对,如:Cache-Control: no-cache,每一个消息头最后以回车符(CR)和换行符(LF)结尾。HTTP消息头结束后,会用一个空白的字段来标识,这样就会出现两个连续的CR-LF。结构大体如下图所示:我们前面在介绍HTTP缓存时提到的Cache-Control字段,就位于请求报文头里。此外常见的HTTP请求报文头属性还有Accept、Cookie、Referer、Connection、Host、Content-Type等等。详细的报文头属性这里就不再介绍了,感兴趣的童鞋可自行查阅。Content-Type用来表示请求体数据的媒体类型信息,常见类型有application/json、text/xml以及application/x-www-form-urlencoded。浏览器负责发送HTTP请求,同时也接收返回的HTTP响应信息。HTTP响应报文同样由三部分组成:响应行、响应头和响应体。下面是一个实际的HTTP响应报文:响应行包含协议版本信息以及状态码和状态描述信息。HTTP响应状态码由5段组成:1) 1xx 消息,一般是告诉客户端,请求已经收到了,正在处理,别急...2) 2xx 处理成功,一般表示:请求收到、我明白你要的、请求已受理、已经处理完成等信息.3) 3xx 重定向到其它地方,它让客户端再发起一个请求以完成整个处理。4) 4xx 处理发生错误,责任在客户端,如客户端的请求一个不存在的资源,客户端未被授权,禁止访问等。5) 5xx 处理发生错误,责任在服务端,如服务端抛出异常,路由出错,HTTP版本不支持等。响应头结构和请求头一样,常见报文头属性有:Cache-Control、ETag、Location、Set-Cookie、Content-Type等。响应体则是服务器返回的数据了,可能是一个HTML页面,一个图片或者一段JSON数据。HTTP请求报文生成后,总算是可以出发了,祝大家一路顺风!HTTP请求发出之后,就交由指定的后台服务来进行处理(Web服务器或者反向代理服务器等),具体的处理过程,我们会在后续的《Web之旅-后端篇》中再详细介绍。终于来到了大家最感兴趣的环节,估计看了前面那么多繁琐的步骤,已经脑阔疼了吧。建议休息五分钟,然后再来看下浏览器获取到HTML页面后,是怎么一步步把界面渲染出来的。页面渲染在前面浏览器运行机制章节,我们有提到,浏览器是多进程的,每打开一个tab页就会创建一个新的进程,也就是渲染进程。渲染进程又是多线程的,各个线程之间相互协作,共同完成页面的渲染工作。那么各个线程是怎样的一个分工呢?简单来讲,GUI渲染线程按照从上到下的顺序解析HTML文件,当遇到任何样式(link、style)与脚本(script)时,就会调用异步请求线程去加载资源。加载到的CSS交给GUI渲染线程继续处理,JS文件则交由JS引擎线程去解析执行。当JS引擎线程解析遇到事件(如Ajax异步请求)时,提交任务给事件触发线程,由事件触发线程判断触发条件是否满足,满足时再交由JS引擎线程处理。对于setInterval和setTimeout方法,定时计数交给定时触发器线程处理,计时完毕后再交由JS引擎处理。从页面的渲染角度来讲,大概可以划分成以下几个过程:1) 解析HTML/SVG/XHTML,构造DOM树。Webkit中有三个C++的类来处理这三类文档,解析后会产生一个DOM树。2) 解析CSS构造CSS规则树。3) 解析JS,通过DOM API和CSSOM API 来操作DOM树和CSS规则树4) 通过DOM树和CSS规则树构造Render树,计算各元素尺寸和位置,即Layout/Reflow的过程。DOM树与HTML一一对应,而Render树会忽略诸如head、display:none的元素,并且附加CSS规则到Render树的每个节点(Element)上。5) 绘制Render树(Paint),绘制页面像素信息6) 浏览器会将各层的信息发送给GPU,GPU会将各层合成(composite),显示在屏幕上。整个解析过程,默认采用同步的方式进行。当解析到外部资源(CSS、JS)时,浏览器会启用异步请求线程去加载资源。如果是CSS资源,资源加载不会阻塞DOM树的解析,但是要在CSS加载完成后,才能构造Render树。如果CSS加载不阻塞render树渲染的话,那么当CSS加载完之后,Render树可能又得Repaint或者Reflow了,这就造成了一些没有必要的损耗。什么是Repaint和Reflow呢?Repaint(重绘):部分节点需要更新,但不改变其他集合形状。如改变某个元素的颜色是,就会发生重绘。Reflow(重排):Render树的部分更新,如尺寸变化,就会发生重排。为提高页面的加载速度,我们要尽量的避免页面的Repaint和Reflow操作。如果解析遇到外部JS资源,资源加载将阻塞DOM树的解析,直到JS解析完成后,再继续往下解析。这是因为JS是可操纵DOM的,如果在修改这些元素属性同时渲染界面(即JS引擎线程和GUI线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。因此为了防止渲染出现不可预期的结果,浏览器设置GUI渲染线程与JS引擎线程为互斥的关系,当JS引擎执行时GUI线程会被挂起,GUI更新则会被保存在一个队列中等到JS引擎线程空闲时立即被执行。所以如果JS执行时间过长,就会阻塞整个页面的渲染,我们要尽量避免这种情况,比如把JS脚本应用放到HTML的最后(</body>之前)。那如果耗时操作必不可少呢,别担心,JS里有一个叫Worker的类,可以帮助我们实现类似多线程的操作,感兴趣的童鞋可以去了解下。当然,JS也可以采用异步加载的方式,如HTML5在<script>增加的async和defer属性,可以让浏览器异步去下载并执行JS,而不阻塞页面的渲染。异步加载原理基本上都是向DOM中写入script或者通过eval函数执行JS代码,可以把它放在匿名函数中执行,也可以在onload中执行,也可以通过XHR注入实现,也可以创建一个iframe元素,然后在iframe中执行**JS代码。但是异步执行需要自行判断指定JS文件是否会对页面的渲染造成影响,否则会出现渲染异常的情况。这次旅程差不多到这里就要结束了,是时候挥手告别了。关闭TCP连接 建立TCP连接需要三次握手,关闭TCP连接则需要四次挥手。 第一次挥手是浏览器发完数据后,发送FIN请求断开连接。第二次挥手是服务器发送ACK表示同意,如果在这一次服务器也发送FIN请求断开连接似乎也没有不妥,但考虑到服务器可能还有数据要发送,所以服务器发送FIN放在了第三次挥手中。最后浏览器返回ACK表示同意,也就是第四次挥手。结束语 首先恭喜大家完成了此次的web前端之旅,通过这次旅程,大家应该对前端的整个加载机制有了初步的了解,如果还意犹未尽,可以参考《WebKit技术内幕》一书进行深入学习和研究。 同时我们也看到了,在整个页面的加载机制中,有很多复杂繁琐的步骤。而浏览器也已经做了很多的优化工作,那么对于前端开发来说,如何才能快速的获取和展示出我们想要的数据呢?下一篇文章《Web之旅-前端优化篇》,将针对每一个步骤,阐述如何进行优化,以达到极致体验。敬请期待。
上滑加载中
推荐直播
-
OpenHarmony应用开发之网络数据请求与数据解析
2025/01/16 周四 19:00-20:30
华为开发者布道师、南京师范大学泰州学院副教授,硕士研究生导师,开放原子教育银牌认证讲师
科技浪潮中,鸿蒙生态强势崛起,OpenHarmony开启智能终端无限可能。当下,其原生应用开发适配潜力巨大,终端设备已广泛融入生活各场景,从家居到办公、穿戴至车载。 现在,机会敲门!我们的直播聚焦OpenHarmony关键的网络数据请求与解析,抛开晦涩理论,用真实案例带你掌握数据访问接口,轻松应对复杂网络请求、精准解析Json与Xml数据。参与直播,为开发鸿蒙App夯实基础,抢占科技新高地,别错过!
回顾中 -
Ascend C高层API设计原理与实现系列
2025/01/17 周五 15:30-17:00
Ascend C 技术专家
以LayerNorm算子开发为例,讲解开箱即用的Ascend C高层API
回顾中
热门标签