命令测试post_【第2088期】前端中台化,把格局做大——NodeJS 和测试服务探索

前言

今日早读文章由《React状态管理与同构实战》作者@LucasHC投稿分享。

正文从这开始~~

近些年,「NodeJS 应该如何在公司业务中真实落地 」这类问题屡见不鲜。自从 2009 年 NodeJS 诞生之后,抢尽风头,圈粉无数。但一定有工程师不禁要质疑「NodeJS 真的已经开辟天地,占据架构体系的一席之地了吗」,「国外听说 NodeJS 开展如火如荼,国内现在到底是个什么状态」,「听到过阿里 NodeJS 扛下双十一,到底是什么情况」

没错,风头越大,质疑也就越多。当争议和浮华褪去,技术的落地:就让上帝的归上帝,撒旦的归撒旦。本系列文章,我将会梳理 NodeJS 在我司以及在国内外其他团队的典型项目案例,并深入探讨 NodeJS 的发展前景和最佳实践。

开篇小茶歇

本篇文章内容较长,涉及到了:端到端测试,NodeJS 服务,中台能力(docker 镜像等基础设施),基于图片比对的插件实现等。

命中注定的缘分 —— 当 NodeJS 遇见端到端测试困局

端到端测试,也叫做 UI 测试,e2e 测试。用白话说,类似常见的自动化测试,它站在用户使用的角度,并基于协议或者其他技术手段,打开真实浏览器,与浏览器中页面交互。

端到端测试有着肉眼可见的优势,比如:项目经过不断的开发,最终肯定会趋于稳定,在适当的时机引入端到端测试能及早发现问题,进而保证产品的质量。这种让软件代替人工,实施快速、反复的测试,收益非常明显。有人总结出端到端收益公式(出处:测试人员的 “救命稻草”):

端到端收益 = 迭代次数 全手动执行成本 - 首次自动化成本 - 维护次数 维护成本

即便收益明显,且相关领域工具层出不穷,但端到端测试的落地实施目前并不广泛。有条件接入端到端测试的团队,端到端测试似乎也没有扮演到应有的角色,一直难以发挥出最大化作用。其原因除了“项目特点是否适合”以外,我认为还和端到端测试在开发上线流程中进行接入的阶段有密不可分的关系。

具体来说,相当多的团队会将端到端测试放到本地执行,和项目代码强耦合。比如,本地通过 npm script 脚本来实施端到端测试。端到端测试需要保证最新待测试页面的可访问性,因此相关脚本需要优先保障本地服务的成功搭建。以 npm run e2e 这样的 npm script 为例,相关流程如下图:

3d529421f92f4a681cd8455f233f2b81.png

本质上这是一种“按心情”执行。一般需要开发者在本地开发完毕之后,自觉执行脚本并观察端到端测试结果。“按心情”的事情,自然是无法正规化、流程化、平台化的,注定是比较鸡肋的存在。

顺着上述思路,我们可以想到:借助 huskey,将上述端到端测试放到 pre-commit 或者 pre-push 阶段强制执行。这样一来我们使得端到端测试流程化,将“按心情”执行改为了强制执行。

但进一步思考,在 pre-commit/pre-push 阶段执行的弊端也很明显:增加了额外的 git hooks,延长了代码提交流程,直接影响到了上线效率。如果是一个 hot-fix 紧急修改 bug,这样的时间殇是我们无法接受的。同时,本地阶段执行端到端测试的一个前提就是先要保证本地服务的可用性,暂且不谈开启本地服务的时间开销,一个更尴尬问题就在于:本地服务和线上环境是有天然差别的,本地执行的端到端测试难以幂等于线上真实效果。

基于上述情况,端到端测试在团队技术体系中,要么渐渐地成为一个“漂亮的玩具”,华而不实;要么就是一个开发者“眼见心烦的累赘”,最终沦为鸡肋。

这么看来,端到端测试想要破局并突破,势必应该在执行流程上进行创新。为此,我们认为:端到端测试应该搬到“容器”上进行,融合到 CI/CD 阶段实施,彻底做到自动化、服务化。

这里插入一个知识点:什么是 CI/CD 阶段呢?

它们都是现代互联网应用编译和发布流程当中的常用词语,分别对应:持续集成(Continuous Integration)和持续部署(Continuous Deployment),实际上我们还有一个持续交付(Continuous Delivery)的概念,这里不再详细展开,我们来聚焦到持续集成和部署。

在持续集成环境中,开发人员将代码提交到主干 master,并触发 Gitlab 的 hook,进而自动推进代码的编译。不同的团队对持续集成阶段的定义也许会有略微不同,但是并不妨碍我们理解。我司在持续集成阶段主要完成:构建项目流程。具体来说,在这个阶段中台团队使用基础镜像启动容器,拉取最新代码,安装必要依赖,执行单测脚本,并最终 commit 出下一阶段(持续部署阶段)的镜像。

在持续部署阶段,中台使用构建阶段(持续集成阶段)产出的镜像,启动容器,按照一定 pipeline 流程,串行发布最新版本应用,最终启动服务。

了解 CI/CD 的概念之后,将端到端测试后置到 CD/CD 阶段,并在真实容器中执行——这似乎是一个很好的尝试和创新。

NodeJS 实现端到端服务 —— 想说爱你不容易

截止为此,根据我们的“容器中执行端到端测试服务并接入 CI/CD”的设计思想,我们可以画出来一个简单的流程分析。

3833310f822bf773ee981b1887875bda.png

由上图,衍生出第一个问题:我们应该将端到端服务接入到 CI 阶段还是 CD 阶段呢?

按照常理:

CI 阶段应该重视测试验证结果,以保障所有的提交在部署前的质量,对可能出现的一些问题进行预警;

CD 阶段应该没有人为干预,只有当一个修改在工作流 pipeline 中构建失败才能阻止它部署到产品线。

但是,端到端测试需要保证具有一个可访问的最新版本应用地址,而 CI 阶段在我司只是进行代码的编译和容器基础镜像的生成,并不会开启应用服务,因而不具备端到端测试所需的地址。我们当然可以“改造” CI 阶段,新启动一个新的进程,进行应用服务的启动,但这样的做法显然粗暴而不合理。

同时 CD 阶段我司在金丝雀过程之前,有一个“办公室阶段”(下文统一使用办公室阶段/办公室环境一词),即:办公室内(公司内网环境下)可全量访问新版本应用。也就是说公司内网下访问线上地址:www.a.com/b,网关会将该流量全部…

综合考虑,对于我司来讲,在这个“办公室”阶段,应该是最好执行端到端测试的时间点。一旦端到端测试无法通过,将会中断部署交付流程。

2f6f9d5553e829bce5c7e502e7684042.png

这样一来,就解决了全量可测页面的访问性问题,同时端到端测试的环境完全和线上环境保持一致。

任何一个创新型项目的开展之路,都注定曲折坎坷。设计先行,但在实施过程中,我们还是遇见了较多的阻力和难点。主要问题集中在端到端框架和中台容器的贴合性、一致性上。下面我举一些典型例子来进行说明。

融入社区,反推框架的进步和完善

我们选用了目前业界最为流行和活跃的 Cypress 作为端到端测试框架,关于不同端到端框架的对比和技术实现原理这里不再赘述,感兴趣的同学可以关注我们的博文,后续将会专门进行解剖。

整体端到端服务流程并不复杂,如下图:

cc6000f8151e8474f7039f51200621f5.png

这只是一个极简的图示,粗略地表现了在相关代码 MR(merge request)成功构建,并部署到办公室环境时,中台请求我们的端到端测试服务开启接口。

这就存在了第一个难题:我们发现,在办公室部署完成之后,端到端服务接收到 post 请求,执行 cypress.run(),总会得到报错:Cypress binary is not installed。为什么本地就能顺利执行,到了容器上,开启 NodeJS 服务之后就会得到报错呢?

翻看 Cypress 代码实现,究其原因非常有趣,Cypress 会在 npm post-install 过程安装 Cypress binary 到容器系统路径下,post-install 是 npm 的一个 hook,它会在 npm install 成功执行后触发。在执行 cypress.run() 时,Cypress 会先执行 cypress.verify() 验证 Cypress 的可用性,其中一个验证标准就是检查系统路径下是否存在 Cypress binary。

那为什么我们容器上就找不到 Cypress binary 呢?我依然用图示还原案发现场:

5ec3549ce4cc8d19ef278a4a5963fff1.png

在第一次构建时,我们的构建脚本执行 npm install,并成功触发 npm post-install,Cypress 将 Cypress binary 安装在容器系统路径:~/.cache/Cypress 当中。

第二(N)次构建时,面对一个“全新”的空容器,中台为我们缓存了 node_modules,因此 npm install 并不会真正下载依赖,post-install 的 hook 也不会触发,也就不存在“Cypress 将 Cypress binary 安装在容器系统路径:~/.cache/Cypress 当中”这一动作。进而执行时,得到了 Cypress binary is not installed 的报错。

解决方案也不难,我的第一个直观想法是构建脚本当中的 npm install 改为 npm ci, 这里插入一下 npm ci 和 npm install 的区别:

  • npm ci 需要项目必须要含有 package-lock.json 或者 npm-shrinkwrap.json 文件

  • 如果上述两种 lock 文件和 package.json 声明的依赖产生冲突,npm ci 命令会强行退出,并报错,而 npm install 命令会更新 lock 文件

  • npm ci 命令会全量安装项目所有的依赖,无法添加单独依赖项目

  • 如果项目中已经存在 nodemodules,npm ci 命令会删除 nodemodules 文件,并重新安装

  • npm ci 命令不会写 package.json 内容以及 lock 文件内容

因此不难看出,在构建阶段,本就应该使用 npm ci 命令,这也是 npm ci 命令命名的由来。

但使用 npm ci 和中台缓存 node_modules 的行为又相矛盾,无可避免地增加了构建的耗时。在任何公司的构建部署系统中,npm ci 安装依赖的时间一定会是不可忽略的大头之一。

有没有更“优雅”的方法呢?我坚信“ PR makes world better”。让我们回到本质,核心问题在于「中台缓存了 nodemodules,导致 post-install 无法触发,进而无法安装 Cypress binary 到容器系统路径」,如果我们也能缓存 Cypress binary 到指定路径,且在执行 cypress.run() 以及 cypress.verify() 时,让 Cypress 去设定的缓存路径下找 Cypress binary 是不是就能解决问题。那么这个”缓存路径“当然就是 nodemodules 文件下的某个路径即可(因为中台缓存了 node_modules 文件)。

总结一下,关键点在于:

  • Cypress 需要新增可配置环境变量,用于指明 Cypress binary 的安装路径

  • 我们设置环境变量 CYPRESSCACHEFOLDER 为 ./node_modules/.cache/cypress/

  • cypress.run() 触发 cypress.verify() 执行时,去 CYPRESSCACHEFOLDER 指定的路径下查找 Cypress binary 是否存在

此时整体流程如图:

6e753483c0d15caa1228484a88fdf673.png

对于增加配置环境变量,使得容器环境执行 Cypress 更加灵活的提议,当然也得到了 Cypress 官方的认可,此问题暂告解决。同时,对于 Cypress 本身体积较大,安装耗时且不稳定的问题,我们同样使用一个 CYPRESSINSTALLBINARY 环境变量指明默认的 Cypress 软件下载地址。我们在公司内网保存一份,内网下载 Cypress 既迅速又可靠。最终的构建部分脚本如下 (采用 yml 格式,不影响读者理解):

build:

# export cypress variables

- export CYPRESS_CACHE_FOLDER=node_modules/.cache/Cypress&& export CYPRESS_INSTALL_BINARY=http://内网地址/cypress.zip

## application build

- yarn

- yarn build

其中可见在执行依赖安装(yarn)和构建项目(yarn build)之前,我们声明并导出了相关环境变量。

前端和中台化 打通基于 Cypress 的 NodeJS 服务任督二脉

解决了 Cypress binary 安装问题,我们在执行过程中遇到的第二个问题也很有趣。在 cypress.run() 执行时,得到报错信息,“CI stage dependency missing in docker”,经过和官方团队的讨论:

7458276cf02537c1a1ddabdaa1de0fd3.png

我们严重怀疑容器上执行 Cypress 出错的原因在于:容器系统版本过低。中台当前提供的容器系统版本均为:Debian 8.2(jessie),NodeJS v10.14.0,即 docker 基础镜像声明为:baseimage: nodejs/v10.14.0jessie (debian 8)。为此,我们组织中台团队以及公司内部安全组进行沟通,并制作出加入了安全包的新版本 baseimage: nodejs/v12.13.0stretch (debian 9)的基础镜像,供项目容器使用。

基础镜像的升级并不是简单制作一个镜像那么简单,其中涉及到较多“技术之外”的探索和磨合,这里我们不过多展开。总之,中台团队的存在对于各种类型 NodeJS 应用/服务的落地和发展至关重要。同时中台方面涉及到的能力是传统前端开发所欠缺的。因此,项目推动能力,跨团队沟通能力也是 NodeJS 发展甚至任何一项前端技术都不可忽视的一环。

此外 Cypress 作为一个复杂的端到端测试框架,它本身需要很多系统级的依赖,比如 Xvfb(is an X server that can run on machines with no display hardware and no physical input devices/虚拟屏幕虚拟输入设备)等,这里梳理总结一下必备系统依赖包包括:

  • xvfb

  • libgtk-3-dev

  • libnss3

  • libxss1

  • libasound2

  • xz-utils

到此为止,简要总结一下“端到端测试上容器”这一过程遇见的关键问题以及解决方案:

  • Cypress binary 安装问题:提 PR 解决,提供 Cypress binary 缓存安装路径

  • Cypress 安装超时且不稳定:提 PR 解决,提供内网获取路径,从内网下载

容器系统不兼容:制作镜像并推动中台升级容器系统基础镜像

当然以上问题并不是全部,但极具代表性,也能总结出任何一个前端团队在公司内推广落地新技术时可能会遇见的问题。具体的挫折可能来自 NodeJS 服务自身,也可能来自于和已有技术体系的不兼容,解决方案有技术方向的努力,也有项目推动方向的尝试。

到此,我们涉及了服务粗略设计以及基础环境的搭建。接下来,我将重点介绍一下容器化端到端测试服务的技术体系架构设计。

一个完善、易扩展的 NodeJS 服务设计

文章主题围绕着如何开发一个“容器上运行的端到端测试系统”展开,前面也提到过,其实就是在合适的时机去触发端到端框架的执行,想来就这么简单。但是我们在设计一个系统,一个平台时,应该考虑更多问题,比如:

  • 横向多项目扩展能力

  • 平台化服务能力

  • 运行效率极致化设计方案

  • 通报与预警中断机制

  • 合理选型技术方案以及存储方案

我们的端到端服务起名为「Goalkeeper」,意为“守门员”,希望它像一名优秀的守门员一样,守卫着我们产品质量的最后一道防线。

横向多项目扩展能力

Goalkeeper 目前已经进入成熟阶段,从立项的角度来说,该 NodeJS 服务不能只服务于一个项目测试,理想地它应该具备支持公司内所有产品接入的能力,并将接入过程和复杂度降到最低。

当办公室环境部署完成后,中台请求 Goalkeeper Post 接口 https://api.goalkeeper.com/run,这个接口提交数据字段包括:

{

"stage_name": "office",

"description": "style: 1221 活动页样式兼容低版本安卓",

"mr_iid": 2049999,

"app_name": "xen",

"author": "houce",

"event_name": "deployment_finished",

"candidate_id": 6666,

"deploy_id": 6666

}

app_name 字段为唯一的项目名称,配合其他表意字段(应该不难理解,这里不再一一说明),这样的接口设计自然支持全公司所用应用的接入,仅从接口设计上,具备先天扩展能力。接下来的说明也将进一步就横向扩展来展开。

Goalkeeper 首页仪表盘页面,选择查看应用项目:

8a7e9aa756c966cb3af21f820db8c69a.png

运行效率极致化设计

为了最高效地进行端到端测试,我们分析:对于不同的应用,应该多核多进程执行端到端测试,保证不同应用测试任务执行的并行性,即对于多个项目的部署,端到端测试不会发生阻塞,不排队;对于同一个项目应用,必须要避免短时间内多次不同部署之间的互相影响,对于这些端到端测试执行任务应该正交化设计,串行展开。

具体实施就需要一个消息队列,不同应用采用不同消息队列 tube,相同应用在同一个 tube 中串行生产和消费。因为 Goalkeeper 是一个服务内的消息队列设计,因此我选用了轻量且兼具强大功能的 Beastalkd 作为消息队列的技术选型。

Goalkeeper 某个应用下部署列表页面,点击查看具体信息:

fa065d2bf5c5899b49c283fd711bca78.png

平台化服务能力

具备了支持多应用的能力,接下来很自然地就想到:「开发者如何查看测试报告和了解测试细节呢」?

Goalkeeper 的设计包含了非常重要的一块内容 —— 平台化展示。这其实就是一个典型的:基于 Koa 的 NodeJS 后端服务,前端采用 React 作为多页面应用方案。具体来说,每次端到端测试服务完成之后,将产生的所有测试报告类数据存入 Redis,开发者访问 https://www.goalkeeper.com/dashboard,Koa 基于服务端渲染,获取相关数据进行单页面应用的平台化展示。

这些相关数据,不仅包含了每个端到端测试的 case 内容、case 执行信息和结果,还包含了测试产生的富媒体文件地址(包括测试录像,测试截图等)。关于测试产生的富媒体文件,我们采用了容器持久化技术进行存储,并对外提供静态服务。

换句话说,Goalkeeper 在 NodeJS 的服务层面提供了:

  • 容器上的端到端测试

  • 整套单页应用服务(包括查询平台和富媒体静态服务等)

比如对于某项目应用某次部署测试信息,可查询:

9ed4e7967e9b03046f86f10a558b7c79.png

视频信息以及截图信息:

b063e06606a561ce270b95f743d33500.png

63b073e67d39667b9f5f1529dfe780a6.png

通报与预警中断机制

为了更好地服务线上应用,我们也设计了高效的通报与预警机制。通报机制是指在一次提交部署开始,对应相关的端到端测试完成之后,通过企业微信和邮件将测试信息和测试平台展示地址发送给提交人或负责人。预警中断机制是指在端到端测试发现异常结果时,阻断上线流程,并强通知给提交人和负责人。

我们的异常结果不仅包含测试 case 的失败,更具特色的是也包含了视觉比对测试(visual testing)的异常。基于 Cypress,我们封装了一套视觉测试插件,它能够在任意节点自动对测试页面进行全量截图,并保存为对比基准图片。在下一次测试进行时,对当前最新测试的相同节点进行页面全量截图,并进行和基准图片的比对,如果两幅图片的不同像素超过一定百分比或一定像素阈值,则认为视觉比对失败。如图:

768f21ecac35e8967ee10c0ec071f6d0.png

视觉比对测试,能够大大解放测试 case 编写的复杂度,非常适合样式类测试的回归。当然对于预期之中的图片对比失败,比如是正常的页面 UI 改版,我们提供了「跳过视觉比对并更新基准图片」的能力。

在任何一种测试失败时,我们都会出发预警中断流程。如图,

52c2d8e41caf9b6fd2508d83efd9f0a3.png

架构和流程再梳理

我们通过分析一个请求的流程,再来总结梳理一下整个设计过程:

如图,简单示例:

be0737a2ef624259949d35a42daa0482.png

更细节一点的图示例:

ef4082674f572ac9021a0a95234ae999.png

当开发者提交代码被合并,Merge Request id 为 123 的相关部署到内网环境之后,触发中台 hook,中台会请求端到端测试 Goalkeeper 服务接口 ./run,该服务会为每一个应用创建一个进程处理,利用消息队列机制跑该次部署的端到端测试,并最后将测试状态结果(running/success/fail)写入 Redis 当中。在这个过程中,中台可以根据轮询接口 ./consult,该接口查询 Redis 中相关 Merge Request id 的测试状态,中台根据该结果值进行解锁上线流程或继续锁定上线。

同时,在该次部署所对应的端到端测试结束时,会更新测试报告平台内容,方便开发者访问最新部署产生的端到端测试报告以及录像等富媒体信息。相应的通知和预警机制也会在该阶段触发。

整套系统的关键依赖的服务项如图:

a8f8037b3fb6fe682f49629f0e824039.png

整个 Goalkeeper 平台主要依靠 Koa,Koa-static,Koa-router 来处理测试服务请求,并提供可查询的测试报告平台后台服务。Cypress 是主要的端到端测试框架,它提供了丰富的插件和扩展能力,我们在 Cypress 的基础上,封装了大量贴合自己业务的插件和扩展,比如实现视觉比对测试的 @kfe/goalkeeper-image-snapshot,@kfe/goalkeeper-image-snapshot-runner。Cypress 对应的测试脚本 cases 我们用一个单独的 Gitlab 仓库维护,每次在部署发生并启动端到端测试时,拉取最新的测试 cases 代码。最后,@kfe/goalkeeper-report-generator 是整个可查询平台的仓库,它是一个完整的基于 React SSR 的单页面应用,根据 React-router,提供了:

  • 首页,仪表盘页面(/dashboard)该页面展示了所有已接入的应用项目基本信息

  • 应用项目详情页(/:app)该页面展示了当前应用项目的基本信息

  • 项目部署列表页(/:app/mrList)该页面展示了当前应用项目下,所有的部署信息列表

  • 测试详情页(/:app/mrList/:mrId)该页面展示了当前部署对应的测试信息

  • 测试媒体查询页面(/:app/:mrId/media)该页面展示了当前部署对应测试的富媒体信息,包括测试录屏、应用截图等

总结

这篇文章我们介绍了 NodeJS 助力传统端到端测试,最终实现破局和创新的双赢项目案例。具体实施上,文章分析了如何实现容器上执行测试,如何接入 CI/CD pipeline,如何打造一个面向任何项目的 Goalkeeper 平台。

对于前端开发者来说,学习并实施 NodeJS,最关键的就是格局。我们要熟知 NodeJS 特性,更要有所谓的“后端”思维,架构思维。我相信 NodeJS 的发展和落地,不是因为它一定具有了某种与生俱来的力量,而是它的某些特点符合技术发展趋势或自然更迭规律。

我相信自己,生来如同璀璨的夏日之花,不凋不败,妖冶如火,承受心跳的负荷和呼吸的累赘,乐此不疲。—— 泰戈尔 Tagore

我想,开发者们一定会承受心跳的负荷和呼吸的累赘,但对于技术的发展乐此不疲。请关注我们,后续会带来更多前端技术实践和各种知识!

关于本文 作者:@LucasHC 原文:https://juejin.im/post/6883397368155373576

d96299713581bf9e3f1db09251aa3d02.png

@LucasHC曾分享过

【第2026期】「可视化搭建系统」——从设计到架构,探索前端领域技术和业务价值

【第1706期】不只是同构应用(isomorphic 工程化你所忽略的细节)

欢迎自荐投稿,前端早读课等你来

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443267.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 诊断工具 Arthas 常见命令

基本概念 云原生这么多微服务,当然需要一个诊断利器来排查问题。 Arthas 是阿里开源的 Java 诊断工具,深受开发者喜爱。在线排查问题,无需重启;动态跟踪 Java 代码;实时监控 JVM 状态。Arthas 支持 JDK 6&#xff0c…

28和lba48命令格式区别_编译Sass(命令行)

本文作者:开课吧无忧图文编辑:开三金sass编译有很多种方式,如命令行编译模式、编辑器自动编译、编译软件koala、sass-loader等。今天我们就先来看第一种:命令行编译刚才我在test文件夹里面已经建立了一个style.scss文件&#xff0…

子窗体中组合框联动_一张表实现组合框联动

嗨,大家中午好!最近,有网友给我私信,想要一个联动的示例,一个有关于部门联动的操作。其实关于联动的操作有很多,可以是组合框的联动,列表框联动,组合框与列表框也可以联动&#xff0…

中如何实现文字转语音_录音转文字、文字转语音,学会这一招就够了!手把手教你如何操作...

阅读文章时候想着有人可以把文章读给我听就好了,写作时想着语音直接可以转换成文字就好了,大家是不是有时会突然冒出这样的想法?七十这些看似天真的想法,还真的有办法解决,这里就手把手教你如何操作才能将的文字转换成…

图像 理想低通滤波_图像处理之滤波(下)

[toc]目录一、常规滤波低通高通带通带阻二、非局部均值滤波三、维纳滤波四、卡尔曼滤波前言所谓滤波,其实就是从混合在一起的诸多信号中提取出所需要的信号。信号的分类:确定型信号,可以表示为确定的时间函数,可确定其在任何时刻的…

泰山行宫碧霞元君祠_临清市泰山行宫碧霞元君祠5月4号(农历三月三十日)举行大型泰山奶奶接驾法会...

临清是泰山奶奶的娘家,每年的四月泰山奶奶要回临清省亲临清市道教协会定于2019年农历三月三十(5月4号星期六)于临清桑树园泰山行宫碧霞元君祠举行大型泰山奶奶迎鸾接驾庙会。届时,将有架鼓会、云龙会、狮胞会、钢叉会、高跷会、天音会、彩船会、秧歌会等…

充分条件反过来是必要条件吗_“充分必要条件”引发的现实思考

昨天看了一篇文章是介绍“充分条件和必要条件”,大致就是A能直接推导出B,那A就是B的充分条件。A不一定能推导出B,但是没A一定推导不出B,那A就是B必要条件。举个简单的例子:对你好(A)与喜欢你&am…

手机游戏降低游戏延迟的软件_怎么降低手机网络延迟(减少网络延迟的5个小技巧)...

在过去的几十年里,用户或开发人员并不担心延迟。在上世纪90年代和本世纪初,个人互联网连接速度要慢得多,因此发送请求和接收响应之间的延迟要远远小于下载完成所需的时间。如今,更高的带宽连接使下载速度更快,因此延迟…

mysql极客_极客mysql16

1.MySQL会为每个线程分配一个内存(sort_buffer)用于排序该内存大小为sort_buffer_size1>如果排序的数据量小于sort_buffer_size,排序将会在内存中完成2>如果排序数据量很大,内存中无法存下这么多数据,则会使用磁盘临时文件来辅助排序&a…

linux 测试环境启用jar_Linux下搭建测试环境

一、下载安装包https://pan.baidu.com/s/1h-Nk8HcWKKtqbjrn0J_t1g 457jJDK1.8安装包、Tomcat8安装包本文用的远程连接Linux操作系统的客户端工具为Xshell,相关使用请自行百度二、安装JDK1、先检查该环境是否已经安装过jdk。输入java -version。如果有,…

代码中 密码存储_你还记得浏览器自动存储的密码吗?用js代码恢复一下记忆吧...

哈喽大家好我是无知便是罪专注于收集和分享互联网上不为人知的好东西正常来说我们的手机和浏览器都有一个非常实用的功能就是可以自动的加密存储我们的常用密码了然后呢在我们需要的时候呢它可以自动填入进来非常非常的省时省力不过呢这种功能的我们用久了就很容易忘记自己当初…

diff算法阮一峰_【重学数据结构与算法(JS)】字符串匹配算法(三)——BM算法

前言文章的一开头,还是要强调下字符串匹配的思路将模式串和主串进行比较从前往后比较从后往前比较2. 匹配时,比较主串和模式串的下一个位置3. 失配时,在模式串中寻找一个合适的位置如果找到,从这个位置开始与主串当前失配位置进行比较如果未找…

python input 拖入路径 去除转义 空格_python学习笔记(基础-2)(转载)

1.输出用print()在括号中加上字符串,就可以向屏幕上输出指定的文字。2.输入如果要让用户从电脑输入一些字符怎么办?Python提供了一个input(),可以让用户输入字符串,并存放到一个变量里。输入是Input,输出是Output&…

mysql和mdy_Liunx下安装MySql

1.安装数据库:执行命令 yum -y install mysql-server2.启动数据库:安装完毕,执行命令service mysqld start3.登录数据库:mysql -u root -p回车后输入密码(mysql的默认用户名是root,密码为空)4.使用数据库:登…

python websocket服务器https_Socket与WebSocket以及http与https重新总结

Socket与WebSocket以及http与https重新总结一.Socket网络中的Socket是一个抽象的接口 ,而是为了方便使用TCP或UDP而抽象出来的一层 ,可以理解为网络中连接的两端。通常被叫做套接字接口.二.WebSocketWebSocket就是其中一种,是为了创建一种双向…

java button中文乱码_java解决中文乱码的几种写法

工作中总会遇到中文乱码问题,以导出文件,文件名称是中文的话,下载下来的文件名称会乱码问题,总结了几种解决文件名乱码的写法,仅供参考。首先定义一个汉语字符串String zhName "错误码模板";一、java.net.U…

java铝轮_为速度而生 JAVA Fuoco铝合金气动公路

人类在追求速度的历史上一直在不断创新,从两个轮子的自行车,到四个轮字的汽车,再到螺旋桨的飞机,追求速度是人类与生俱来的天性。就如同公路车的用途非常多,综合型公路车、耐力型公路车、爬坡型公路车,但唯…

java excel中删除两列_Java 插入、隐藏/显示、删除Excel行或列

概述操作Excel工作表时,对表格中的行或列数据可执行,包括插入、隐藏、显示、删除等在内的多种操作需求,本文将通过Java代码示例演示每种操作的具体实现方法。文中方法使用了Java Excel类库(Free Spire.XLS for Java 免费版),可通过…

Java0steam_Java学习 - Stream 使用

Java Stream使用这段时间在学数据库和Java,发现Java的Stream实际上和数据库的查询操作非常类似。这里简单介绍Stream的用法,并和Sql Server中的操作联系起来。此文为初学Stream所写,以后对Stream有更深的理解后会重写当我们使用一个流的时候&…

mysql初始化很慢_mysql初始化报错

/var/log/mysql.log 日志报错如上图所示解决方法:SELinux惹的祸通俗的讲就是linux服务器的安全策略解决:临时关闭:setenforce 0永久关闭需要修改配置文件,重启机器:修改/etc/selinux/config 文件将SELINUXenforcing改为…