Nacos源码分析十四、服务端处理获取配置请求

x33g5p2x  于2021-12-20 转载在 其他  
字(3.6k)|赞(0)|评价(0)|浏览(468)

Nacos客户端的学习已经基本告一段落。从本篇开始我们把关注点放在服务端。

我们知道nacos服务端主要功能就是提供配置中心的功能和命名服务。接下来我们还是按这两部分讨论。

首先是配置中心。我们先看一下服务端如何处理客户端发起的获取配置的请求,相应接口是在com.alibaba.nacos.config.server.controller.ConfigController中定义,我们看一下getConfig方法:

@GetMapping
@Secured(action = ActionTypes.READ, parser = ConfigResourceParser.class)
public void getConfig(HttpServletRequest request, HttpServletResponse response,
        @RequestParam("dataId") String dataId, @RequestParam("group") String group,
        @RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY) String tenant,
        @RequestParam(value = "tag", required = false) String tag)
        throws IOException, ServletException, NacosException {
    // check tenant
    ParamUtils.checkTenant(tenant);
    tenant = processTenant(tenant);
    // check params
    ParamUtils.checkParam(dataId, group, "datumId", "content");
    ParamUtils.checkParam(tag);
    
    final String clientIp = RequestUtil.getRemoteIp(request);
    inner.doGetConfig(request, response, dataId, group, tenant, tag, clientIp);
}

先是参数检查,然后获取客户端IP,最后调用ConfigServletInner的doGetConfig方法。

doGetConfig方法比较长,先画一个流程图吧:

  1. 首先获取读取锁,如果没有得到锁则返回失败。lockResult>0时执行读取操作
  2. 然后是判断beta、tag、autoTag来确定是否带对应的参数进行数据获取
  3. 再根据PropertyUtil.isDirectRead()方法确定是通过mysql读取还是本地文件
  4. response写对应的内容,最终返回。

我们看一下PropertyUtil.isDirectRead()判断:

public static boolean isDirectRead() {
    return ApplicationUtils.getStandaloneMode() && isEmbeddedStorage();
}

是否是单机模式,并且开启mysql存储,默认的embeddedStorage值和是否是单机模式值一致:

private static boolean embeddedStorage = ApplicationUtils.getStandaloneMode();

persistService.findConfigInfo4Beta是beta的数据库查询:

@Override
public ConfigInfo4Beta findConfigInfo4Beta(final String dataId, final String group, final String tenant) {
    String tenantTmp = StringUtils.isBlank(tenant) ? StringUtils.EMPTY : tenant;
    final String sql = "SELECT ID,data_id,group_id,tenant_id,app_name,content,beta_ips FROM config_info_beta WHERE data_id=? AND group_id=? AND tenant_id=?";
    
    return databaseOperate.queryOne(sql, new Object[] {dataId, group, tenantTmp}, CONFIG_INFO4BETA_ROW_MAPPER);
    
}

findConfigInfo 不带tag的:

@Override
public ConfigInfo findConfigInfo(final String dataId, final String group, final String tenant) {
    final String tenantTmp = StringUtils.isBlank(tenant) ? StringUtils.EMPTY : tenant;
    final String sql = "SELECT ID,data_id,group_id,tenant_id,app_name,content,md5,type FROM config_info "
            + " WHERE data_id=? AND group_id=? AND tenant_id=?";
    final Object[] args = new Object[] {dataId, group, tenantTmp};
    return databaseOperate.queryOne(sql, args, CONFIG_INFO_ROW_MAPPER);
    
}

findConfigInfo4Tag 带tag的:

@Override
public ConfigInfo4Tag findConfigInfo4Tag(final String dataId, final String group, final String tenant,
        final String tag) {
    String tenantTmp = StringUtils.isBlank(tenant) ? StringUtils.EMPTY : tenant;
    String tagTmp = StringUtils.isBlank(tag) ? StringUtils.EMPTY : tag.trim();
    
    final String sql = "SELECT ID,data_id,group_id,tenant_id,tag_id,app_name,content FROM config_info_tag WHERE data_id=? AND group_id=? AND tenant_id=? AND tag_id=?";
    
    return databaseOperate
            .queryOne(sql, new Object[] {dataId, group, tenantTmp, tagTmp}, CONFIG_INFO4TAG_ROW_MAPPER);
}

然后我们看一下DiskUtil的获取file的方法,以带tag的为例:

public static File targetTagFile(String dataId, String group, String tenant, String tag) {
    File file = null;
    if (StringUtils.isBlank(tenant)) {
        file = new File(ApplicationUtils.getNacosHome(), TAG_DIR);
    } else {
        file = new File(ApplicationUtils.getNacosHome(), TENANT_TAG_DIR);
        file = new File(file, tenant);
    }
    file = new File(file, group);
    file = new File(file, dataId);
    file = new File(file, tag);
    return file;
}

就是分目录往下new File

最后我们看一下response写文件:

fis.getChannel()
        .transferTo(0L, fis.getChannel().size(), Channels.newChannel(response.getOutputStream()));

这个是文件的输入流转response的输出流。 零拷贝传输。

总结

服务端如何处理获取配置的请求基本分析完了。

  1. 读锁的获取
  2. beta、tag、autoTag的判断来确认具体读什么配置
  3. PropertyUtil.isDirectRead()判断是读mysql还是读文件
  4. 使用jdk的零拷贝传输直接将文件输入流转response输出流

相关文章