安吉网站建设,全球最好的设计网站,怎么通过网络宣传自己的产品,优化资源配置一、隔离
对系统或资源进行分割#xff0c;实现当系统发生故障时能限定传播范围和影响范围。进一步的#xff0c;通过隔离能够降低系统之间得耦合度#xff0c;使得系统更容易维护和扩展。某些业务场景下合理使用隔离技巧也能提高整个业务的性能。我理解隔离本质就是一种解…一、隔离
对系统或资源进行分割实现当系统发生故障时能限定传播范围和影响范围。进一步的通过隔离能够降低系统之间得耦合度使得系统更容易维护和扩展。某些业务场景下合理使用隔离技巧也能提高整个业务的性能。我理解隔离本质就是一种解耦手段。
1.1 动静隔离
动静隔离本质上是根据资源的变化频率对它们进行划分和隔离。本质上是加速/缓存变化频率小的数据将它们与其它资源进行隔离避免其它资源频繁变化影响到它们从而提高性能
场景一 将对象存储和业务服务隔离
对象存储费用低、存储量大并且放入对象存储空间的资源变化频率也低。我们将对象存储作为一个单独的模块让所有业务服务共享这样业务服务就无需考虑存储问题比如空间不足、静态资源和业务数据在带宽上无法隔离造成业务卡顿等问题。 本质上是对静态资源(静态文件)和动态资源(动态业务数据)进行了隔离将它们进行隔离提高了业务服务的带宽性能、每个业务服务也不需要考虑自身的存储空间以及数据之间的一致性问题将业务服务变为一种无状态的服务更方便扩缩容。
场景二数据表字段的分离
针对一个业务设计了一张数据表该表包括了一个对象的基本信息和统计信息。基本信息的变动频率往往很低(用户名、性别、状态、手机号、密码)而统计信息变化频率往往很高(点赞数、关注数、粉丝数、资产数)等等 我们可以将基本信息和统计信息进行分离能够得到以下好处
修改统计信息只会使得统计信息的缓存失效不会使得基本信息的缓存失效使得B树叶子节点能够存放更多记录从而降低树的高度缓解单表数据量大导致读写操作慢的问题
场景三 各种数据库的读写分离也借鉴了该思想
1.2 快慢隔离
把服务的吞吐想象成一个蓄水池当突然洪流进来的时候池子需要一定时间才能将其排放完而这时候其它的小流量在池子里面待的时间取决于这个蓄水池的排放能力为了提高排放能力(接口响应速度)我们可以对服务进行快慢隔离。
当我们请求一个接口时它可能涉及到很多业务处理有些业务轻处理快、有些重处理慢。在不影响用户体验的前提下我们可以将这些重的业务特别是一些大的并发业务从上游解耦到消息队列的消费者端处理提高整个api的响应速度保证业务最终完成即可。
1.3 热点隔离
统计某个热点数据重访问频次最高TopKS数据进行缓存或者将remoteCache升级为localCache提升效率
1.4 物理隔离
线程池隔离同一主机下使用cgroup隔离服务的cpu、内存进程隔离、集群隔离等
二、超时控制
超时控制通过限制请求在系统里停留的最长时间避免请求长时间在系统中占用资源降低系统的性能。(当用户发起一次请求过了2~3秒都没反应用户往往会重试上次的请求也就应该丢弃了如果不设置超时时间它还会继续在系统中执行业务消耗系统的资源) 超时控制应该具备传递功能当上游服务已经返回超时错误时下游服务不要再继续执行。Quota传递到下游服务中应该继承超时策略 go-grpc框架中会依赖gRPC Metadata Exchange基于HTTP2的Headers传递grpc-timeout字段传递到下游构建待timeout的context。 简单说如果你调用grpc方法中传入的context携带timeout那么grpc则会在http2的header frame中设置字段grpc-timeout为context.DeadLine()而grpc server在接收请求时若发现grpc-timeout的存在则会构造一个带timeout的context传给handler从而实现grpc的超时传递
go-zero的超时控制实现
go-zero 中我们可以再BFF层配置Timeout字段设置接口的超时时间它会帮我们完成超时传递
go-zero/core/fx/timeout.go:超时控制
package fximport (contextfmtruntime/debugstringstime
)var (// ErrCanceled is the error returned when the context is canceled.ErrCanceled context.Canceled// ErrTimeout is the error returned when the contexts deadline passes.ErrTimeout context.DeadlineExceeded
)// DoOption defines the method to customize a DoWithTimeout call.
type DoOption func() context.Context// DoWithTimeout runs fn with timeout control.
func DoWithTimeout(fn func() error, timeout time.Duration, opts ...DoOption) error {parentCtx : context.Background()for _, opt : range opts {parentCtx opt()}ctx, cancel : context.WithTimeout(parentCtx, timeout)defer cancel()// create channel with buffer size 1 to avoid goroutine leakdone : make(chan error, 1)panicChan : make(chan any, 1)go func() {defer func() {if p : recover(); p ! nil {// attach call stack to avoid missing in different goroutinepanicChan - fmt.Sprintf(%v\n\n%s, p, strings.TrimSpace(string(debug.Stack())))}}()done - fn()}()select {case p : -panicChan:panic(p)case err : -done:return errcase -ctx.Done():return ctx.Err()}
}// WithContext customizes a DoWithTimeout call with given ctx.
func WithContext(ctx context.Context) DoOption {return func() context.Context {return ctx}
}参考
小米技术团队https://xiaomi-info.github.io/2019/12/30/grpc-deadline/
三、过载保护、限流
本质上是根据系统的情况限制请求接收的数量将能力以外的请求快速响应失败但是二者有一些区别 过载保护在未达到阈值前尽可能的接收请求当cpu达到阈值(一般为90%)时得到系统的最大负载开始丢弃一些请求。但是由于这个时候已经接近满负载了并且丢弃请求本身也具有一丢丢的性能损耗此时若请求仍大量进来还是会将服务打崩。 限流限流算法从始至终都在限制请求接收的速率弥补过载保护在极端条件的风险使得服务更加稳健
过载保护
通过记录当前机器的各项性能指标比如cpu、内存、响应延迟等信息判断是否过载如果过载则开启过载保护以过载的系统负载作为阈值判断当前请求数量是否超过阈值。 负载统计 const (// 250ms and 0.95 as beta will count the average cpu load for past 5 secondscpuRefreshInterval time.Millisecond * 250allRefreshInterval time.Minute// moving average beta hyperparameterbeta 0.95
)func init() {go func() {cpuTicker : time.NewTicker(cpuRefreshInterval)defer cpuTicker.Stop()allTicker : time.NewTicker(allRefreshInterval)defer allTicker.Stop()for {select {case -cpuTicker.C:threading.RunSafe(func() {curUsage : internal.RefreshCpu()prevUsage : atomic.LoadInt64(cpuUsage)// cpu cpuᵗ⁻¹ * beta cpuᵗ * (1 - beta)//指数衰变算法 usage : int64(float64(prevUsage)*beta float64(curUsage)*(1-beta))atomic.StoreInt64(cpuUsage, usage)})case -allTicker.C:printUsage()}}}()
}过载保护/core/load/adaptiveshedder.go
func (as *adaptiveShedder) shouldDrop() bool {if as.systemOverloaded() || as.stillHot() {if as.highThru() {flying : atomic.LoadInt64(as.flying)as.avgFlyingLock.Lock()avgFlying : as.avgFlyingas.avgFlyingLock.Unlock()msg : fmt.Sprintf(dropreq, cpu: %d, maxPass: %d, minRt: %.2f, hot: %t, flying: %d, avgFlying: %.2f,stat.CpuUsage(), as.maxPass(), as.minRt(), as.stillHot(), flying, avgFlying)logx.Error(msg)stat.Report(msg)return true}}return false
}分布式限流
参考go-zero的分布式限流实现https://pandaychen.github.io/2020/09/21/A-DISTRIBUTE-GOREDIS-RATELIMITER-ANALYSIS/
四、熔断降级
五、重试、负载均衡