1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-03-13 17:24:44 +08:00

feat: PHP 增加性能调整配置 (#6420)

This commit is contained in:
zhengkunwang 2024-09-09 17:08:04 +08:00 committed by GitHub
parent 7aefd0df1a
commit ad3670c9ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 326 additions and 9 deletions

View File

@ -76,6 +76,13 @@ func (b *BaseApi) DeleteRuntime(c *gin.Context) {
helper.SuccessWithOutData(c)
}
// @Tags Website
// @Summary Delete runtime
// @Description 删除运行环境校验
// @Accept json
// @Success 200
// @Security ApiKeyAuth
// @Router /installed/delete/check/:id [get]
func (b *BaseApi) DeleteRuntimeCheck(c *gin.Context) {
runTimeId, err := helper.GetIntParamByKey(c, "runTimeId")
if err != nil {
@ -362,7 +369,6 @@ func (b *BaseApi) UpdatePHPFile(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
// 写一个调用 GetPHPConfigFile 的方法
// @Tags Runtime
// @Summary Get php conf file
// @Description 获取 php 配置文件
@ -383,3 +389,45 @@ func (b *BaseApi) GetPHPConfigFile(c *gin.Context) {
}
helper.SuccessWithData(c, data)
}
// @Tags Runtime
// @Summary Update fpm config
// @Description 更新 fpm 配置
// @Accept json
// @Param request body request.FPMConfig true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /runtimes/php/fpm/config [post]
func (b *BaseApi) UpdateFPMConfig(c *gin.Context) {
var req request.FPMConfig
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
if err := runtimeService.UpdateFPMConfig(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithOutData(c)
}
// @Tags Runtime
// @Summary Get fpm config
// @Description 获取 fpm 配置
// @Accept json
// @Param id path integer true "request"
// @Success 200 {object} response.FPMConfig
// @Security ApiKeyAuth
// @Router /runtimes/php/fpm/config/:id [get]
func (b *BaseApi) GetFPMConfig(c *gin.Context) {
id, err := helper.GetParamID(c)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, nil)
return
}
data, err := runtimeService.GetFPMConfig(id)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}

View File

@ -95,3 +95,8 @@ type PHPFileReq struct {
ID uint `json:"id" validate:"required"`
Type string `json:"type" validate:"required"`
}
type FPMConfig struct {
ID uint `json:"id" validate:"required"`
Params map[string]interface{} `json:"params" validate:"required"`
}

View File

@ -37,6 +37,14 @@ func (r *Runtime) GetPath() string {
return path.Join(constant.RuntimeDir, r.Type, r.Name)
}
func (r *Runtime) GetFPMPath() string {
return path.Join(constant.RuntimeDir, r.Type, r.Name, "conf", "php-fpm.conf")
}
func (r *Runtime) GetPHPPath() string {
return path.Join(constant.RuntimeDir, r.Type, r.Name, "conf", "php.ini")
}
func (r *Runtime) GetLogPath() string {
return path.Join(r.GetPath(), "build.log")
}

View File

@ -58,6 +58,8 @@ type IRuntimeService interface {
UpdatePHPConfig(req request.PHPConfigUpdate) (err error)
UpdatePHPConfigFile(req request.PHPFileUpdate) error
GetPHPConfigFile(req request.PHPFileReq) (*response.FileInfo, error)
UpdateFPMConfig(req request.FPMConfig) error
GetFPMConfig(id uint) (*request.FPMConfig, error)
}
func NewRuntimeService() IRuntimeService {
@ -833,7 +835,7 @@ func (r *RuntimeService) UpdatePHPConfig(req request.PHPConfigUpdate) (err error
phpConfigPath := path.Join(runtime.GetPath(), "conf", "php.ini")
fileOp := files.NewFileOp()
if !fileOp.Stat(phpConfigPath) {
return buserr.WithMap("ErrFileNotFound", map[string]interface{}{"name": "php.ini"}, nil)
return buserr.WithName("ErrFileNotFound", "php.ini")
}
configFile, err := fileOp.OpenFile(phpConfigPath)
if err != nil {
@ -931,3 +933,64 @@ func (r *RuntimeService) UpdatePHPConfigFile(req request.PHPFileUpdate) error {
}
return nil
}
func (r *RuntimeService) UpdateFPMConfig(req request.FPMConfig) error {
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
return err
}
cfg, err := ini.Load(runtime.GetFPMPath())
if err != nil {
return err
}
for k, v := range req.Params {
var valueStr string
switch v := v.(type) {
case string:
valueStr = v
case int:
valueStr = fmt.Sprintf("%d", v)
case float64:
valueStr = fmt.Sprintf("%.f", v)
default:
continue
}
cfg.Section("www").Key(k).SetValue(valueStr)
}
if err := cfg.SaveTo(runtime.GetFPMPath()); err != nil {
return err
}
return nil
}
var PmKeys = map[string]struct {
}{
"pm": {},
"pm.max_children": {},
"pm.start_servers": {},
"pm.min_spare_servers": {},
"pm.max_spare_servers": {},
}
func (r *RuntimeService) GetFPMConfig(id uint) (*request.FPMConfig, error) {
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(id))
if err != nil {
return nil, err
}
fileOp := files.NewFileOp()
if !fileOp.Stat(runtime.GetFPMPath()) {
return nil, buserr.WithName("ErrFileNotFound", "php-fpm.conf")
}
params := make(map[string]interface{})
cfg, err := ini.Load(runtime.GetFPMPath())
if err != nil {
return nil, err
}
for _, key := range cfg.Section("www").Keys() {
if _, ok := PmKeys[key.Name()]; ok {
params[key.Name()] = key.Value()
}
}
res := &request.FPMConfig{Params: params}
return res, nil
}

View File

@ -13,7 +13,7 @@ func (r *RuntimeRouter) InitRouter(Router *gin.RouterGroup) {
baseApi := v2.ApiGroupApp.BaseApi
{
groupRouter.GET("/installed/delete/check/:runTimeId", baseApi.DeleteRuntimeCheck)
groupRouter.GET("/installed/delete/check/:id", baseApi.DeleteRuntimeCheck)
groupRouter.POST("/search", baseApi.SearchRuntimes)
groupRouter.POST("", baseApi.CreateRuntime)
groupRouter.POST("/del", baseApi.DeleteRuntime)
@ -39,6 +39,7 @@ func (r *RuntimeRouter) InitRouter(Router *gin.RouterGroup) {
groupRouter.POST("/php/config", baseApi.UpdatePHPConfig)
groupRouter.POST("/php/update", baseApi.UpdatePHPFile)
groupRouter.POST("/php/file", baseApi.GetPHPConfigFile)
groupRouter.POST("/php/fpm/config", baseApi.UpdateFPMConfig)
groupRouter.GET("/php/fpm/config/:id", baseApi.GetFPMConfig)
}
}

View File

@ -166,4 +166,9 @@ export namespace Runtime {
id: number;
type: string;
}
export interface FPMConfig {
id: number;
params: any;
}
}

View File

@ -96,3 +96,11 @@ export const UpdatePHPFile = (req: Runtime.PHPUpdate) => {
export const GetPHPConfigFile = (req: Runtime.PHPFileReq) => {
return http.post<File.File>(`/runtimes/php/file`, req);
};
export const UpdateFPMConfig = (req: Runtime.FPMConfig) => {
return http.post(`/runtimes/php/fpm/config`, req);
};
export const GetFPMConfig = (id: number) => {
return http.get<Runtime.FPMConfig>(`/runtimes/php/fpm/config/${id}`);
};

View File

@ -2443,6 +2443,20 @@ const message = {
uninstallExtension: 'Are you sure you want to uninstall the extension {0}',
phpConfigHelper:
'Modifying the configuration requires restarting the operating environment, do you want to continue',
operateMode: 'operation mode',
dynamic: 'dynamic',
static: 'static',
ondemand: 'on-demand',
dynamicHelper:
'dynamically adjust the number of processes, high flexibility, suitable for websites with large traffic fluctuations or low memory',
staticHelper:
'fixed number of processes, suitable for websites with high concurrency and stable traffic, high resource consumption',
ondemandHelper:
'processes are started and destroyed on demand, resource utilization is optimal, but the initial response may be slow',
max_children: 'maximum number of processes allowed to be created',
start_servers: 'number of processes created at startup',
min_spare_servers: 'minimum number of idle processes',
max_spare_servers: 'maximum number of idle processes',
},
process: {
pid: 'Process ID',

View File

@ -2266,6 +2266,17 @@ const message = {
popularExtension: '常用擴充',
uninstallExtension: '是否確認卸載擴充功能 {0}',
phpConfigHelper: '修改配置需要重新啟動運行環境是否繼續',
operateMode: '運行模式',
dynamic: '動態',
static: '靜態',
ondemand: '按需',
dynamicHelper: '動態調整進程數彈性高適合流量波動較大或低記憶體的網站',
staticHelper: '固定進程數適合高併發穩定流量的網站資源消耗較高',
ondemandHelper: '進程按需啟動和銷毀資源利用最優但初始回應可能較慢',
max_children: '允許創建的最大進程數',
start_servers: '啟動時所建立的進程數',
min_spare_servers: '最小空閒行程數',
max_spare_servers: '最大空閒行程數',
},
process: {
pid: '進程ID',

View File

@ -2268,6 +2268,17 @@ const message = {
popularExtension: '常用扩展',
uninstallExtension: '是否确认卸载扩展 {0}',
phpConfigHelper: '修改配置需要重启运行环境是否继续',
operateMode: '运行模式',
dynamic: '动态',
static: '静态',
ondemand: '按需',
dynamicHelper: '动态调整进程数灵活性高适合流量波动较大或者低内存的网站',
staticHelper: '固定进程数适合高并发和稳定流量的网站资源消耗较高',
ondemandHelper: '进程按需启动和销毁资源利用最优但初始响应可能较慢',
max_children: '允许创建的最大进程数',
start_servers: '启动时创建的进程数',
min_spare_servers: '最小空闲进程数',
max_spare_servers: '最大空闲进程数',
},
process: {
pid: '进程ID',

View File

@ -16,7 +16,6 @@
</el-input>
<span class="input-help">{{ $t('php.max_execution_time') }}</span>
</el-form-item>
<el-form-item label="post_max_size" prop="post_max_size">
<el-input clearable v-model.number="form.post_max_size" maxlength="15">
<template #append>M</template>

View File

@ -11,12 +11,15 @@
<el-tab-pane :label="$t('php.uploadMaxSize')" name="2">
<Upload :id="runtime.id" v-if="index == '2'"></Upload>
</el-tab-pane>
<el-tab-pane :label="'php-fpm'" name="3">
<PHP :id="runtime.id" v-if="index == '3'" :type="'fpm'"></PHP>
<el-tab-pane :label="$t('website.nginxPer')" name="5">
<Performance :id="runtime.id" v-if="index == '5'"></Performance>
</el-tab-pane>
<el-tab-pane :label="'php'" name="4">
<el-tab-pane :label="$t('website.source')" name="4">
<PHP :id="runtime.id" v-if="index == '4'" :type="'php'"></PHP>
</el-tab-pane>
<el-tab-pane :label="'FPM ' + $t('website.source')" name="3">
<PHP :id="runtime.id" v-if="index == '3'" :type="'fpm'"></PHP>
</el-tab-pane>
</el-tabs>
</template>
</DrawerPro>
@ -24,11 +27,12 @@
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { Runtime } from '@/api/interface/runtime';
import Config from './config/index.vue';
import Function from './function/index.vue';
import Upload from './upload/index.vue';
import { Runtime } from '@/api/interface/runtime';
import PHP from './php-fpm/index.vue';
import Performance from './performance/index.vue';
const index = ref('0');
const open = ref(false);

View File

@ -0,0 +1,140 @@
<template>
<el-form :model="params" :rules="variablesRules" ref="phpFormRef" label-position="top" v-loading="loading">
<el-row v-loading="loading">
<el-col :span="22" :offset="1">
<el-form-item :label="$t('runtime.operateMode')" prop="pm">
<el-select v-model="params.pm">
<el-option :label="$t('runtime.dynamic')" :value="'dynamic'"></el-option>
<el-option :label="$t('runtime.static')" :value="'static'"></el-option>
<el-option :label="$t('runtime.ondemand')" :value="'ondemand'"></el-option>
</el-select>
<span class="input-help">
<el-text v-if="params.pm == 'dynamic'">{{ $t('runtime.dynamicHelper') }}</el-text>
<el-text v-if="params.pm == 'static'">{{ $t('runtime.staticHelper') }}</el-text>
<el-text v-if="params.pm == 'ondemand'">{{ $t('runtime.ondemandHelper') }}</el-text>
</span>
</el-form-item>
<el-form-item label="max_children" prop="pm.max_children">
<el-input clearable v-model.number="params['pm.max_children']" maxlength="15"></el-input>
<span class="input-help">
{{ $t('runtime.max_children') }}
</span>
</el-form-item>
<el-form-item label="start_servers" prop="pm.start_servers">
<el-input clearable v-model.number="params['pm.start_servers']" maxlength="15"></el-input>
<span class="input-help">
{{ $t('runtime.start_servers') }}
</span>
</el-form-item>
<el-form-item label="min_spare_servers" prop="pm.min_spare_servers">
<el-input clearable v-model.number="params['pm.min_spare_servers']" maxlength="15"></el-input>
<span class="input-help">
{{ $t('runtime.min_spare_servers') }}
</span>
</el-form-item>
<el-form-item label="max_spare_servers" prop="pm.max_spare_servers">
<el-input clearable v-model.number="params['pm.max_spare_servers']" maxlength="15"></el-input>
<span class="input-help">
{{ $t('runtime.max_spare_servers') }}
</span>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSaveStart(phpFormRef)">
{{ $t('commons.button.save') }}
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script lang="ts" setup>
import { GetFPMConfig, UpdateFPMConfig } from '@/api/modules/runtime';
import { checkNumberRange, Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
import { computed, onMounted, reactive, ref } from 'vue';
const props = defineProps({
id: {
type: Number,
default: 0,
},
});
const id = computed(() => {
return props.id;
});
const loading = ref(false);
const phpFormRef = ref();
const initData = () => {
return {
pm: 'dynamic',
'pm.max_children': 150,
'pm.start_servers': 10,
'pm.min_spare_servers': 10,
'pm.max_spare_servers': 30,
};
};
const params = reactive(initData());
const variablesRules = reactive({
pm: [Rules.requiredSelect],
'pm.max_children': [checkNumberRange(0, 5000)],
'pm.start_servers': [checkNumberRange(0, 99999)],
'pm.min_spare_servers': [checkNumberRange(0, 99999)],
'pm.max_spare_servers': [checkNumberRange(0, 99999)],
});
const get = () => {
loading.value = true;
GetFPMConfig(id.value)
.then((res) => {
const resParams = res.data.params;
params['pm'] = resParams['pm'];
params['pm.max_children'] = Number(resParams['pm.max_children']);
params['pm.start_servers'] = Number(resParams['pm.start_servers']);
params['pm.min_spare_servers'] = Number(resParams['pm.min_spare_servers']);
params['pm.max_spare_servers'] = Number(resParams['pm.max_spare_servers']);
})
.finally(() => {
loading.value = false;
});
};
const onSaveStart = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
const action = await ElMessageBox.confirm(
i18n.global.t('runtime.phpConfigHelper'),
i18n.global.t('database.confChange'),
{
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
type: 'info',
},
);
if (action === 'confirm') {
loading.value = true;
submit();
}
});
};
const submit = async () => {
loading.value = true;
UpdateFPMConfig({ id: id.value, params: params })
.then(() => {
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
get();
})
.finally(() => {
loading.value = false;
});
};
onMounted(() => {
get();
});
</script>