cpumassager

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 4, 2021 License: MIT Imports: 9 Imported by: 0

README

cpu-massager-go

cpu-massager是一个过载保护器,称为"CPU按摩器"。

本仓库提供一个用go语言实现用来给CPU做马杀鸡的按摩器,利用该按摩器,可以设定一些参数,根据CPU的状态和所设参数,动态调整拒绝服务的概率,服务程序使用按摩器提供的相关API来决定对收到请求的应对方式:是照常处理还是拒绝服务,以此来让CPU的使用率维持在一个合适的水位,避免服务雪崩。


目录

使用方法

分两步:

  1. 调用StartMassagePlan这个API启动按摩计划;
  2. 调用NeedMassage这个API判断是否要拒绝服务。
启动按摩计划

在程序启动的时候调用StartMassagePlan。例如,在Linux环境下可以使用默认参数直接调用:

func main() {
    err := cpumassager.StartMassagePlan()
    if err != nil {
        handleError() //  处理出错的情况,一般打印一下出错信息
        os.Exit(1) //  然后退出就好了
    }
    serve() //  进入服务程序正常处理流程
}

有需要调整相关参数的可以使用WithXXX系列API来设定相关参数启动按摩计划,具体参数的说明,可以参照代码中对于options结构的注释。

判断是否拒绝服务

程序启动,接收到请求,开始处理之前,先调用NeedMassage这个API来决定是正常处理该请求还是拒绝为其服务返回过载的错误信息。

func handleARequest() {
    if cpumassager.NeedMassage() {
        refuse() //  拒绝服务该请求,做一些简单的处理,例如设定回包的错误码,上报过载告警等
        return  //  然后直接返回
    }
    process() //  正常处理该请求
}

工作原理

按摩器分为如下几个部分:

  1. 提供给服务程序调用的API,具体可以参照"使用方法"部分的说明;
  2. 按摩器内部的CPU使用率收集器、记录器和用于判断是否需要拒绝服务的决断器。

按摩器涉及模块的示意图:

工作原理示意图

CPU使用率收集器

服务程序启动按摩计划之后,按摩器就会启动一个routine来每隔1秒钟定期收集CPU使用率。收集器以一个接口的形式提供,不同的操作系统对于CPU使用率的取用方法可能会不一样,可以根据具体情况来提供具体的实现。

Linux平台上CPU使用率,读取procfs(进程文件系统)中的"/proc/stat"文件得到当下的CPU时间,取一个时间段前后的差值就可以得到。具体的可以参照htop的源码LinuxProcessList_scanCPUTime

CPU使用率收集器示意图:

CPU使用率收集器

CPU使用率记录器

记录器用来记录收集器收集到的CPU使用率数据。记录器并不记录所有的CPU使用率数据,而是维护了一系列计数器,每个CPU使用率采集周期,都对每个计数器进行调整:

  1. 如果CPU使用率数据>=当前计数器对应的CPU使用率,那么将该计数器加1,最高加到100;
  2. 如果CPU使用率数据<当前计数器对应的CPU使用率,那么将该计数器减1,最低减至0。

由于每个计数器的范围是[0, 100],这样就维护了最近100个采集周期(也就是最近100秒)的CPU使用率在不同水位的占比情况。例如,如果">=80计数器"的数值是75,那么就表示最近100次采集数据中,有75次CPU使用率不低于80%。维护这样的计数可以避免某[几]次的CPU使用率统计数据可能的误差,用一段时间内的集聚效果来确保获取到最近一段时间的CPU使用率真实水准。

CPU使用率记录器示意图:

CPU使用率记录器

处理方式决断器

处理决断器,用来决定每个请求的处理方式:

  1. 当CPU处在空闲的 轻松 状态时,每个请求都需要正常处理;
  2. 当CPU处在繁忙的 疲累 状态时,需要根据设定参数以动态变化的概率拒绝为相关请求服务。
判断CPU高低负荷

在具体判断CPU的"轻松"和"疲累"状态时,需要在每个CPU使用率采集时间点计算当下的CPU高低负荷,这个是根据启动按摩计划传入的两个参数和CPU记录器的计数器读数计算得到的:

  1. highLoadLevel,高负荷等级,这个是和CPU使用率记录器的计数器相匹配的,按摩器在判断CPU状态的时候,会根据该等级获取对应的计数器读数;
  2. highLoadRatio,高负荷比例,这个需要和高负荷等级配合使用,如果CPU使用率记录器中对应高负荷等级的计数器读数的占比高于高负荷比例,则认为CPU处于 高负荷 中,否则认为CPU处于 低负荷 中。
切换CPU状态

CPU状态由轻松到疲累状态比较简单,CPU使用率采集器每个定期采集动作都会判断CPU是否高负荷,如果是在低负荷时检测到高负荷,直接将CPU状态由"轻松"转变成"疲累"即可。

由疲累到轻松的切换,相对复杂一些,先说明一个 intensity-按摩力度 的概念,按摩力度是指拒绝服务的概率,以百分比表示,取值范围是[0, 100],例如,50表示以50%的概率拒绝服务。

还需要说明一个 CPU持续高/低负荷 的概念,这个会作为CPU疲累程度调整的依据,持续高/低负荷只有CPU处于疲累时才有意义,由每个检查周期得到的highLoadLevel对应计数器读数决定:

  1. 在疲累状态下检测到当前CPU处于高负荷,且本次检查周期得到的highLoadLevel对应计数器读数和上周期相比提高了,那么就认为 CPU持续高负荷
  2. 在疲累状态下检测到当前CPU处于低负荷,且本次检查周期得到的highLoadLevel对应计数器读数和上周期相比降低了,那么就认为 CPU持续低负荷
  3. CPU每次由轻松转变到疲累或者调整按摩力度的时候都会重置changeIntensityTime为currentCPUsageRecordTime。

具体做疲累到轻松的切换时,会根据每个采样动作的判断结果,评估CPU是否持续高/低负荷,以此来对CPU的按摩力度做动态提高或降低,在合适的时机(CPU的按摩力度降为0的时候)才能进入轻松状态,调整按摩力度的时候,需要考虑启动按摩计划时传入的相关参数:

  1. initialIntensity,初始化按摩力度,表示当CPU初次进入疲累状态时候拒绝服务的概率;
  2. stepIntensity,按摩力度调整步进值,如果CPU进入疲累状态后持续处于高负荷/低负荷状态的时间超过配置的检查周期,会以此参数来增加/减少实际的按摩力度;
  3. currentIntensity,实际的按摩力度;
  4. checkPeriodInSeconds,调整按摩力度的检查周期,在CPU处在疲累状态下,CPU状态持续时长超过该值,则会调整按摩力度。

切换CPU状态示意图:

切换CPU状态

疲累时拒绝服务

CPU处于疲累状态时,会根据如下几个方式来决定是否需要拒绝服务:

  1. todoTasks,待处理任务数,疲累状态下每调用一次NeedMassage()就会加1;
  2. doneTasks,已完成任务数,疲累状态下每次调用NeedMassage()返回false的情况下就会加1;
  3. requireTasks,需要完成的任务数,用如下公式计算得到:todoTasks * (100 - currentIntensity) / 100;
  4. 如果doneTasks < requireTasks,则需要提供服务,否则拒绝服务。

这种拒绝服务的方式,基于本地的信息作出决断,算法也非常简单,可以在不增加额外依赖的情况下,提供均匀的拒绝概率。配合前面的动态按摩力度,达到了在过载时候动态维护高服务水准的目的。

Documentation

Overview

Package cpumassager is a generated GoMock package.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NeedMassage

func NeedMassage() bool

NeedMassage 非是否需要做下马杀鸡放松一下 每次收到请求都调用一下,若返回false,继续做后续处理,否则直接返回

func handleARequest() {
    if cpumassage.NeedMassage() {
        refuse() //  拒绝服务该请求,做一些简单的处理,例如设定回包的错误码,上报过载告警等
        return  //  然后直接返回
    }
    process() //  正常处理该请求
}

func StartMassagePlan

func StartMassagePlan(opts ...Option) error

StartMassagePlan 启动马杀鸡计划,在启动程序后立即调用

func main() {
    err := cpumassage.StartMassagePlan()
    if err != nil {
        handleError() //  处理出错的情况,一般打印一下出错信息
        os.Exit(1) //  然后退出就好了
    }
    serve() //  进入服务程序正常处理流程
}

Types

type CPUsageCollector

type CPUsageCollector interface {
	// GetCPUsage 获取CPU使用率
	GetCPUsage() float64
}

CPUsageCollector 收集CPU使用率的接口

func NewDockerCPUsageCollector added in v0.1.3

func NewDockerCPUsageCollector() (CPUsageCollector, error)

NewDockerCPUsageCollector 新建一个docker的CPU使用率收集器

func NewLinuxCPUsageCollector

func NewLinuxCPUsageCollector() (CPUsageCollector, error)

NewLinuxCPUsageCollector 新建一个linux的CPU使用率收集器

type CounterType

type CounterType int

CounterType 计数器类型,用来记录满足不同条件的CPU使用率情况

const (
	// CounterTypeZero 用来记录CPU使用率>=0情况的计数器
	CounterTypeZero CounterType = 0

	// CounterTypeTen 用来记录CPU使用率>=10情况的计数器
	CounterTypeTen CounterType = 1

	// CounterTypeTwenty 用来记录CPU使用率>=20情况的计数器
	CounterTypeTwenty CounterType = 2

	// CounterTypeThirty 用来记录CPU使用率>=30情况的计数器
	CounterTypeThirty CounterType = 3

	// CounterTypeForty 用来记录CPU使用率>=40情况的计数器
	CounterTypeForty CounterType = 4

	// CounterTypeFifty 用来记录CPU使用率>=50情况的计数器
	CounterTypeFifty CounterType = 5

	// CounterTypeSixty 用来记录CPU使用率>=60情况的计数器
	CounterTypeSixty CounterType = 6

	// CounterTypeSeventy 用来记录CPU使用率>=70情况的计数器
	CounterTypeSeventy CounterType = 7

	// CounterTypeEighty 用来记录CPU使用率>=80情况的计数器
	CounterTypeEighty CounterType = 8

	// CounterTypeNinety 用来记录CPU使用率>=90情况的计数器
	CounterTypeNinety CounterType = 9
)

type MockCPUsageCollector

type MockCPUsageCollector struct {
	// contains filtered or unexported fields
}

MockCPUsageCollector is a mock of CPUsageCollector interface

func NewMockCPUsageCollector

func NewMockCPUsageCollector(ctrl *gomock.Controller) *MockCPUsageCollector

NewMockCPUsageCollector creates a new mock instance

func (*MockCPUsageCollector) EXPECT

EXPECT returns an object that allows the caller to indicate expected use

func (*MockCPUsageCollector) GetCPUsage

func (m *MockCPUsageCollector) GetCPUsage() float64

GetCPUsage mocks base method

type MockCPUsageCollectorMockRecorder

type MockCPUsageCollectorMockRecorder struct {
	// contains filtered or unexported fields
}

MockCPUsageCollectorMockRecorder is the mock recorder for MockCPUsageCollector

func (*MockCPUsageCollectorMockRecorder) GetCPUsage

func (mr *MockCPUsageCollectorMockRecorder) GetCPUsage() *gomock.Call

GetCPUsage indicates an expected call of GetCPUsage

type Option added in v0.1.2

type Option func(*options)

Option 用来设定massagePlan的启动参数的函数

func WithCPUSageCollector added in v0.1.2

func WithCPUSageCollector(cpusageCollector CPUsageCollector) Option

WithCPUSageCollector 用来设定massagePlan的CPU使用率收集器

func WithCheckPeriodInseconds added in v0.1.2

func WithCheckPeriodInseconds(checkPeriodInseconds uint) Option

WithCheckPeriodInseconds 用来设定massagePlan检查CPU状态的周期

func WithHighLoadLevel added in v0.1.2

func WithHighLoadLevel(highLoadLevel CounterType) Option

WithHighLoadLevel 用来设定massagePlan的高负荷等级

func WithInitialIntensity added in v0.1.2

func WithInitialIntensity(initialIntensity uint) Option

WithInitialIntensity 用来设定massagePlan的初始按摩力度

func WithLoadStatusJudgeRatio added in v1.0.0

func WithLoadStatusJudgeRatio(loadStatusJudgeRatio float64) Option

WithLoadStatusJudgeRatio 用来设定massagePlan的高负荷判别比例

func WithStepIntensity added in v0.1.2

func WithStepIntensity(stepIntensity uint) Option

WithStepIntensity 用来设定massagePlan的步进按摩力度

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL