全部产品

故障排查之 DRM

KB: 184015

 · 

更新时间:2021-02-09 11:34

本文汇总梳理了动态配置(DRM)在使用过程中遇到的常见问题,主要内容如下:

如何利用 DRM 动态设置 loglevel?

基于 SOFABoot 开发的程序,对于日志,有如下默认配置:

  • application.properties:

# log level for current application with groupid com.hula.sofa
 logging.level.com.hula.sofa=INFO
  • logback-spring.xml:

<springProperty scope="context" name="logging.level" source="logging.level.com.hula.sofa"/>

我们可以使用 DRM 来动态更新 loglevel,步骤如下:

  1. 定义对应的动态配置类,示例如下:

            import com.alipay.drm.client.DRMClient;
            import com.alipay.drm.client.api.annotation.DAttribute;
            import com.alipay.drm.client.api.annotation.DObject;
            import com.alipay.drm.client.api.model.DependencyLevel;
            import org.springframework.beans.factory.annotation.Autowired;
            import org.springframework.beans.factory.annotation.Value;
            import org.springframework.boot.logging.LogLevel;
            import org.springframework.boot.logging.LoggingSystem;
            @DObject(region="hula", appName ="dynamic-log-level", id ="com.hula.sofa.config.DynamicConfig")
            public class DynamicConfig{
                // 取application.properties配置的值作为默认值
                @DAttribute
                @Value("${logging.level.com.hula.sofa}")
                private String loglevel;
                @Autowired
                LoggingSystem loggingSystem;
                public void init(){
                    DRMClient.getInstance().register(this);
                }
                public String getLoglevel(){
                     return loglevel;
                }
                public void setLoglevel(String loglevel){
                    this.loglevel = loglevel;
                    LogLevel level =LogLevel.valueOf(loglevel.toUpperCase());
                    // 使用springboot的LoggingSystem设置目标logger的loglevel
                    loggingSystem.setLogLevel("com.hula.sofa", level);
                }
            }
  2. 在 SOFA 微服务平台上配置对应的动态配置,即可实现动态更新 loglevel。DRM推送.png

    说明

    Note:在客户端值处,推送成功情况下不会显示新的值。

重启服务后,为何属性获取的是动态配置推送过的值,而不是默认值?

动态配置默认用法是:当服务端推送配置后,启动时,客户端会默认同步加载服务端配置值。如果不想使用该默认同步加载,需如此设置:@DAttribute(dependency = DependencyLevel.NONE

更多依赖级别,说明如下:

依赖等级

依赖描述

NONE

无依赖,启动期不加载服务端值,启动此级别后,客户端仅会接收服务端在运行期间产生的配置推送。

ASYNC

异步更新,启动期异步加载服务端值,不关注加载结果。

WEAK

弱依赖,启动期同步加载服务端推送值。 - 当服务端不可用时不影响应用正常启动。 - 服务端可用后,客户端会依靠心跳检测重新拉取到服务端值。

STRONG

强依赖,启动期同步加载服务端值。 - 如服务端未设置值,则使用代码初始化值。 - 如从服务端获取数据请求异常,或客户端设值异常时,均会抛出异常,应用启动失败。

EAGER

最强依赖,启动期必须拉取到服务端值。如服务端未推送过值则抛异常,应用启动失败。

如何给属性赋初始值?

有下述几种方式:

  • 直接在定义式赋值。例如:private String loglevel = "info"

  • application.properties 中获取,示例如下:

//正确方式 
@DAttribute private String loglevel ="info";//初始值为info
//或者
@Value("${logging.level.com.hula.sofa}")
@DAttributeprivate String loglevel;

注意:请勿在 init 方法里赋值。

这样赋值时,在客户端重启后,会覆盖推送值,并变回默认值,将造成后续推送无法生效。示例如下:

//错误方式
public void init(){
         DRMClient.getInstance().register(this);
         setLoglevel("info");
}