perf: 优化首页加载速度 (#6461)

This commit is contained in:
zhengkunwang 2024-09-11 22:12:16 +08:00 committed by GitHub
parent fc70345fcd
commit d2ca265cc2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 239 additions and 148 deletions

View File

@ -2,6 +2,7 @@ package v1
import (
"errors"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/constant"
@ -55,25 +56,17 @@ func (b *BaseApi) LoadDashboardBaseInfo(c *gin.Context) {
// @Tags Dashboard
// @Summary Load dashboard current info
// @Description 获取首页实时数据
// @Accept json
// @Param ioOption path string true "request"
// @Param netOption path string true "request"
// @Accept json、
// @Param request body dto.DashboardReq true "request"
// @Success 200 {object} dto.DashboardCurrent
// @Security ApiKeyAuth
// @Router /dashboard/current/:ioOption/:netOption [get]
// @Router /dashboard/current [post]
func (b *BaseApi) LoadDashboardCurrentInfo(c *gin.Context) {
ioOption, ok := c.Params.Get("ioOption")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error ioOption in path"))
var req dto.DashboardReq
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
netOption, ok := c.Params.Get("netOption")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error netOption in path"))
return
}
data := dashboardService.LoadCurrentInfo(ioOption, netOption)
data := dashboardService.LoadCurrentInfo(req)
helper.SuccessWithData(c, data)
}

View File

@ -35,6 +35,12 @@ type OsInfo struct {
DiskSize int64 `json:"diskSize"`
}
type DashboardReq struct {
Scope string `json:"scope"`
IoOption string `json:"ioOption"`
NetOption string `json:"netOption"`
}
type DashboardCurrent struct {
Uptime uint64 `json:"uptime"`
TimeSinceUptime string `json:"timeSinceUptime"`

View File

@ -3,6 +3,10 @@ package service
import (
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/shirou/gopsutil/v3/load"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/net"
network "net"
"os"
"sort"
@ -11,7 +15,6 @@ import (
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/copier"
@ -19,9 +22,6 @@ import (
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/host"
"github.com/shirou/gopsutil/v3/load"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/net"
)
type DashboardService struct{}
@ -29,7 +29,7 @@ type DashboardService struct{}
type IDashboardService interface {
LoadOsInfo() (*dto.OsInfo, error)
LoadBaseInfo(ioOption string, netOption string) (*dto.DashboardBase, error)
LoadCurrentInfo(ioOption string, netOption string) *dto.DashboardCurrent
LoadCurrentInfo(req dto.DashboardReq) *dto.DashboardCurrent
Restart(operation string) error
}
@ -139,79 +139,88 @@ func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto
baseInfo.CPUCores, _ = cpu.Counts(false)
baseInfo.CPULogicalCores, _ = cpu.Counts(true)
baseInfo.CurrentInfo = *u.LoadCurrentInfo(ioOption, netOption)
baseInfo.CurrentInfo = *u.LoadCurrentInfo(dto.DashboardReq{
Scope: "ioNet",
IoOption: ioOption,
NetOption: netOption,
})
return &baseInfo, nil
}
func (u *DashboardService) LoadCurrentInfo(ioOption string, netOption string) *dto.DashboardCurrent {
func (u *DashboardService) LoadCurrentInfo(req dto.DashboardReq) *dto.DashboardCurrent {
var currentInfo dto.DashboardCurrent
if req.Scope == "gpu" {
currentInfo.GPUData = loadGPUInfo()
currentInfo.XPUData = loadXpuInfo()
}
hostInfo, _ := host.Info()
currentInfo.Uptime = hostInfo.Uptime
currentInfo.TimeSinceUptime = time.Now().Add(-time.Duration(hostInfo.Uptime) * time.Second).Format(constant.DateTimeLayout)
currentInfo.Procs = hostInfo.Procs
currentInfo.CPUTotal, _ = cpu.Counts(true)
totalPercent, _ := cpu.Percent(100*time.Millisecond, false)
if len(totalPercent) == 1 {
currentInfo.CPUUsedPercent = totalPercent[0]
currentInfo.CPUUsed = currentInfo.CPUUsedPercent * 0.01 * float64(currentInfo.CPUTotal)
}
currentInfo.CPUPercent, _ = cpu.Percent(100*time.Millisecond, true)
loadInfo, _ := load.Avg()
currentInfo.Load1 = loadInfo.Load1
currentInfo.Load5 = loadInfo.Load5
currentInfo.Load15 = loadInfo.Load15
currentInfo.LoadUsagePercent = loadInfo.Load1 / (float64(currentInfo.CPUTotal*2) * 0.75) * 100
memoryInfo, _ := mem.VirtualMemory()
currentInfo.MemoryTotal = memoryInfo.Total
currentInfo.MemoryAvailable = memoryInfo.Available
currentInfo.MemoryUsed = memoryInfo.Used
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
swapInfo, _ := mem.SwapMemory()
currentInfo.SwapMemoryTotal = swapInfo.Total
currentInfo.SwapMemoryAvailable = swapInfo.Free
currentInfo.SwapMemoryUsed = swapInfo.Used
currentInfo.SwapMemoryUsedPercent = swapInfo.UsedPercent
currentInfo.DiskData = loadDiskInfo()
currentInfo.GPUData = loadGPUInfo()
currentInfo.XPUData = loadXpuInfo()
if ioOption == "all" {
diskInfo, _ := disk.IOCounters()
for _, state := range diskInfo {
currentInfo.IOReadBytes += state.ReadBytes
currentInfo.IOWriteBytes += state.WriteBytes
currentInfo.IOCount += (state.ReadCount + state.WriteCount)
currentInfo.IOReadTime += state.ReadTime
currentInfo.IOWriteTime += state.WriteTime
}
} else {
diskInfo, _ := disk.IOCounters(ioOption)
for _, state := range diskInfo {
currentInfo.IOReadBytes += state.ReadBytes
currentInfo.IOWriteBytes += state.WriteBytes
currentInfo.IOCount += (state.ReadCount + state.WriteCount)
currentInfo.IOReadTime += state.ReadTime
currentInfo.IOWriteTime += state.WriteTime
if req.Scope == "basic" {
currentInfo.TimeSinceUptime = time.Now().Add(-time.Duration(hostInfo.Uptime) * time.Second).Format(constant.DateTimeLayout)
currentInfo.Procs = hostInfo.Procs
currentInfo.CPUTotal, _ = cpu.Counts(true)
totalPercent, _ := cpu.Percent(100*time.Millisecond, false)
if len(totalPercent) == 1 {
currentInfo.CPUUsedPercent = totalPercent[0]
currentInfo.CPUUsed = currentInfo.CPUUsedPercent * 0.01 * float64(currentInfo.CPUTotal)
}
currentInfo.CPUPercent, _ = cpu.Percent(100*time.Millisecond, true)
loadInfo, _ := load.Avg()
currentInfo.Load1 = loadInfo.Load1
currentInfo.Load5 = loadInfo.Load5
currentInfo.Load15 = loadInfo.Load15
currentInfo.LoadUsagePercent = loadInfo.Load1 / (float64(currentInfo.CPUTotal*2) * 0.75) * 100
memoryInfo, _ := mem.VirtualMemory()
currentInfo.MemoryTotal = memoryInfo.Total
currentInfo.MemoryAvailable = memoryInfo.Available
currentInfo.MemoryUsed = memoryInfo.Used
currentInfo.MemoryUsedPercent = memoryInfo.UsedPercent
swapInfo, _ := mem.SwapMemory()
currentInfo.SwapMemoryTotal = swapInfo.Total
currentInfo.SwapMemoryAvailable = swapInfo.Free
currentInfo.SwapMemoryUsed = swapInfo.Used
currentInfo.SwapMemoryUsedPercent = swapInfo.UsedPercent
currentInfo.DiskData = loadDiskInfo()
}
if netOption == "all" {
netInfo, _ := net.IOCounters(false)
if len(netInfo) != 0 {
currentInfo.NetBytesSent = netInfo[0].BytesSent
currentInfo.NetBytesRecv = netInfo[0].BytesRecv
if req.Scope == "ioNet" {
if req.IoOption == "all" {
diskInfo, _ := disk.IOCounters()
for _, state := range diskInfo {
currentInfo.IOReadBytes += state.ReadBytes
currentInfo.IOWriteBytes += state.WriteBytes
currentInfo.IOCount += (state.ReadCount + state.WriteCount)
currentInfo.IOReadTime += state.ReadTime
currentInfo.IOWriteTime += state.WriteTime
}
} else {
diskInfo, _ := disk.IOCounters(req.IoOption)
for _, state := range diskInfo {
currentInfo.IOReadBytes += state.ReadBytes
currentInfo.IOWriteBytes += state.WriteBytes
currentInfo.IOCount += (state.ReadCount + state.WriteCount)
currentInfo.IOReadTime += state.ReadTime
currentInfo.IOWriteTime += state.WriteTime
}
}
} else {
netInfo, _ := net.IOCounters(true)
for _, state := range netInfo {
if state.Name == netOption {
currentInfo.NetBytesSent = state.BytesSent
currentInfo.NetBytesRecv = state.BytesRecv
if req.NetOption == "all" {
netInfo, _ := net.IOCounters(false)
if len(netInfo) != 0 {
currentInfo.NetBytesSent = netInfo[0].BytesSent
currentInfo.NetBytesRecv = netInfo[0].BytesRecv
}
} else {
netInfo, _ := net.IOCounters(true)
for _, state := range netInfo {
if state.Name == req.NetOption {
currentInfo.NetBytesSent = state.BytesSent
currentInfo.NetBytesRecv = state.BytesRecv
}
}
}
}

View File

@ -18,7 +18,7 @@ func (s *DashboardRouter) InitRouter(Router *gin.RouterGroup) {
{
cmdRouter.GET("/base/os", baseApi.LoadDashboardOsInfo)
cmdRouter.GET("/base/:ioOption/:netOption", baseApi.LoadDashboardBaseInfo)
cmdRouter.GET("/current/:ioOption/:netOption", baseApi.LoadDashboardCurrentInfo)
cmdRouter.POST("/current", baseApi.LoadDashboardCurrentInfo)
cmdRouter.POST("/system/restart/:operation", baseApi.SystemRestart)
}
}

View File

@ -105,4 +105,10 @@ export namespace Dashboard {
power: string;
memoryUtil: string;
}
export interface DashboardReq {
scope: string;
ioOption: string;
netOption: string;
}
}

View File

@ -9,8 +9,8 @@ export const loadBaseInfo = (ioOption: string, netOption: string) => {
return http.get<Dashboard.BaseInfo>(`/dashboard/base/${ioOption}/${netOption}`);
};
export const loadCurrentInfo = (ioOption: string, netOption: string) => {
return http.get<Dashboard.CurrentInfo>(`/dashboard/current/${ioOption}/${netOption}`);
export const loadCurrentInfo = (req: Dashboard.DashboardReq) => {
return http.post<Dashboard.CurrentInfo>(`/dashboard/current`, req);
};
export const systemRestart = (operation: string) => {

View File

@ -309,6 +309,7 @@ const isProductPro = ref();
const searchInfo = reactive({
ioOption: 'all',
netOption: 'all',
scope: 'all',
});
const baseInfo = ref<Dashboard.BaseInfo>({
@ -416,79 +417,153 @@ const onLoadBaseInfo = async (isInit: boolean, range: string) => {
}
const res = await loadBaseInfo(searchInfo.ioOption, searchInfo.netOption);
baseInfo.value = res.data;
currentInfo.value = baseInfo.value.currentInfo;
await onLoadCurrentInfo();
const resData = res.data.currentInfo;
currentInfo.value.ioReadBytes = resData.ioReadBytes;
currentInfo.value.ioWriteBytes = resData.ioWriteBytes;
currentInfo.value.ioCount = resData.ioCount;
currentInfo.value.ioReadTime = resData.ioReadTime;
currentInfo.value.ioWriteTime = resData.ioWriteTime;
currentInfo.value.netBytesSent = resData.netBytesSent;
currentInfo.value.netBytesRecv = resData.netBytesRecv;
currentInfo.value.uptime = resData.uptime;
loadAppCurrentInfo();
isStatusInit.value = false;
statusRef.value.acceptParams(currentInfo.value, baseInfo.value, isStatusInit.value);
appRef.value.acceptParams();
if (isInit) {
timer = setInterval(async () => {
if (isActive.value && !globalStore.isOnRestart) {
await onLoadCurrentInfo();
loadAppCurrentInfo();
}
}, 3000);
}
};
const onLoadCurrentInfo = async () => {
const res = await loadCurrentInfo(searchInfo.ioOption, searchInfo.netOption);
currentInfo.value.timeSinceUptime = res.data.timeSinceUptime;
let timeInterval = Number(res.data.uptime - currentInfo.value.uptime) || 3;
currentChartInfo.netBytesSent =
res.data.netBytesSent - currentInfo.value.netBytesSent > 0
? Number(((res.data.netBytesSent - currentInfo.value.netBytesSent) / 1024 / timeInterval).toFixed(2))
: 0;
netBytesSents.value.push(currentChartInfo.netBytesSent);
if (netBytesSents.value.length > 20) {
netBytesSents.value.splice(0, 1);
}
currentChartInfo.netBytesRecv =
res.data.netBytesRecv - currentInfo.value.netBytesRecv > 0
? Number(((res.data.netBytesRecv - currentInfo.value.netBytesRecv) / 1024 / timeInterval).toFixed(2))
: 0;
netBytesRecvs.value.push(currentChartInfo.netBytesRecv);
if (netBytesRecvs.value.length > 20) {
netBytesRecvs.value.splice(0, 1);
}
currentChartInfo.ioReadBytes =
res.data.ioReadBytes - currentInfo.value.ioReadBytes > 0
? Number(((res.data.ioReadBytes - currentInfo.value.ioReadBytes) / 1024 / 1024 / timeInterval).toFixed(2))
: 0;
ioReadBytes.value.push(currentChartInfo.ioReadBytes);
if (ioReadBytes.value.length > 20) {
ioReadBytes.value.splice(0, 1);
}
currentChartInfo.ioWriteBytes =
res.data.ioWriteBytes - currentInfo.value.ioWriteBytes > 0
? Number(((res.data.ioWriteBytes - currentInfo.value.ioWriteBytes) / 1024 / 1024 / timeInterval).toFixed(2))
: 0;
ioWriteBytes.value.push(currentChartInfo.ioWriteBytes);
if (ioWriteBytes.value.length > 20) {
ioWriteBytes.value.splice(0, 1);
}
currentChartInfo.ioCount = Math.round(Number((res.data.ioCount - currentInfo.value.ioCount) / timeInterval));
let ioReadTime = res.data.ioReadTime - currentInfo.value.ioReadTime;
let ioWriteTime = res.data.ioWriteTime - currentInfo.value.ioWriteTime;
let ioChoose = ioReadTime > ioWriteTime ? ioReadTime : ioWriteTime;
currentChartInfo.ioTime = Math.round(Number(ioChoose / timeInterval));
timeIODatas.value.push(dateFormatForSecond(res.data.shotTime));
if (timeIODatas.value.length > 20) {
timeIODatas.value.splice(0, 1);
}
timeNetDatas.value.push(dateFormatForSecond(res.data.shotTime));
if (timeNetDatas.value.length > 20) {
timeNetDatas.value.splice(0, 1);
}
loadData();
currentInfo.value = res.data;
const loadAppCurrentInfo = async () => {
await Promise.all([onLoadCurrentInfo('gpu'), onLoadCurrentInfo('basic'), onLoadCurrentInfo('ioNet')]);
statusRef.value.acceptParams(currentInfo.value, baseInfo.value, isStatusInit.value);
};
const onLoadCurrentInfo = async (scope: string) => {
const req = {
scope: scope,
ioOption: searchInfo.ioOption,
netOption: searchInfo.netOption,
};
const res = await loadCurrentInfo(req);
const resData = res.data;
if (scope === 'ioNet') {
let timeInterval = Number(res.data.uptime - currentInfo.value.uptime) || 3;
currentChartInfo.netBytesSent =
res.data.netBytesSent - currentInfo.value.netBytesSent > 0
? Number(((res.data.netBytesSent - currentInfo.value.netBytesSent) / 1024 / timeInterval).toFixed(2))
: 0;
console.log('value', res.data.netBytesSent - currentInfo.value.netBytesSent);
console.log(
'number',
Number(((res.data.netBytesSent - currentInfo.value.netBytesSent) / 1024 / timeInterval).toFixed(2)),
);
netBytesSents.value.push(currentChartInfo.netBytesSent);
if (netBytesSents.value.length > 20) {
netBytesSents.value.splice(0, 1);
}
currentChartInfo.netBytesRecv =
res.data.netBytesRecv - currentInfo.value.netBytesRecv > 0
? Number(((res.data.netBytesRecv - currentInfo.value.netBytesRecv) / 1024 / timeInterval).toFixed(2))
: 0;
netBytesRecvs.value.push(currentChartInfo.netBytesRecv);
if (netBytesRecvs.value.length > 20) {
netBytesRecvs.value.splice(0, 1);
}
currentChartInfo.ioReadBytes =
res.data.ioReadBytes - currentInfo.value.ioReadBytes > 0
? Number(
((res.data.ioReadBytes - currentInfo.value.ioReadBytes) / 1024 / 1024 / timeInterval).toFixed(2),
)
: 0;
ioReadBytes.value.push(currentChartInfo.ioReadBytes);
if (ioReadBytes.value.length > 20) {
ioReadBytes.value.splice(0, 1);
}
currentChartInfo.ioWriteBytes =
res.data.ioWriteBytes - currentInfo.value.ioWriteBytes > 0
? Number(
((res.data.ioWriteBytes - currentInfo.value.ioWriteBytes) / 1024 / 1024 / timeInterval).toFixed(
2,
),
)
: 0;
ioWriteBytes.value.push(currentChartInfo.ioWriteBytes);
if (ioWriteBytes.value.length > 20) {
ioWriteBytes.value.splice(0, 1);
}
currentChartInfo.ioCount = Math.round(Number((res.data.ioCount - currentInfo.value.ioCount) / timeInterval));
let ioReadTime = res.data.ioReadTime - currentInfo.value.ioReadTime;
let ioWriteTime = res.data.ioWriteTime - currentInfo.value.ioWriteTime;
let ioChoose = ioReadTime > ioWriteTime ? ioReadTime : ioWriteTime;
currentChartInfo.ioTime = Math.round(Number(ioChoose / timeInterval));
timeIODatas.value.push(dateFormatForSecond(res.data.shotTime));
if (timeIODatas.value.length > 20) {
timeIODatas.value.splice(0, 1);
}
timeNetDatas.value.push(dateFormatForSecond(res.data.shotTime));
if (timeNetDatas.value.length > 20) {
timeNetDatas.value.splice(0, 1);
}
loadData();
currentInfo.value.ioReadBytes = resData.ioReadBytes;
currentInfo.value.ioWriteBytes = resData.ioWriteBytes;
currentInfo.value.ioCount = resData.ioCount;
currentInfo.value.ioReadTime = resData.ioReadTime;
currentInfo.value.ioWriteTime = resData.ioWriteTime;
currentInfo.value.netBytesSent = resData.netBytesSent;
currentInfo.value.netBytesRecv = resData.netBytesRecv;
}
if (scope === 'gpu') {
currentInfo.value.gpuData = resData.gpuData;
currentInfo.value.xpuData = resData.xpuData;
}
if (scope === 'basic') {
currentInfo.value.uptime = resData.uptime;
currentInfo.value.timeSinceUptime = resData.timeSinceUptime;
currentInfo.value.procs = resData.procs;
currentInfo.value.load1 = resData.load1;
currentInfo.value.load5 = resData.load5;
currentInfo.value.load15 = resData.load15;
currentInfo.value.loadUsagePercent = resData.loadUsagePercent;
currentInfo.value.cpuPercent = resData.cpuPercent;
currentInfo.value.cpuUsedPercent = resData.cpuUsedPercent;
currentInfo.value.cpuUsed = resData.cpuUsed;
currentInfo.value.cpuTotal = resData.cpuTotal;
currentInfo.value.memoryTotal = resData.memoryTotal;
currentInfo.value.memoryAvailable = resData.memoryAvailable;
currentInfo.value.memoryUsed = resData.memoryUsed;
currentInfo.value.memoryUsedPercent = resData.memoryUsedPercent;
currentInfo.value.swapMemoryTotal = resData.swapMemoryTotal;
currentInfo.value.swapMemoryAvailable = resData.swapMemoryAvailable;
currentInfo.value.swapMemoryUsed = resData.swapMemoryUsed;
currentInfo.value.swapMemoryUsedPercent = resData.swapMemoryUsedPercent;
currentInfo.value.timeSinceUptime = res.data.timeSinceUptime;
currentInfo.value.shotTime = resData.shotTime;
currentInfo.value.diskData = resData.diskData;
}
};
function loadUpTime(uptime: number) {
if (uptime <= 0) {
return '-';

View File

@ -159,7 +159,9 @@
/>
</template>
</el-popover>
<span class="input-help">{{ computeSize(item.used) }} / {{ computeSize(item.total) }}</span>
<span class="input-help" v-if="chartsOption[`disk${index}`]">
{{ computeSize(item.used) }} / {{ computeSize(item.total) }}
</span>
</el-col>
</template>
<template v-for="(item, index) of currentInfo.gpuData" :key="index">
@ -385,9 +387,6 @@ const acceptParams = (current: Dashboard.CurrentInfo, base: Dashboard.BaseInfo,
data: formatNumber(Number(currentInfo.value.gpuData[i].gpuUtil.replaceAll(' %', ''))),
};
}
if (currentInfo.value.diskData.length + currentInfo.value.gpuData.length > 5) {
showMore.value = isInit ? false : showMore.value || false;
}
currentInfo.value.xpuData = currentInfo.value.xpuData || [];
for (let i = 0; i < currentInfo.value.xpuData.length; i++) {
chartsOption.value['gpu' + i] = {
@ -395,6 +394,9 @@ const acceptParams = (current: Dashboard.CurrentInfo, base: Dashboard.BaseInfo,
data: formatNumber(Number(currentInfo.value.xpuData[i].memoryUtil.replaceAll('%', ''))),
};
}
if (currentInfo.value.diskData.length + currentInfo.value.gpuData.length > 5) {
showMore.value = isInit ? false : showMore.value || false;
}
});
};