Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 前端增加自适应限流的选项 #256

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions web/src/polaris/administration/accessLimiting/detail/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@ import DetailPage from '@src/polaris/common/duckComponents/DetailPage'
import { Values } from '../operations/CreateDuck'

import { Form, Card, Text, Table, H6, FormItem, FormText } from 'tea-component'
import { LimitType, LimitTypeMap, LimitMethodTypeMap, LimitAction, LimitActionMap, LimitFailoverMap } from '../types'
import {
LimitResource,
LimitResourceMap,
LimitType,
LimitTypeMap,
LimitMethodTypeMap,
LimitAction,
LimitActionMap,
LimitFailoverMap, MaxAmountUnit, MaxAmountHeader,
} from '../types'
import insertCSS from '@src/polaris/common/helpers/insertCSS'

insertCSS(
Expand Down Expand Up @@ -38,6 +47,7 @@ export default purify(function AccessLimitingDetailPag(props: DuckCmpProps<Acces
const { ruleDetail } = selector(store)
const {
name,
resource: strResource,
type: strLimitType,
namespace,
service,
Expand Down Expand Up @@ -69,6 +79,11 @@ export default purify(function AccessLimitingDetailPag(props: DuckCmpProps<Acces
<FormItem label='限流规则名称'>
<FormText>{name || '-'}</FormText>
</FormItem>

<FormItem label='限流资源'>
<FormText>{LimitResourceMap[strResource]}</FormText>
</FormItem>

<FormItem label='限流类型'>
<FormText>{LimitTypeMap[strLimitType]}</FormText>
</FormItem>
Expand Down Expand Up @@ -183,12 +198,25 @@ export default purify(function AccessLimitingDetailPag(props: DuckCmpProps<Acces
)
},
},
strResource === LimitResource.CPU && {
key: 'precision',
header: '滑动窗口精度',
render: item => {
const { precision } = item
return <Text>{precision}</Text>
},
},
{
key: 'maxAmount',
header: '请求数阈值',
header: MaxAmountHeader[strResource],
render: item => {
const { maxAmount } = item
return <Text>{maxAmount}次</Text>
return (
<Text>
{maxAmount}
{MaxAmountUnit[strResource]}
</Text>
)
},
},
]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export default class AccessLimitingDetailPageDuck extends DetailPage {
maxAmount: o.maxAmount,
validDurationNum: Number(o.validDuration.substring(0, o.validDuration.length - 1)),
validDurationUnit: o.validDuration.substring(o.validDuration.length - 1, o.validDuration.length),
precision: o.precision,
}))
: [],
arguments:
Expand Down
6 changes: 4 additions & 2 deletions web/src/polaris/administration/accessLimiting/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
LimitMethodType,
LimitArgumentsType,
LimitFailover,
LimitAmountsValidationUnit,
LimitAmountsValidationUnit, LimitResource,
} from './types'

export interface DescribeLimitRulesParams {
Expand All @@ -26,6 +26,7 @@ export interface DescribeLimitRulesParams {
export interface LimitConfig {
validDuration: string
maxAmount: number
precision: number
}

export interface LimitConfigForFormFilling {
Expand All @@ -34,6 +35,7 @@ export interface LimitConfigForFormFilling {
maxAmount: number
validDurationNum: number
validDurationUnit: LimitAmountsValidationUnit
precision: number // 滑动窗口精度
}

interface LimitMethodConfig {
Expand Down Expand Up @@ -101,6 +103,7 @@ export async function describeLimitRules(params: DescribeLimitRulesParams) {
export interface CreateLimitRulesBaseParams {
id?: string
name: string // 规则名
resource: LimitResource // 限流资源
type: LimitType // 限流类型
namespace: string // 规则所属命名空间
service: string // 规则所属服务名
Expand All @@ -110,7 +113,6 @@ export interface CreateLimitRulesBaseParams {
max_queue_delay: number // 匀速排队的最大排队时长
failover: LimitFailover // 失败处理策略
disable: boolean // 是否停用该限流规则,默认启用
resource: string
}

export interface CreateLimitRulesParams extends CreateLimitRulesBaseParams {
Expand Down
75 changes: 65 additions & 10 deletions web/src/polaris/administration/accessLimiting/operations/Create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import Input from '@src/polaris/common/duckComponents/form/Input'
import InputNumber from '@src/polaris/common/duckComponents/form/InputNumber'
import Switch from '@src/polaris/common/duckComponents/form/Switch'
import {
LimitResource,
LimitResourceOptions,
LimitTypeOptions,
LimitType,
LimitMethodTypeOptions,
Expand All @@ -33,7 +35,7 @@ import {
LimitFailoverOptions,
LimitFailover,
LimitAmountsValidationUnit,
LimitAmountsValidationUnitOptions,
LimitAmountsValidationUnitOptions, MaxAmountUnit, MaxAmountHeader, MaxAmountDefault,
} from '../types'
import insertCSS from '@src/polaris/common/helpers/insertCSS'
import { FieldAPI } from '@src/polaris/common/ducks/Form'
Expand Down Expand Up @@ -76,6 +78,7 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps<LimitRule

const {
name: nameField,
resource: resourceField,
type: typeField,
namespace: namespaceField,
service: serviceField,
Expand All @@ -91,6 +94,7 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps<LimitRule
.getAPI(store, dispatch)
.getFields([
'name',
'resource',
'type',
'namespace',
'service',
Expand All @@ -106,10 +110,26 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps<LimitRule

const { type: methodTypeField, value: methodValueField } = methodField.getFields(['type', 'value'])

// 只有单机限流模式才有匀速排队
// 按CPU使用率时,只显式单机限流选项
const limitResource = resourceField.getValue()
const limitTypeOptions =
limitResource === LimitResource.QPS ? LimitTypeOptions : LimitTypeOptions.filter(o => o.value === LimitType.LOCAL)

// 只有QPS单机限流模式才有匀速排队
let limitActionOptions = LimitActionOptions
const limitType = typeField.getValue()
const limitActionOptions =
limitType === LimitType.LOCAL ? LimitActionOptions : LimitActionOptions.filter(o => o.value === LimitAction.REJECT)
if (limitResource === LimitResource.QPS) {
if (limitType === LimitType.LOCAL) {
// 单机QPS限流 展示 快速失败 + 匀速排队
limitActionOptions = LimitActionOptions.filter(o => o.value !== LimitAction.BBR)
} else {
// 分布式QPS限流 只展示 快速失败
limitActionOptions = LimitActionOptions.filter(o => o.value === LimitAction.REJECT)
}
} else {
limitActionOptions = LimitActionOptions.filter(o => o.value === LimitAction.BBR)
}

// 获取arguments amounts列表值
const argumentsList = argumentsField.getValue()
const amountsList = amountsField.getValue()
Expand Down Expand Up @@ -217,7 +237,8 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps<LimitRule

const [serviceInputValue, setServiceInputValue] = React.useState('')

const filteredLimitTypeOptions = LimitTypeOptions
// const filteredLimitTypeOptions = LimitTypeOptions
const filteredLimitResourceOptions = LimitResourceOptions
return (
<DetailPage
store={store}
Expand All @@ -232,10 +253,25 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps<LimitRule
<FormField label='限流规则名称' field={nameField} message='最长64个字符' required>
<Input field={nameField} maxLength={64} size='l' />
</FormField>

<FormField label='限流资源' field={resourceField} required>
<Segment
value={resourceField.getValue()}
options={filteredLimitResourceOptions}
onChange={value => {
resourceField.setValue(LimitResource[value])
if (value === LimitResource.CPU) {
typeField.setValue(LimitType.LOCAL)
actionField.setValue(LimitAction.BBR)
}
}}
/>
</FormField>

<FormField label='限流类型' field={typeField} required>
<Segment
value={typeField.getValue()}
options={filteredLimitTypeOptions}
options={limitTypeOptions}
onChange={value => {
typeField.setValue(LimitType[value])
if (value === LimitType.GLOBAL) {
Expand Down Expand Up @@ -458,7 +494,7 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps<LimitRule
const { id } = o.getFields(['id'])
return id.getValue()
}}
style={{ width: '400px' }}
style={{ width: '550px' }}
records={[...amountsField.asArray()]}
columns={[
{
Expand Down Expand Up @@ -493,13 +529,31 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps<LimitRule
)
},
},
limitResource === LimitResource.CPU && {
key: 'precision',
header: '滑动窗口精度',
render: item => {
const { precision } = item.getFields(['precision'])
return (
<InputAdornment>
<InputNumber
field={precision}
min={1}
onInputChange={value => precision.setValue(+value)}
hideButton
size='l'
/>
</InputAdornment>
)
},
},
{
key: 'maxAmount',
header: '请求数阈值',
header: MaxAmountHeader[limitResource],
render: item => {
const { maxAmount } = item.getFields(['maxAmount'])
return (
<InputAdornment after='次'>
<InputAdornment after={MaxAmountUnit[limitResource]}>
<InputNumber
field={maxAmount}
min={1}
Expand Down Expand Up @@ -545,9 +599,10 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps<LimitRule
onClick={() =>
amountsField.asArray().push({
id: `${Math.round(Math.random() * 10000)}`,
maxAmount: 1,
maxAmount: MaxAmountDefault[limitResource],
validDurationNum: 1,
validDurationUnit: LimitAmountsValidationUnit.s,
precision: 10,
})
}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ export default class LimitRuleCreatePageDuck extends DetailPage {
const handledAmounts = values.amounts.map(item => ({
maxAmount: item.maxAmount,
validDuration: `${item.validDurationNum}${item.validDurationUnit}`,
precision: item.precision,
}))

const handledArguments = values.arguments.map(item => ({
Expand Down Expand Up @@ -278,6 +279,7 @@ export default class LimitRuleCreatePageDuck extends DetailPage {
maxAmount: o.maxAmount,
validDurationNum: Number(o.validDuration.substring(0, o.validDuration.length - 1)),
validDurationUnit: o.validDuration.substring(o.validDuration.length - 1, o.validDuration.length),
precision: o.precision,
}))
: [],
arguments:
Expand Down
56 changes: 52 additions & 4 deletions web/src/polaris/administration/accessLimiting/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,48 @@ export interface Lists {
serviceList: []
}

// 限制资源类型,支持QPS, CPU
export enum LimitResource {
QPS = 'QPS',
// CONCURRENCY = 'CONCURRENCY', // 并发量
CPU = 'CPU',
}
export const LimitResourceOptions = [
{
value: LimitResource.QPS,
text: 'QPS',
},
{
value: LimitResource.CPU,
text: 'CPU使用率',
},
]
export const LimitResourceMap = LimitResourceOptions.reduce((map, curr) => {
map[curr.value] = curr.text
return map
}, {})

// 阈值的标题
export enum MaxAmountHeader {
QPS = '请求数阈值',
// CONCURRENCY = '次',
CPU = 'CPU使用率阈值',
}

// 阈值的计数单位
export enum MaxAmountUnit {
QPS = '次',
// CONCURRENCY = '次',
CPU = '%',
}

// 阈值的计数单位
export enum MaxAmountDefault {
QPS = 1,
// CONCURRENCY = '次',
CPU = 80,
}

// 限流类型,支持LOCAL(单机限流), GLOBAL(分布式限流)
export enum LimitType {
GLOBAL = 'GLOBAL',
Expand All @@ -26,10 +68,11 @@ export const LimitTypeMap = LimitTypeOptions.reduce((map, curr) => {
return map
}, {})

// 限流效果,支持REJECT(直接拒绝),UNIRATE(匀速排队),默认REJECT
// 限流效果,支持REJECT(直接拒绝),UNIRATE(匀速排队),BBR(自适应),默认REJECT
export enum LimitAction {
REJECT = 'REJECT',
UNIRATE = 'UNIRATE',
REJECT = 'REJECT', // 实现为令牌桶
UNIRATE = 'UNIRATE', // 实现为漏桶
BBR = 'BBR',
}
export const LimitActionOptions = [
{
Expand All @@ -40,6 +83,10 @@ export const LimitActionOptions = [
value: LimitAction.UNIRATE,
text: '匀速排队',
},
{
value: LimitAction.BBR,
text: '自适应',
},
]

export const LimitActionMap = LimitActionOptions.reduce((map, curr) => {
Expand Down Expand Up @@ -213,12 +260,13 @@ export const generateDefaultValues: Values = {
validDurationNum: 1,
validDurationUnit: LimitAmountsValidationUnit.s,
maxAmount: 1,
precision: 10,
},
],
regex_combine: true,
action: LimitAction.REJECT,
max_queue_delay: 1,
failover: LimitFailover.FAILOVER_LOCAL,
disable: true,
resource: 'QPS',
resource: LimitResource.QPS,
}