2024年2月

前言

2022年1月,京东成为央视总台2022年春节联欢晚会独家互动合作伙伴,双方在红包互动、电商等方面展开全方位深度合作。在除夕当天产生691亿次互动,送出15亿元红包好物。

如何在这种大规模、高并发的场景下,确保系统的稳定性和性能,为用户提供稳定流畅的互动体验,成为了我们亟待解决的问题。

接下来我们主要从静态资源优化、缓存、容错、工程化几个方面来详细介绍前端团队所做的努力和创新。

静态资源优化

首屏资源加载策略

在春晚主持人口播之后,大量用户会集中在一段时间内涌入互动页面,这会导致流量峰值。为了降低页面打开时的请求次数和资源体积,我们根据页面交互,将所需资源分为三类:首屏、次屏以及操作后。

首屏资源主要包括:HTML文档、JavaScript、CSS以及样式图片。由于这是单页面应用,我们可以通过常规技术将JS和CSS进行打包。对于样式图片,我们可以通过按需加载的方式,显著减小首屏资源体积。

页面包含两个楼层,首屏的互动楼层和次屏的万券齐发楼层。其中,首屏会展示两排优惠券,因此,我们需要在首屏加载这部分券楼层的样式图片。互动主玩法中主要包括抽奖弹窗、邀人弹窗和击鼓游戏。通过拆分优化,首屏的样式图片体积减少约41%。再加上
CDN
降质和
WebP
参数的优化,样式图片的体积可以降低到178KB。

同时,我们将需要单独加载的击鼓游戏精灵动画图从首屏加载清单中剥离,使得首屏样式图片的加载次数从2次减少到1次。这样一来,用户在打开页面时,所需的请求次数和资源体积都得到了显著降低,进而提高了用户体验。

动画图片低损压缩

动画是页面资源消耗的主要部分。在春晚页面中,我们需平衡用户交互体验与资源优化。经过与设计和
CDN
团队多次沟通,我们决定采用技术手段降低资源消耗,同时保证用户体验。

首先是确定技术方案。设计团队最初提议使用3D模型,需借助
WebGL
进行渲染。但这存在两个问题:一是资源消耗大,3D模型通常包含3~4个文件,首屏加载请求数增加;二是兼容性问题,WebGL在低端机型上表现不佳。考虑到观众范围广泛,我们决定选用兼容性更好的方案。

经过技术调研,我们最终确定采用帧动画方案:设计团队将3D动画转化为精灵图,并将不变部分(如鼓架)单独抽离。精灵图仅包含运动部分(如鼓面敲击动画),有效降低资源消耗。

在确定方案后,设计团队导出了第一版资源文件。然而,精灵图大小为1236KB,主光效也有400KB,离我们的目标还有一定差距。经过双方反复尝试,我们通过抽帧方式将击鼓精灵图从24帧降至4帧,大小从1236KB降至265KB。结合降质参数和
WebP
格式,最终大小仅为78KB,下降了93%。此外,我们将主光效换成放大一倍的一倍图,并通过CSS属性scale实现放大,进一步节省资源。

雪碧图方案的演进

元素背景图使用雪碧图模式,是前端基本优化手段,可以显著降低请求次数。我们在首屏资源拆分后的情况下,可以将18个样式背景图合并成1个。相较于常规方案,春晚红包还扩展了2个功能:

1、css雪碧图在运行时为图片URL添加
CDN
降质参数和webp格式转换参数(someimage.png!q70.webp),极限降低CDN带宽。我们扩展开发了自动雪碧图脚本,可以支持自动生成2套
background-image
样式代码,分别对应普通图片URL和带!q70.webp的URL。通过运行时检测webp支持特性,切换HTML标签上的class名,来使对应的后代选择器的
background-image
属性生效。对于
webp
的特性检测的技术方案,我们考虑过如下两种方案:

a、通过版本判断,从caniuse看,可以按照只有iOS14以下不支持webp来作为判断依据。

b、通过创建一个Image对象,其src为一个基于base64的webp图片,根据load是否成功来判断是否支持webp。

比较这2个方案,方案a的优势是通过UA判断系统版本是同步执行的,可以在调用渲染页面前的任意地方执行并修改HTML标签的class属性。确保内容渲染后有正确的背景图css生效。不会对原有渲染逻辑产生入侵性修改。而方案b的优势是经过大规模实践,判断逻辑的可靠性较高,缺点是异步逻辑的,需要修改原来的渲染逻辑。由于我们这次需要支持全国亿万用户,为确保稳定可靠,所以最终选择方案b。

css文件中的背景图样式,是在渲染相应DOM的时候才发起请求,又由于React渲染是同步的,我们需要调整执行render的时机,以确保在渲染页面内容之前完成HTML的class属性设置,避免请求两次图片。

2、动态雪碧图。万券齐发楼层首屏露出2排8个坑位,对应8次logo图片请求,由于券和logo的数据是通过接口下发的,所以无法使用编译时雪碧图方案。为了将图片请求次数减少到1次,我们和后台、视觉、产品沟通后,设计了一套多团队协作的方案。设计同学可以根据产品提前确认的券位置将logo图合并成雪碧图,并上传到云存储。展示如下:

雪碧图规格确定后,通过固定的
background-position
属性,以及动态设置logo元素的
className
和背景图,即可实现动态雪碧图。

自动衍生WebP背景图css代码

上面提到运行时判断是否使用webp背景图,那对应的css代码就需要两套,利用PostCSS插件可以在编译时自动基于原有背景图样式代码生成webp背景图的代码,在紧张的开发过程中避免出错和遗漏。通过使用PostCSS插件中,CSS对象的
walkDecls
方法,我们可以遍历所有的
background-image
属性。然后,使用正则表达式匹配对应的样式,在编译打包时生成一套.webp .origin-class选择器的样式。在运行时,如果HTML标签具有
webp
属性,系统将后代选择器的样式覆盖原有样式。

除了img标签,我们在背景图也进行了webp优化,使得全站图片由902.4kb减小到512.6kb,经过多种流量和兼容性测试效果表现良好。由此可见,在项目中大量使用图片时,
WebP
格式已成为一个不容忽视的性能优化关键。

降低服务器成本及风险

春晚活动是一个典型的秒杀业务场景:随着春晚主持人一声令下,全国观众会同一时间涌入活动页面,给接口带来超高的流量压力。下面将从流量削峰、降级处理两个个方面介绍前端如何与后台合作应对这类高并发场景。

流量削峰

在高并发场景下,流量削峰有助于系统平稳度过流量高峰。本次活动中,初始化接口和击鼓抽奖接口流量最大,因此我们主要针对这两个接口进行削峰。

1.初始化接口:在页面加载之前,即资源位入口,配置一个“加载中”页面链接。这个页面随机加载1-3秒后跳转到活动页面。当流量超过系统承载能力时,开启灰度开关,部分用户进入此页面,然后等待几秒后进入活动页面。

2.击鼓抽奖接口:本次活动的核心玩法接口。如果仅仅是简单地随机延时几秒请求,会极大地影响用户体验。我们采用更精细化的处理方式。已知击鼓交互在用户敲击满次数或倒计时结束时触发抽奖接口,因此,随机设定敲鼓次数,将原本集中在1-2秒内的请求打散至10秒区间,用户几乎无感知。

即时状态的本地存储

针对用户优惠券领取状态的保存问题,权衡了多种因素,如活动规模、服务器端压力和活动持续时长等。最终,我们决定采用前端本地缓存来保存用户领券状态,从而提升性能并优化用户体验。

我们对比了前端常用的本地存储机制,如
cookie

localStorage

sessionStorage
。然而,这些机制各有优缺点:

1.
cookie
存储空间较小(4K),且在与服务端通信时会占用请求头部,可能导致请求头过大,超过服务端设置的最大值,进而引发报错,并增加不必要的网络消耗。
2.
sessionStorage
生命周期较短,仅适用于会话期间。

综合考虑后,我们选择了
localStorage
作为优化方案。它具有较长的生命周期和较大的储存空间(2.5M-4M),能满足业务需求。采用
localStorage
缓存数据,不仅可以简化调用链路、降低风险和节约成本,还能直接从本地读取券的领取状态,避免网络延迟导致的响应时间过长,提升用户体验。

工程化

为了使业务开发人员能更专注于自身业务开发,我们将手机兼容性、设备分级、环境判断、自动合成雪碧图、自动图片压缩、自动上传云存储、合并代码文件等通用解决方案统一纳入工程化层面处理。

通过工程化,可以最大程度的释放生产力和创造力。上述的各种前端各种优化方案,离不开工程化的助力,与此同时保证了在快速开发交付的效率和稳定性。

提供拟真的
MOCK
环境

我们搭建了一个拟真的
MOCK
环境,以在短时间内模拟所需场景,确保在任意场景下都能提供友好交互。该环境1:1还原了服务端的
MOCK
环境,能快速模拟正常数据,同时还能模拟请求超时、HTTP状态码异常、数据结构异常、非常规业务异常码等场景。在ajax模块中,我们采用透明转发方式,降低业务开发同学创作mock数据的成本,避免mock数据进入生产环境。如图所示,
MOCK
开发环境与联调开发环境对比,可以看出mock环境对业务开发来说是透明且无副作用的,同时又能快速
MOCK
数据。

编写稳定高效的发布脚本

春晚参与用户的设备种类繁多,我们需在不同设备上实现极致体验,同时减轻
CDN
过高
QPS
的压力。为此,我们与客户端团队联合,根据不同设备的不同版本,提供了内置包、离线包和线上
CDN
包等多套环境。结合多轮内测和公测,在短短27天内,需部署10多套环境。线上环境部署错综复杂,还包括资源收集和大小计算等工作。若采用人工方式,极易出现误操作,带来不良后果。幸运的是,项目初期便引入了环境变量,通过环境变量解决不同环境间的差异。此外,在编译前后加入了一系列脚本,替代人工拷贝上传、资源收集、大小计算等操作,避免人工操作失误,提高稳定性,确保每个环境稳定部署。

工程化的目标,始终是提升开发效率,降低开发难度,分离关注点,让业务研发同学更专注于自身业务的开发。

容灾

作为一档全球直播节目,现场不免会出现各种状况,需要做好各种紧急预案。降级处理分为主动降级和被动降级两类:

1.
主动降级:各个资源位和交互按钮上添加降级开关,上游接口或下游页面出现紧急情况时,可通过配置CMS快速打开降级开关。

2.被动降级:通过不同样式和文案提示区分各类接口异常码及系统环境,快速定位问题原因。这样一来,客服同学可以第一时间安抚客户,并提供相应处理方案。

总结

2022年央视春晚互动项目是一次大规模、高并发的挑战,前端团队通过静态资源优化、缓存、容错和工程化等方面的努力和创新,确保了系统的稳定性和性能,为用户提供了一个稳定流畅的互动体验。在静态资源优化方面,团队通过首屏资源拆分、帧动画方案替代3D模型、动态雪碧图和
WebP
格式优化等技术手段,显著降低了资源消耗和请求次数。在降低服务器成本及风险方面,选择
localStorage
作为非常规优化方案,提升用户体验。在容错方面,流量削峰和降级处理,确保系统稳定运行。在工程化方面,统一处理通用解决方案、提供拟真的
MOCK
环境和编写稳定高效的发布脚本,降低开发难度,确保每个环境稳定部署。通过这些技术手段和创新,前端团队成功应对了春晚互动项目带来的技术难题,为用户提供了一个稳定流畅的互动体验。

作者:京东零售 赵越

来源:京东云开发者社区 转载请注明来源

docker 官方文档:
https://docs.docker.com/get-docker/

docker 中文文档:
https://www.kancloud.cn/jingyucloud/docker/216412

搭建私有仓库参考:
https://zhuanlan.zhihu.com/p/511286328

开放远程API接口参考:
https://blog.csdn.net/ic_esnow/article/details/113284475

一、简介

容器概念

容器是一种轻量级、可移植、自包含的软件运行环境。它允许开发者将一个应用及其全部运行环境——包括代码、运行时、系统工具、系统库以及设置——全部封装在一起。这种封装确保了应用在任何环境中都能以相同的方式运行,无论是在开发人员的个人电脑上、测试环境中、还是在生产环境的服务器或云平台上。

核心特性

  • 隔离性
    :容器通过操作系统级别的虚拟化实现了进程和资源的隔离。每个容器都运行在一个独立的环境中,并且容器与容器之间、容器与宿主机之间都是相互隔离的。
  • 轻量级
    :与传统的虚拟机相比,容器不需要额外加载一个完整的操作系统内核,只需利用宿主机的内核即可运行。这大大减少了资源消耗和启动时间。
  • 可移植性
    :由于容器内包含了应用运行所需的一切,因此可以确保应用在不同的计算环境中运行时的一致性和兼容性。
  • 微服务架构的支持
    :容器非常适合微服务架构,因为它们允许每个服务单独容器化,这样可以独立地开发和扩展服务。

容器与虚拟机的区别

  • 启动时间
    :容器只需几秒钟即可启动,而虚拟机可能需要几分钟。
  • 性能
    :容器直接运行在宿主机的操作系统之上,几乎没有额外开销,因此性能接近物理机。虚拟机则需要额外的资源来运行完整的操作系统。
  • 资源占用
    :容器共享宿主机的操作系统内核,而虚拟机则需要为每个虚拟机实例运行一个完整的操作系统,因此容器更加节省资源。
  • 隔离性
    :虚拟机提供了更强的隔离性,因为它们彼此之间以及与宿主机之间是完全独立的。容器虽然也提供了隔离性,但因为它们共享宿主机的内核,所以相对较弱。

容器技术的出现和普及改变了软件开发、部署和运维的方式,使得应用的交付更加快速、高效。Docker 是目前最流行的容器平台之一,但也有其他技术如 Podman、containerd 等。

什么是Docker

Docker 是一个开源的应用容器引擎,允许开发者打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(默认情况下),更重要的是容器性能开销极低。

核心概念
  • 镜像(Image)
    :Docker 镜像是用于创建 Docker 容器的模板,可以将其理解为一个只读的文件系统。它提供了容器运行时所需的程序、库、资源、配置等文件,但不包含任何动态数据。用户可以基于镜像启动新的容器实例。
  • 容器(Container)
    :容器是镜像的运行实例。它可以被启动、开始、停止、删除,每个容器都是相互隔离、保证安全的平台。容器的核心是隔离性和临时性,这意味着当容器被删除时,容器内的更改和数据也会随之消失。
  • 仓库(Repository)
    :Docker 仓库是集中存放镜像文件的场所。最著名的公共仓库是 Docker Hub,其中包含了数量庞大的镜像供用户下载。除了 Docker Hub,用户还可以创建私有仓库来存放自己的镜像。
工作原理

Docker 使用客户端-服务器(C/S)架构模式。Docker 客户端与 Docker 服务器(Docker Daemon)通信,Docker Daemon 负责构建、运行和分发 Docker 容器。Docker 客户端和服务器可以运行在同一个系统上,也可以通过网络从远程客户端与 Docker Daemon 通信。

主要特点
  1. 快速、一致地交付应用
    :Docker 可以快速构建、测试并部署应用,并确保应用在任何环境中都能以相同的方式运行。
  2. 响应式扩展与缩减
    :根据业务需求,容易地在服务中增加或删除容器来扩展或缩减服务。
  3. 运行任何地方
    :Docker 容器可以在开发者的本地笔记本电脑、物理或虚拟机、数据中心、云服务等任何地方运行。
  4. 隔离
    :Docker 确保每个容器都在自己的隔离环境中运行,使得应用更加安全。
  5. 轻量级
    :Docker 利用 Linux 容器技术,比传统的虚拟化技术更加轻量,提高了系统利用率和性能。

Docker 的出现极大地简化了部署应用的流程,让开发、测试、生产环境之间的切换变得更加容易和快捷,对现代软件开发和运维方式产生了深远影响。

二、Window安装

在Win10及以上系统安装Docker Desktop使用Docker

确保系统安装 Hyper-V 参考文章(
https://www.runoob.com/docker/windows-docker-install.html)

1、在
Docker Desktop下载
网页上点击Docker Desktop for Windows下载或者直接去
官网下载安装包

2、安装包下载好后,直接双击Docker Desktop Installer.exe文件进行安装,把接下来的页面所有选项全部选中

参考:
https://blog.csdn.net/qq_39611230/article/details/108641842

在这里插入图片描述

在这里插入图片描述

3、安装完成后,打开Docker Desktop应用,在setting页面选择 Docker Engine

内容如下

{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  },
  "experimental": false,
  "features": {
    "buildkit": true
  },
  "registry-mirrors": [
    "http://hub-mirror.c.163.com",
    "https://docker.mirrors.ustc.edu.cn"
  ],
  "insecure-registries": [
    "192.168.1.153:5000"
  ]
}

//registry-mirrors 配置源,这里使用的是163的源
//insecure-registries 私有仓库地址


参考:

https://docs.docker.com/desktop/install/windows-install/

https://www.runoob.com/docker/windows-docker-install.html

https://zhuanlan.zhihu.com/p/191588757

https://blog.csdn.net/BThinker/article/details/123358697

三、CentOS安装

1、选择要安装的平台

Docker要求CentOS系统的内核版本高于3.10

#通过 uname -r 命令查看你当前的内核版本
uname -r 

安装文档地址

img

2、选择要安装的操作系统

img

3、首先卸载已安装的Docker

使用
Root权限
登录 Centos。确保yum包更新到最新。

sudo yum update

在尝试安装新版本之前,请卸载任何此类旧版本以及关联的依赖项,操作系统没有安装过Docker就跳过。

sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

img

可能会报告您没有安装这些软件包,卸载 Docker 时,存储在
/var/lib/docker/
其中的映像、容器、卷和网络不会自动删除。

1、您可以设置 Docker 的存储库并从中安装,以便于安装和升级任务。这是推荐的方法。

2、您可以下载 RPM 软件包,手动安装它,并完全手动管理升级。这在无法访问 Internet 的气隙系统上安装 Docker 等情况下很有用。

3、在测试和开发环境中,您可以使用自动化便利脚本来安装 Docker。

4、使用rpm存储库安装

在新主机上首次安装 Docker 引擎之前,需要设置 Docker 存储库。之后,您可以从存储库安装和更新 Docker。

4.1、设置仓库

安装
yum-utils
软件包(提供
yum-config-manager
实用程序)并设置存储库。

## 安装Docker所需要的一些工具包
sudo yum install -y yum-utils

## 建立Docker仓库 (映射仓库地址)
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

4.2、安装 Docker Engine

若要安装最新版本,请运行:

sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

如果系统提示您接受 GPG 密钥,请验证指纹是否匹配,如果匹配
060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35
,请接受它。

此命令将安装 Docker,但不会启动 Docker。它还会创建一个
docker
组,但是,默认情况下,它不会向该组添加任何用户。

4.3、启动 Docker

sudo systemctl start docker

4.4、通过运行
hello-world
映像来验证 Docker 引擎安装是否成功。

sudo docker run hello-world

5、软件包安装

如果无法使用 Docker
rpm
的存储库安装 Docker 引擎,可以下载
.rpm
版本的文件并手动安装。每次要升级 Docker 引擎时,都需要下载一个新文件。

前往
https://download.docker.com/linux/centos/
并选择您的 CentOS 版本。然后浏览并
x86_64/stable/Packages/
下载
.rpm
要安装的 Docker 版本的文件。

5.1、安装 Docker 引擎,将以下路径更改为下载 Docker 包的路径。

 sudo yum install /path/to/package.rpm

Docker 已安装但未启动。组已创建,但未将用户添加到
docker
组。

5.2、启动 Docker。

sudo systemctl start docker

5.3、通过运行
hello-world
映像来验证 Docker 引擎安装是否成功。

sudo docker run hello-world

6、升级Docker 引擎

若要升级 Docker 引擎,请下载较新的包文件并重复安装过程,使用
yum -y upgrade
而不是
yum -y install
,并指向新文件。

使用便捷脚本安装

Docker 在
https://get.docker.com/
提供了一个方便的脚本,用于以非交互方式将 Docker 安装到开发环境中。不建议将方便脚本用于生产环境,但它可用于创建根据需求量身定制的预配脚本。另请参阅使用存储库安装步骤,了解使用软件包存储库进行安装的安装步骤。该脚本的源代码是开源的,您可以在 GitHub 上的
docker-install
存储库中找到它。

在本地运行脚本之前,请始终检查从 Internet 下载的脚本。在安装之前,请熟悉便利脚本的潜在风险和限制:

  • 脚本需要
    root

    sudo
    权限才能运行。
  • 该脚本尝试检测您的 Linux 发行版和版本,并为您配置包管理系统。
  • 该脚本不允许您自定义大多数安装参数。
  • 该脚本在不要求确认的情况下安装依赖项和建议。这可能会安装大量软件包,具体取决于主机的当前配置。
  • 默认情况下,该脚本会安装 Docker、containerd 和 runc 的最新稳定版本。使用此脚本预配计算机时,这可能会导致 Docker 意外的主要版本升级。在部署到生产系统之前,请始终在测试环境中测试升级。
  • 该脚本并非旨在升级现有 Docker 安装。使用脚本更新现有安装时,依赖项可能不会更新到预期的版本,从而导致版本过时。

提示:运行前预览脚本步骤

您可以使用以下
--dry-run
选项运行脚本,以了解脚本在调用时将运行哪些步骤:

$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo sh ./get-docker.sh --dry-run

此示例从
https://get.docker.com/
下载脚本并运行它以在 Linux 上安装 Docker 的最新稳定版本:

$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh
Executing docker install script, commit: 7cae5f8b0decc17d6571f9f52eb840fbc13b2737
<...>

现在,您已成功安装并启动了 Docker 引擎。该
docker
服务在基于 Debian 的发行版上自动启动。在基于发行版(如 CentOS、Fedora、RHEL 或 SLES)上
RPM
,您需要使用相应的
systemctl
or
service
命令手动启动它。如消息所示,默认情况下,非 root 用户无法运行 Docker 命令。

以非特权用户身份使用 Docker,还是以无根模式安装?
安装脚本需要
root

sudo
具有权限才能安装和使用 Docker。如果要授予非 root 用户对 Docker 的访问权限,请参阅 Linux 的安装后步骤。您还可以在没有权限的情况下
root
安装 Docker,或配置为在无根模式下运行。有关在无根模式下运行 Docker 的说明,请参阅
以非 root 用户身份运行 Docker 守护程序

安装预发行版
Docker 还提供了一个方便的
https://test.docker.com/
脚本,用于在 Linux 上安装 Docker 的预发行版。此脚本等同于 中的
get.docker.com
脚本,但将包管理器配置为使用 Docker 包存储库的测试通道。测试通道包括 Docker 的稳定版本和预发布版本(测试版、候选版本)。使用此脚本可以抢先体验新版本,并在它们作为稳定版本发布之前在测试环境中对其进行评估。

若要从测试通道在 Linux 上安装最新版本的 Docker,请运行:

$ curl -fsSL https://test.docker.com -o test-docker.sh
$ sudo sh test-docker.sh

使用便捷脚本后升级 Docker
如果使用方便脚本安装了 Docker,则应直接使用包管理器升级 Docker。重新运行便利脚本没有任何好处。如果它尝试重新安装主机上已存在的存储库,则重新运行它可能会导致问题。

卸载 Docker 引擎

  1. 卸载 Docker 引擎、CLI、containerd 和 Docker Compose 包:

    $ sudo yum remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
    
  2. 主机上的映像、容器、卷或自定义配置文件不会自动删除。要删除所有映像、容器和卷,请执行以下操作:

    $ sudo rm -rf /var/lib/docker
    $ sudo rm -rf /var/lib/containerd
    

您必须手动删除任何已编辑的配置文件。

参考:

https://docs.docker.com/engine/install/

https://docs.docker.com/engine/install/centos/

https://blog.csdn.net/BThinker/article/details/123358697

https://www.runoob.com/docker/centos-docker-install.html

在文本索引构建这种需要大量占用磁盘IO的任务,如果正巧你的内存还有点余粮,是否可以先索引存储到内存,然后再顺序写入到磁盘呢?,需要大量占用磁盘IO,如果正巧你的内存还有点余粮,是否可以先索引存储到内存,然后再顺序写入到磁盘呢?

将Linux的内存变为磁盘,可以通过tmpfs文件系统实现。

tmpfs介绍

以下是ChatGPT的介绍:

tmpfs文件系统是Linux内核自带的一种内存文件系统,它可以将内存空间作为虚拟磁盘使用。使用tmpfs文件系统将内存变为磁盘,可以通过以下步骤实现:

创建一个tmpfs文件系统:

sudo mkfs.tmpfs -m 100M -o size=100M /dev/shm/mydisk  

这条命令将在/dev/shm/mydisk设备上创建一个大小为100MB的tmpfs文件系统。

挂载tmpfs文件系统:

sudo mount -t tmpfs /dev/shm/mydisk /mnt/mydisk  

这条命令将/dev/shm/mydisk设备上的tmpfs文件系统挂载到/mnt/mydisk目录。

此时,/mnt/mydisk目录就可以像普通磁盘一样使用了。可以将文件写入到该目录,也可以从该目录读取文件。

docker使用tmpfs

在docker容器环境如何使用呢?是否需要在container里去挂载?

其实在docker里,tmpfs是默认支持的,可以通过 在启动命令里,加上类似
--mount type=tmpfs,destination=/mnt/tmpfs,tmpfs-mode=1770,tmpfs-size=12G
来实现挂载。

注意tmpfs挂载的,是container容器独享的,不能和其他容器共享,有效期就是容器的生命周期。

我们来实验:

[root@dev ~]#docker run -it --rm --mount type=tmpfs,destination=/mnt/tmpfs,tmpfs-mode=1770,tmpfs-size=12G gcc:12 bash
root@87b86fe9a4d0:/# df -h 
Filesystem      Size  Used Avail Use% Mounted on
overlay         182G  160G   13G  93% /
tmpfs            64M     0   64M   0% /dev
tmpfs            63G     0   63G   0% /sys/fs/cgroup
shm              64M     0   64M   0% /dev/shm
/dev/sda2       182G  160G   13G  93% /etc/hosts
tmpfs            12G     0   12G   0% /mnt/tmpfs
tmpfs            63G     0   63G   0% /proc/acpi
tmpfs            63G     0   63G   0% /proc/scsi
tmpfs            63G     0   63G   0% /sys/firmware
  • 首先通过
    docker run
    挂载,制定大小12G
  • 在容器里,通过
    df -h
    可以看到挂载的
    /mnt/tmpfs
    类型为
    tmpfs
    ,大小12G

K8S 使用tmpfs

在K8S里,tmpfs对应的是
emptyDir
Volume,将
emptyDir.medium
指定为
Memory
,可以让 Kubernetes 挂载 tmpfs(基于 RAM 的文件系统)。

emptyDir
的一些用途:

  • 缓存空间,例如基于磁盘的归并排序。
  • 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
  • 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。

emptyDir 配置示例

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir:
      sizeLimit: 500Mi
      medium: Memory

Spark on k8s

对于运行在K8S上的spark,也可以通过volumes参数来指定使用tmpfs。

spark提供下面几种类型的volume

  • hostPath
    : mounts a file or directory from the host node’s filesystem into a pod.
  • emptyDir
    : an initially empty volume created when a pod is assigned to a node.
  • nfs
    : mounts an existing NFS(Network File System) into a pod.
  • persistentVolumeClaim
    : mounts a
    PersistentVolume
    into a pod.

可以通过下面的参数来配置Volume:

--conf spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.path=<mount path>
--conf spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.readOnly=<true|false>
--conf spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].mount.subPath=<mount subPath>

对于VolumeType的配置,可以通过下面的形式来做:

spark.kubernetes.driver.volumes.[VolumeType].[VolumeName].options.[OptionName]=<value>

因此,spark on k8s支持
tmpfs
, 假设
VolumeName

spark-empty-dir
, 挂载路径
/mnt/cache-index
, 大小限制
12G
,那么提供任务时可以指定参数:

--conf spark.kubernetes.executor.volumes.emptyDir.spark-empty-dir.mount.path=/mnt/cache-index
--conf spark.kubernetes.executor.volumes.emptyDir.spark-empty-dir.options.medium=Memory
--conf spark.kubernetes.executor.volumes.emptyDir.spark-empty-dir.options.sizeLimit=12G

优化后,文本索引构建时IO占用:

本文介绍分布式开源版本控制系统
Git
的下载、安装,并基于
Git
实现克隆
GitHub
中项目代码的方法。

Git
是一款开源软件,因此我们直接在
Git

官方下载地址
下载最新版本的
Git
即可。其中,在下图所示的位置选择适合我们操作系统的
Git
版本。

随后,选择下图红色方框内的内容,下载最新版的
Git

下载完毕后,双击得到的
.exe
文件,进入安装流程,如下图所示;接下来,我们仅对安装流程中比较重要的配置选项进行介绍,对于没有出现的窗口,大家直接选择默认的配置选项即可。

首先,配置好
Git
的安装路径。

其次,在如下所示的窗口中,建议将下图中红色方框内的选项勾选中,使得软件安装完毕后在桌面创建快捷方式;其余的勾选框,大家就使用默认的勾选状态即可。

随后,在如下所示的窗口中,需要配置
Git
所使用的编译器;这里我们就选择默认的选项即可。其实对于一般的用户而言,这里的设置我们应该也用不上。

在如下所示的窗口中,需要配置一个项目的初始分支的名称,这里选择默认选项即可。

在如下所示的窗口中,需要配置
Git
的环境路径选项,建议选择第二项,这样
Git
将自动配置环境路径。

对于其他没有提及的窗口,大家直接选择默认配置即可。随后,即可开始安装。

稍等片刻,
Git
将安装完毕。

随后,我们就可以开始使用
Git
的各项功能了。例如,假设我们需要基于
Git

GitHub
中复制
C++
包管理器
vcpkg
的相关代码,就可以在
Windows PowerShell
中,输入以下语句。

git clone https://github.com/microsoft/vcpkg

如下图所示。

其中,如果大家在
Git
使用过程中出现错误代码为
10054
的错误,如下图所示(下图中我将
microsoft
这个单词打错了,大家理解即可),则一般是因为网络出现问题导致的;此时可以重新尝试,如果有代理软件需要关闭代理。

此外,如果我们第一次通过
Git
建立与
GitHub
的连接,还会弹出一个
GitHub
的登录窗口,如下图所示。

如果出现这个提示,我们按照要求登录
GitHub
账号即可;登录完毕,即可开始执行
git
操作。

如上图所示,证明
git
操作已经成功。