搭建自動化 Web 頁面性能檢測系統 —— 部署篇

来源:https://www.cnblogs.com/dtux/p/18329811
-Advertisement-
Play Games

我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。 本文作者:琉易 liuxianyu.cn 這一篇是系列文章: 搭建自動化 Web 頁面性能檢測系統 —— 設計篇 搭建自動化 Web 頁面性能檢測系統 —— 實現篇 作 ...


我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。

本文作者:琉易 liuxianyu.cn

這一篇是系列文章:
搭建自動化 Web 頁面性能檢測系統 —— 設計篇
搭建自動化 Web 頁面性能檢測系統 —— 實現篇

作為一個前端想去做全棧的項目時,可能第一個思路是 node + vue/react。一開始可能會新建多個工程目錄去實現,假設分別為 web 和 server,也許還有管理後臺的代碼 admin,那麼就有了三個工程的代碼。此時為了方便管理就需要在遠程倉庫新建一個 group 統一管理代碼,一般這種方式稱之為 MultiRepo。

file

這顯然是不夠簡潔的,對於開發者而言也不便於開發和部署。這類多模塊的項目我們可以引入 Monorepo 的概念,下麵是一些優化方法的嘗試,以 yice-performance(易測) 作為例子講解,本地設備為 M1 晶元的 arm64v8 平臺。

一、node 托管靜態頁面

可以將 web 打包的代碼交給 node 托管,此時就可以將 web 的代碼作為一個文件夾放到 server 的目錄中,這時候我們一般直接訪問後端介面的根路徑即可。如:yice-performance - v1.0
對應的 nginx 配置一般為:

server {
    listen          80;
    server_name     yice.dtstack.cn;

    location / {
        proxy_pass http://localhost:4000/;
    }
}

常見的 node 框架都支持托管靜態文件目錄:

// express
app.use(express.static(path.join(__dirname, 'web/dist')));


// NestJS
import { ServeStaticModule } from '@nestjs/serve-static';

ServeStaticModule.forRoot({
    serveRoot: '/',
    rootPath: join(__dirname, '.', 'web/dist'),
}),

// egg
{
    static: {
        dir: path.join(appInfo.baseDir, 'web/dist'),
    }
}

代碼基本大同小異,從 nginx 配置和項目結構我們也能看出這還是屬於一個 node 項目的結構,前端項目的 nginx 配置一般為:

server {
    listen          80;
    server_name     yice.dtstack.cn;
    root						/opt/dtstack/yice-performance/web/dist/

    location /api {
        proxy_pass http://localhost:4000/;
    }
    location / {
        try_files $uri $uri/ /index.html;
    }
}

二、Turborepo

Turborepo 是用於 JavaScript 和 TypeScript 代碼庫的高性能構建系統。

藉助 Turborepo 我們可以並行的運行和構建代碼,當我們使用傳統的 yarn workspace 管理代碼時,我們的一般會執行以下命令:

# server
yarn
yarn dev

# web
cd web
yarn
yarn dev

此時,本地開發不僅需要同時開啟兩個終端,而且還得分別註意兩個終端所在的路徑,lint、build、test 等命令皆如此。

file

想要更快的完成以上工作,可以使用 turbo run lint test build

file

新項目往往更容易使用 Turborepo,使用 create-turbo 創建即可,參考 官方文檔。歷史項目想要使用 Turborepo 時需要註意一下項目結構:

yice-performance
├─package.json
├─pnpm-lock.yaml
├─pnpm-workspace.yaml
├─turbo.json
├─apps
|  ├─server
|  └─web

將歷史項目的代碼整合到單個文件夾後移入 apps ,註意需要修改相對路徑等代碼,比如 tsconfig.json 文件中關於 @/* 等路徑別名的寫法,以及 import 依賴的路徑,將公共依賴包統一提到根目錄的 package.json 中。
在根目錄添加 turbo.json 文件,這裡是 dev 和 build 命令為例:

{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".apps/server/dist/**", "!.apps/server/cache/**"]
    },
    "dev": {
      "persistent": true,
      "cache": false
    }
  }
}

然後在 apps 下的產品中依次添加兩種命令:

{
  "scripts": {
    "dev": "NODE_ENV=development nest start --watch",
    "build": "NODE_ENV=production nest build"
  }
}
{
  "scripts": {
    "dev": "NODE_ENV=development vite --port 7001",
    "build": "tsc && NODE_ENV=production vite build"
  }
}

這樣就可以通過 pnpm dev 一條命令同時啟多個服務了,pnpm build 可以快速完成多個項目的打包工作。

file

三、docker

以易測依賴的 Puppeteer 為例,對於設備環境的要求就比較多,參考 Puppeteer 故障排除;再比如易測 v2.x 版本新增的數據周報功能使用到 node 端的 echarts,最終依賴 node-canvas,對設備環境的要求也很苛刻。
同時,部署命令寫的腳本中還需要考慮不同環境的差異,比如 Windows 中的情況。
docker 在這裡的作用就是抹平不同設備間的環境差異,減少補充安裝依賴包的痛苦,amd64、arm64 等環境差異導致的依賴包安裝失敗問題,我們可以構建適用於不同平臺的 docker 鏡像包(以下以 linux/amd64 為例,也就是常說的 x86_64 架構)。

Dockerfile

本地編寫 Dockerfile 文件,然後執行 docker build命令構建鏡像。在構建鏡像之前,需要註意下 Dockerfile 構建鏡像時有一個 的概念,對於構建時間會有較大影響。

Docker 鏡像是由多個只讀的層疊加而成的,每一層都是基於前一層構建。Dockerfile 文件中的每條指令都會創建一個新的層,並對鏡像進行修改,執行 docker build 命令時會使用緩存,當前面的層不發生變化時,我們再次構建鏡像時就會更快速。但因為每一層都是基於前一層構建,所以我們應該把變化可能性小的操作放到前面,後續改動只會構建變化的內容,而無需構建整個鏡像,這能大大加快鏡像的構建速度。

比如下方 Dockerfile.server 中的 nodejs 的安裝,如果放在 COPY . . 之後,則每次構建都需要安裝一次 nodejs,我們利用緩存可以大大減少構建時間。

FROM ubuntu:22.04

# 設置時區
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
     && apt-get update -y && apt-get install -y tzdata

# puppeteer 和 node-canvas 對系統依賴的要求
# https://github.com/Automattic/node-canvas?tab=readme-ov-file#compiling
# https://github.com/puppeteer/puppeteer/blob/puppeteer-v19.6.3/docs/troubleshooting.md#chrome-headless-doesnt-launch-on-unix
RUN apt-get update -y \
     && apt-get install -y build-essential libcairo2-dev libpango1.0-dev libnss3 libatk1.0-0 \
     && apt-get install -y ca-certificates fonts-liberation libasound2 libatk-bridge2.0-0 \
     && apt-get install -y libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 \
     && apt-get install -y libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libpangocairo-1.0-0 \
     && apt-get install -y libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 \
     && apt-get install -y libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 \
     && apt-get install -y libxss1 libxtst6

# 處理 chromium 等依賴問題
# https://github.com/puppeteer/puppeteer/blob/puppeteer-v19.6.3/docker/Dockerfile
RUN apt-get update -y \
     && apt-get install -y wget gnupg \
     && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/googlechrome-linux-keyring.gpg \
     && sh -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/googlechrome-linux-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
     && apt-get update -y \
     && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-khmeros fonts-kacst fonts-freefont-ttf libxss1 --no-install-recommends \
     && rm -rf /var/lib/apt/lists/* \
     && apt-get remove -y wget gnupg
# deb [arch=amd6 配置可能會在 /etc/apt/sources.list.d/google.list 和 /etc/apt/sources.list.d/google-chrome.list 中重覆,再嘗試一次
RUN  rm -rf /etc/apt/sources.list.d/google-chrome.list \
     && apt-get update -y \
     && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-khmeros fonts-kacst fonts-freefont-ttf libxss1 --no-install-recommends

# 安裝 nodejs
RUN apt-get update -y && apt-get install -y curl \
     && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
     && apt-get remove -y curl \
     && apt-get install -y nodejs \
     && npm config set registry https://registry.npmmirror.com/ \
     && npm install [email protected] -g

# 設置工作目錄
WORKDIR /yice-performance

# 拷貝代碼安裝依賴
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json ./
COPY apps/server/package.json ./apps/server/
COPY apps/web/package.json ./apps/web/
RUN pnpm install

# 複製項目文件
COPY apps .env ./
# 減少 node_modules 的磁碟占用
RUN pnpm build \
     && find . -name "node_modules" -type d -prune -exec rm -rf '{}' + \
     && pnpm install --production

# 暴露埠
EXPOSE 4000

# 定義環境變數
ENV NODE_ENV=production
# Dockerfile 中需指定 chromium 路徑
ENV PUPPETEER_EXECUTABLE_PATH='google-chrome-stable'

VOLUME [ "/yice-performance/apps/server/yice-report" ]

# 啟動應用程式
CMD ["node", "apps/server/dist/main.js"]
ARG BASE_IMAGE=mysql:5.7
FROM ${BASE_IMAGE}

# 當容器啟動時,會自動執行 /docker-entrypoint-initdb.d/ 下的所有 .sql 文件
COPY ./mysql/demo-data.sql /docker-entrypoint-initdb.d/
# 附加的 mysql 配置
COPY ./mysql/my_custom.cnf /etc/mysql/conf.d/

# 設置 MySQL root 用戶的密碼
ENV MYSQL_ROOT_PASSWORD=123456
ENV MYSQL_DATABASE=yice-performance

# 設置時區
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 暴露埠
EXPOSE 3306

根據 Dockerfile 文件本地構建鏡像,構建完成後在 Docker Desktop 中就可以看到剛剛構建的鏡像。我們新建一個腳本文件來統一管理命令,併在 package.json 中添加 build:docker命令:

#!/bin/sh

cd docker

# amd64
docker buildx build --platform linux/amd64 -f Dockerfile.mysql -t liuxy0551/yice-mysql .
docker buildx build --platform linux/amd64 -f Dockerfile.server -t liuxy0551/yice-server ../

此時執行 pnpm build:docker 即可打包鏡像。

多平臺打包鏡像

由於我們目前使用的 Mac M 系列晶元較多,這是 arm64 v8 平臺的,但往往我們打包後的鏡像是在 x86 的機器上使用,比如 Centos、Ubuntu 等伺服器系統,這就要求我們應該相容 x86 平臺。
使用 docker inspect 的命令可以查看鏡像架構,如下:

docker pull alpine
docker inspect alpine | grep Architecture

修改剛剛寫的 Dockerfile 文件,支持通過 docker build 命令的 build argument 傳遞參數,這在明確不同平臺使用的基礎鏡像時比較有用。有些常用的基礎鏡像是支持多平臺,只需要添加 --platform linux/amd64, linux/arm64 即可,docker buildx 會自動處理一切,yice-mysql 支持了 arm64 v8,其他內容可以自行研究。

鏡像發佈

這裡使用的是阿裡雲容器鏡像服務:https://cr.console.aliyun.com/

 docker login --username=your_username -p your_password registry.cn-hangzhou.aliyuncs.com
docker tag liuxy0551/yice-mysql registry.cn-hangzhou.aliyuncs.com/liuxy0551/yice-mysql:latest
docker tag liuxy0551/yice-server registry.cn-hangzhou.aliyuncs.com/liuxy0551/yice-server:latest

docker push registry.cn-hangzhou.aliyuncs.com/liuxy0551/yice-mysql:latest
docker push registry.cn-hangzhou.aliyuncs.com/liuxy0551/yice-server:latest

docker run

為了保證 yice-server 可以訪問到 yice-mysql兩個容器需要使用同一個網路

docker network create yice-network
docker run -p 3306:3306 -d --name yice-mysql --network=yice-network -v /opt/dtstack/yice-performance/yice-mysql/conf:/etc/mysql/conf.d -v /opt/dtstack/yice-performance/yice-mysql/log:/var/log/mysql -v /opt/dtstack/yice-performance/yice-mysql/data:/var/lib/mysql registry.cn-hangzhou.aliyuncs.com/liuxy0551/yice-mysql:latest
docker run -p 4000:4000 -d --name yice-server --network=yice-network -v /opt/dtstack/yice-performance/yice-report:/yice-performance/apps/server/yice-report registry.cn-hangzhou.aliyuncs.com/liuxy0551/yice-server:latest
  • -p 表示埠映射,-p 宿主機 port:容器 port,這裡暴漏埠是為了外部可以通過 GUI 工具查看數據
  • -d 表示後臺運行並返回容器 id
  • --name 表示給容器指定的名稱
  • -v /opt/dtstack/yice-performance/yice-mysql:/etc/mysql/conf.d 等掛載路徑表示將容器中的配置項、數據、日誌都掛載到主機的 /opt/dtstack/yice-performance/yice-mysql
  • -v /opt/dtstack/yice-performance/yice-report:/yice-performance/apps/server/yice-report 表示將容器中的檢測報告掛載到宿主機
  • 掛載的目的是為了在刪除容器時數據不丟失,且儘量保持容器存儲層不發生寫操作。

執行 docker run 命令生成容器並運行,訪問 http://localhost:4000 即可看到頁面了。

docker-compose

docker-compose 是 Docker 官方提供的一個工具,用於管理多個 Docker 容器的應用程式,使用 docker-compose 可以協同多個容器運行。
新增 docker-compose.yml 文件,在這個文件里定義應用程式所需的服務和容器,包括鏡像、環境變數、埠映射、掛載目錄等信息。

version: '3'

services:
    mysql-service:
        container_name: yice-mysql
        image: registry.cn-hangzhou.aliyuncs.com/liuxy0551/yice-server:latest
        ports:
            - '3306:3306'
        restart: always
        networks:
            - yice-network

    server-service:
        container_name: yice-server
        image: registry.cn-hangzhou.aliyuncs.com/liuxy0551/yice-mysql:latest
        ports:
            - '4000:4000'
        restart: always
        depends_on:
            - mysql-service
        networks:
            - yice-network

networks:
  yice-network:
    driver: bridge
docker-compose -f docker/docker-compose.yml -p yice-performance up -d
命令 作用
docker-compose up 啟動程式,-d 後臺運行
docker-compose down 停止並移除容器、捲、鏡像等
docker-compose ps 列出正在運行的容器
docker-compose logs 查看日誌
docker-compose stop 停止服務
docker-compose start 啟動服務
docker-compose restart 重啟服務

四、常見問題

yice-server 無法啟動

可能是 docker 版本較低,建議升級到 docker v24 及以上,升級前應當備份。

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

image.pngimage.png
image.png

node[1]: ../src/node_platform.cc:61:std::unique_ptr<long unsigned int> node::WorkerThreadsTaskRunner::DelayedTaskScheduler::Start(): Assertion `(0) == (uv_thread_create(t.get(), start_thread, this))' failed.
 1: 0xb090e0 node::Abort() [node]
 2: 0xb0915e  [node]
 3: 0xb7512e  [node]
 4: 0xb751f6 node::NodePlatform::NodePlatform(int, v8::TracingController*) [node]
 5: 0xacbf74 node::InitializeOncePerProcess(int, char**, node::InitializationSettingsFlags, node::ProcessFlags::Flags) [node]
 6: 0xaccb59 node::Start(int, char**) [node]
 7: 0x7f2ffac64d90  [/lib/x86_64-linux-gnu/libc.so.6]
 8: 0x7f2ffac64e40 __libc_start_main [/lib/x86_64-linux-gnu/libc.so.6]
 9: 0xa408ec  [node]
gcc 版本過低

主機部署時建議使用 Ubuntu。
主機模式部署時 CentOS7 上啟動服務時報錯:Error: /lib64/libstdc++.so.6: version 'CXXABI_1.3.9' not found,這是因為 CentOS7gcc 版本過低,需要升級到 gcc-4.8.5 以上,執行下方命令可以看到沒有 CXXABI_1.3.9

strings /lib64/libstdc++.so.6 | grep CXXABI

相關鏈接:
https://github.com/Automattic/node-canvas/issues/1796
https://gist.github.com/nchaigne/ad06bc867f911a3c0d32939f1e930a11
https://ftp.gnu.org/gnu/gcc/

cd /etc/gcc
wget https://ftp.gnu.org/gnu/gcc/gcc-9.5.0/gcc-9.5.0.tar.gz
tar xzvf gcc-9.5.0.tar.gz
mkdir obj.gcc-9.5.0
cd gcc-9.5.0
./contrib/download_prerequisites
cd ../obj.gcc-9.5.0
../gcc-9.5.0/configure --disable-multilib --enable-languages=c,c++
make -j $(nproc)
make install

最後

歡迎關註【袋鼠雲數棧UED團隊】~
袋鼠雲數棧 UED 團隊持續為廣大開發者分享技術成果,相繼參與開源了歡迎 star


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在我們容器虛擬化產品開發過程中,時長會遇到某些應用無法啟動或運行時異常崩潰的問題;讓應用行為信息豐富,則能還原應用異常發生過程,對我們快速分析問題至關重要。 ...
  • 原文:Jetpack Compose學習(12)——Material Theme的主題色切換-Stars-One的雜貨小窩 閑著無事研究了下Jetpack Compose M3 主題切換效果 本系列以往文章請查看此分類鏈接Jetpack compose學習 如何生成主題 首先,我們需要知道的是,M3 ...
  • RunLoop用於管理事件的迴圈處理機制。運行迴圈在應用程式的主線程中自動啟動,負責監聽和分發各種事件,包括用戶交互(如觸摸事件)、定時器事件、選擇器調用和其他非同步回調。 運行迴圈的作用 運行迴圈的主要作用包括: 處理輸入事件:運行迴圈監聽用戶的輸入,如觸摸、點擊和滑動事件,並將它們分發到適當的處理 ...
  • 在實際開發中,經常需要對tableView或者collectionView執行更新數據源的操作,reloadData是一個常見的方法。這是 UITableView 和 UICollectionView 提供的一個方法,用於重新載入視圖的所有可見行(或項)。 當調用 reloadData 方法時,UI ...
  • AndroidStudio卸載 如果已經安裝:首先先卸載AndroidStudio,最好是使用軟體管理軟體進行卸載(遮這樣卸載的比較乾凈)。 找到你的C:\Users\Administrator.gradle,並且刪除掉【如果出現文件正在占用,你需要重啟電腦,否則刪不掉】 java安裝 我們安卓開 ...
  • 前言 今天複習了一些前端演算法題,寫到一兩道比較有意思的題:重建二叉樹、反向輸出鏈表每個節點 題目 重建二叉樹: 輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重覆的數字。例如輸入前序遍歷序列 {1,2,4,7,3,5,6,8} 和中序遍歷序列 { ...
  • title: Nuxt.js必讀:輕鬆掌握運行時配置與 useRuntimeConfig date: 2024/7/29 updated: 2024/7/29 author: cmdragon excerpt: 本文詳細介紹了Nuxt.js中的運行時配置功能,包括定義和使用運行時配置的方法,以及如何 ...
  • ‍ 寫在開頭 點贊 + 收藏 學會 axios的兩種調用方式 經常調介面的同學一定非常熟悉aixos下麵的兩種使用方式: axios(config) // 配置式請求 axios({ method: 'post', url: '/user/12345', }); axios.po ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...