共计 2202 个字符,预计需要花费 6 分钟才能阅读完成。
在申请处理过程中,应用程序会承受和解决申请,而后返回响应后果。在该过程中,还存在一些通用的性能,例如:鉴权、监控、链路追踪。泛滥 RPC 框架会提供称之为 Middleware 或者 Interceptor 等概念,以可插拔的形式来反对上述谈到的泛滥性能。以 gRPC 为例,工作原理如图:
其服务端的接口如下所示:
func UnaryServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error)
func StreamServerInterceptor (srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error
能够看到,接口明确定义了输出参数,输入后果。如果咱们要本人实现一个组件,须要反对使用者传入特定的配置,有没有什么方法能够做到呢?
答案是必定的。
Higher-order function
在理解具体的解决方案之前,须要先理解一个概念叫Higher-order function(高阶函数)
高阶函数是指至多反对以下特定之一的函数:
- 将一个或多个函数作为参数(即过程参数),
- 返回函数作为其后果
第二点,正是须要的个性。以限流的 interceptor 为例,反对传入自定义的限流器。此时就须要定义一个以限流器为参数的高阶函数,而后返回的函数是框架须要的 Interceptor,并在 Interceptor 函数内应用传入的限流器判断是否须要限流。依照接口限流的 Interceptor 具体实现为:
type Limiter interface {Limit(key string) bool
}
func UnaryServerInterceptor(limiter Limiter) grpc.UnaryServerInterceptor {return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {if limiter.Limit(info.FullMethod) {return nil, status.Errorf(codes.ResourceExhausted, "%s is rejected by grpc_ratelimit middleware, please retry later.", info.FullMethod)
}
return handler(ctx, req)
}
}
...
目前传入的参数是固定的,能够这么来实现。更进一步,如果应用比较复杂,除了以后曾经确定的参数,能够预期当前会减少更多的参数。也就要求以后设计的接口须要有很好的扩展性。还有方法么?
答案同样是必定的。
Functional Options
没有意外,利用的就是高阶函数的第一点,该编程模式有一个特定的名称:Functional Options。
首先为传入的参数定义构造体
type options struct {
byMethod bool
byUser bool
byClientIP bool
}
其次,再定义一个函数类型:
type Option func(*Options)
再次,定义批改配置的一组函数
func ByMethod(m bool) Option {return func(o *options) {o.byMethod = m}
}
func ByUser(u bool) Option {return func(o *options) {o.byUser = u}
}
func ByClientIP(c bool) Option {return func(o *options) {o.byClientIP = c}
}
最初,批改提供的 Interceptor 为:
func UnaryServerInterceptor(limiter Limiter, opts ...Option) grpc.UnaryServerInterceptor {return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
default := options {
byMethod: true,
byUser: false,
byClientIP: false,
}
for _, opt := range opts {opt(&default)
}
...
return handler(ctx, req)
}
}
如是,你就领有了一个具备扩展性、反对自定义参数的 Interceptor。
最初
做个总结,谈个观点:
- 高阶函数,并不是属于哪一个特定的编程语言。其余语言如 C ++,同样反对相似的个性。
- 作为架构师须要理解实现细节么,答案是须要。否则,在特定环境下,拿什么来撑持设计所谓的扩展性呢。
本文作者 :cyningsun
本文地址 :https://www.cyningsun.com/07-…
版权申明:本博客所有文章除特地申明外,均采纳 CC BY-NC-ND 3.0 CN 许可协定。转载请注明出处!