返回
系统可靠性提升利器 - 无侵入式自动重试
后端
2024-01-21 21:43:56
引言
重试是提高系统可用性的重要手段,我们在业务代码中经常可以看到大量的重试逻辑。然而,这些重试逻辑往往都是手动实现的,不仅繁琐而且容易出错。有没有一种办法可以无侵入地实现重试,让业务代码完全无感知呢?
业务重试
常见的业务代码如下:
func ExampleRPCSend(ctx context.Context, request *request.SendRequest, opts ...gax.CallOption) (*request.SendResponse, error) {
//ctx := context.Background()
c, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
resp, err := c.Send(request, opts...)
if err != nil {
return nil, err
}
return resp, nil
}
对于上面这段代码,我们希望在遇到网络错误或超时错误时进行重试。我们可以手动添加重试逻辑,如下所示:
func ExampleRPCSendWithRetry(ctx context.Context, request *request.SendRequest, opts ...gax.CallOption) (*request.SendResponse, error) {
//ctx := context.Background()
c, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
var err error
var resp *request.SendResponse
for i := 0; i < maxRetries; i++ {
resp, err = c.Send(request, opts...)
if err == nil || !errors.Is(err, context.DeadlineExceeded) && !errors.Is(err, errors.Unavailable) {
break
}
time.Sleep(time.Second)
}
return resp, err
}
这种方式虽然可以实现重试,但非常繁琐,而且容易出错。有没有一种更简单的方法呢?
无侵入式自动重试
现在,让我们介绍一种无侵入式的自动重试机制。这种机制可以自动检测到网络错误或超时错误,并自动进行重试。业务代码完全无感知,不需要任何修改。
这种机制的原理是使用代理模式。我们创建一个代理对象,并把这个代理对象作为业务对象。当业务对象调用某个方法时,代理对象会拦截这个调用,并在调用失败时自动进行重试。
这种机制的优点是:
- 无需修改业务代码,开箱即用
- 非常简单易用,不需要任何配置
- 可以自动检测到网络错误或超时错误
- 可以自动进行重试,直到成功或达到最大重试次数
使用方式
使用这种机制非常简单,只需要在业务对象前加上一层代理对象即可。例如:
type SendClient struct {
// target is the target address of the service.
target string
// opts is the optional gRPC call options.
opts []gax.CallOption
// retryer is the retryer used by the client.
retryer gax.Retryer
}
func NewSendClient(target string, opts ...gax.CallOption) (*SendClient, error) {
return &SendClient{
target: target,
opts: opts,
// Use default retryer.
retryer: DefaultRetryer,
}
}
func (c *SendClient) Send(ctx context.Context, req *request.SendRequest, opts ...gax.CallOption) (*request.SendResponse, error) {
// Add retryer to the call options.
opts = append(opts, c.retryer)
// Delegate the call to the real client.
return c.c.Send(ctx, req, opts...)
}
在上面的代码中,我们创建了一个代理对象SendClient。这个代理对象包含了一个真正的业务对象c。当SendClient调用Send方法时,它会把retryer添加到调用选项中,然后把调用委托给真正的业务对象。这样,业务对象就可以自动进行重试了。
结语
无侵入式的自动重试机制可以帮助您轻松提升系统可靠性。无需修改业务代码,即可实现故障重试,让您的系统更稳定、更可靠。