Nacos指南-服务发现:CMDB功能解析

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

上文分析创建服务时,我们发现有个访问策略的参数,下面我们就一起探索一下访问策略怎么玩的

名称类型是否必选描述
selectorJSON格式字符串访问策略

在Nacos控制台上对应的配置名称为服务路由类型。除了默认值之外还可以选择标签类型,通过上文分析selector的格式为:

{"type": "label","expression": "CONSUMER.label.myLabel=PROVIDER.label.myLabel"}

若选择标签模式,表达式可以使用如下格式填写(必须以"CONSUMER.label."开始):
例:

CONSUMER.label.region=PROVIDER.label.region

此处我使用 region 作为标签。

CMDB_DATA_TABLE

ipregion
10.10.10.10shanghai
11.11.11.11shanghai
20.20.20.20beijing
21.21.21.21beijing

可以看出来
ip为 10.10.10.10,11.11.11.11 的归属地是上海
ip为 20.20.20.20,21.21.21.21 的归属地是北京

如果我们此时在上海,同城网络请求的耗时假设10ms,若访问北京服务器网络耗时假设30ms。若是我们在微服务调用的时候,同城网络只调用同城服务器是否就大大的提高了网络请求的效率?

先直接上结果:

先注册4个实例

curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?port=8848&healthy=true&ip=10.10.10.10&weight=1.0&serviceName=spring-cloud-demo&encoding=GBK'

curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?port=8848&healthy=true&ip=11.11.11.11&weight=1.0&serviceName=spring-cloud-demo&encoding=GBK'

curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?port=8848&healthy=true&ip=20.20.20.20&weight=1.0&serviceName=spring-cloud-demo&encoding=GBK'

curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?port=8848&healthy=true&ip=21.21.21.21&weight=1.0&serviceName=spring-cloud-demo&encoding=GBK'

此时服务名为spring-cloud-demo的4个实例已经全部注册成功

此时请求实例列表

curl -X GET '127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=spring-cloud-demo'

返回的数据为:

{
    "hosts": [
        {
            "ip": "21.21.21.21",
            "port": 8848,
            "valid": true,
            "healthy": true,
            "marked": false,
            "instanceId": "21.21.21.21#8848#DEFAULT#DEFAULT_GROUP@@spring-cloud-demo",
            "metadata": {},
            "enabled": true,
            "weight": 1.0,
            "clusterName": "DEFAULT",
            "serviceName": "spring-cloud-demo",
            "ephemeral": true
        },
        {
            "ip": "20.20.20.20",
            "port": 8848,
            "valid": true,
            "healthy": true,
            "marked": false,
            "instanceId": "20.20.20.20#8848#DEFAULT#DEFAULT_GROUP@@spring-cloud-demo",
            "metadata": {},
            "enabled": true,
            "weight": 1.0,
            "clusterName": "DEFAULT",
            "serviceName": "spring-cloud-demo",
            "ephemeral": true
        },
        {
            "ip": "10.10.10.10",
            "port": 8848,
            "valid": true,
            "healthy": true,
            "marked": false,
            "instanceId": "10.10.10.10#8848#DEFAULT#DEFAULT_GROUP@@spring-cloud-demo",
            "metadata": {},
            "enabled": true,
            "weight": 1.0,
            "clusterName": "DEFAULT",
            "serviceName": "spring-cloud-demo",
            "ephemeral": true
        },
        {
            "ip": "11.11.11.11",
            "port": 8848,
            "valid": true,
            "healthy": true,
            "marked": false,
            "instanceId": "11.11.11.11#8848#DEFAULT#DEFAULT_GROUP@@spring-cloud-demo",
            "metadata": {},
            "enabled": true,
            "weight": 1.0,
            "clusterName": "DEFAULT",
            "serviceName": "spring-cloud-demo",
            "ephemeral": true
        }
    ],
    "dom": "spring-cloud-demo",
    "name": "DEFAULT_GROUP@@spring-cloud-demo",
    "cacheMillis": 3000,
    "lastRefTime": 1619072167699,
    "checksum": "c1230e0a77527f4093389636e4f85ccf",
    "useSpecifiedURL": false,
    "clusters": "",
    "env": "",
    "metadata": {}
}

我们知道,我们的客户端实例在获取所属服务列表的时候会将自身ip传入clientIP请求参数中(此处详见NamingProxy.queryList)

public String queryList(String serviceName, String clusters, int udpPort, boolean healthyOnly) throws NacosException {
        Map<String, String> params = new HashMap(8);
        params.put("namespaceId", this.namespaceId);
        params.put("serviceName", serviceName);
        params.put("clusters", clusters);
        params.put("udpPort", String.valueOf(udpPort));
		//传入当前实例的ip地址
        params.put("clientIP", NetUtils.localIP());
        params.put("healthyOnly", String.valueOf(healthyOnly));
        return this.reqApi(UtilAndComs.nacosUrlBase + "/instance/list", params, "GET");
    }

下面我们模拟实例端10.10.10.10请求服务列表

curl -X GET '127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=spring-cloud-demo&clientIP=10.10.10.10'

返回的数据为:

{
    "hosts": [
        {
            "ip": "10.10.10.10",
            "port": 8848,
            "valid": true,
            "healthy": true,
            "marked": false,
            "instanceId": "10.10.10.10#8848#DEFAULT#DEFAULT_GROUP@@spring-cloud-demo",
            "metadata": {},
            "enabled": true,
            "weight": 1.0,
            "clusterName": "DEFAULT",
            "serviceName": "spring-cloud-demo",
            "ephemeral": true
        },
        {
            "ip": "11.11.11.11",
            "port": 8848,
            "valid": true,
            "healthy": true,
            "marked": false,
            "instanceId": "11.11.11.11#8848#DEFAULT#DEFAULT_GROUP@@spring-cloud-demo",
            "metadata": {},
            "enabled": true,
            "weight": 1.0,
            "clusterName": "DEFAULT",
            "serviceName": "spring-cloud-demo",
            "ephemeral": true
        }
    ],
    "dom": "spring-cloud-demo",
    "name": "DEFAULT_GROUP@@spring-cloud-demo",
    "cacheMillis": 3000,
    "lastRefTime": 1619072800221,
    "checksum": "c1230e0a77527f4093389636e4f85ccf",
    "useSpecifiedURL": false,
    "clusters": "",
    "env": "",
    "metadata": {}
}

以上已经实现了服务路由标签过滤。若未匹配到标签,则默认返回全部提供方。

看一下实现

首先实现com.alibaba.nacos.api.cmdb.spi.CmdbService接口,将自己的cmdb数据转化成nacos的数据格式。

public class MyCmdbServiceImpl implements CmdbService {

    public static final List<Map<String,String>> CMDB_DATA =new ArrayList<>();

    {
        /* CMDB_DATA_TABLE:模拟cmdb数据库数据 * ip region * 10.10.10.10 shanghai * 11.11.11.11 shanghai * 20.20.20.20 beijing * 21.21.21.21 beijing */
        Map<String,String> machine10=new HashMap<>();
        machine10.put("ip","10.10.10.10");
        machine10.put("region","shanghai");
        CMDB_DATA.add(machine10);

        Map<String,String> machine11=new HashMap<>();
        machine11.put("ip","11.11.11.11");
        machine11.put("region","shanghai");
        CMDB_DATA.add(machine11);

        Map<String,String> machine20=new HashMap<>();
        machine20.put("ip","20.20.20.20");
        machine20.put("region","beijing");
        CMDB_DATA.add(machine20);

        Map<String,String> machine21=new HashMap<>();
        machine21.put("ip","21.21.21.21");
        machine21.put("region","beijing");
        CMDB_DATA.add(machine21);

    }

    @Override
    public Set<String> getLabelNames() {
       return parseKeySet();
    }

    private Set<String> parseKeySet(){
        Set<String> labelNames=new HashSet<>();
        CMDB_DATA.forEach(d->{
            labelNames.addAll(d.keySet());
        });
        return labelNames;
    }

    @Override
    public Set<String> getEntityTypes() {
        return parseKeySet();
    }

    @Override
    public Label getLabel(String labelName) {
        Label label=new Label();
        label.setName(labelName);
        label.setValues(new HashSet<>());
        CMDB_DATA.forEach(d->{
            label.getValues().add(d.get(labelName));
        });
        return label;
    }

    @Override
    public String getLabelValue(String entityName, String entityType, String labelName) {
        return getEntity(entityName,entityType).getLabels().get(labelName);
    }

    @Override
    public Map<String, String> getLabelValues(String entityName, String entityType) {
        return getEntity(entityName,entityType).getLabels();
    }

    @Override
    public Map<String, Map<String, Entity>> getAllEntities() {
        Map<String, Map<String, Entity>> result=new HashMap<>();
        CMDB_DATA.forEach(d->{
            d.keySet().forEach(col->{
                if(!result.containsKey(col)){
                    result.put(col,new HashMap<>());
                }
                Entity entity=new Entity();
                entity.setName(d.get(col));
                entity.setType(col);
                entity.setLabels(d);
                result.get(col).put(d.get(col),entity);
            });
        });
        return result;
    }

    @Override
    public List<EntityEvent> getEntityEvents(long timestamp) {
        //此处是cmdb数据变更事件的实现,由于是模拟,所有没有实现。
        return null;
    }

    @Override
    public Entity getEntity(String entityName, String entityType) {
        Map<String, Map<String, Entity>> allEntities = getAllEntities();
        return allEntities.get(entityType).get(entityName);
    }
}

开启Cmdb加载参数

nacos.cmdb.loadDataAtStart=true

将我们自己的实现引入Nacos,通过SPI机制加载。

在 resources/META-INF/services 目录下创建名为 com.alibaba.nacos.api.cmdb.spi.CmdbService 的文件,文件内容为实现类的全路径:com.alibaba.nacos.cmdb.spi.MyCmdbServiceImpl (此处是我本次实现的类路径,自己实现需要根据实际情况)。

上一篇:Nacos创建服务
下一篇:Nacos删除服务

相关文章