Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Discussion] The way of namespace handling, specifically for id public and ``(empty). #9846

Open
KomachiSion opened this issue Jan 13, 2023 · 22 comments
Labels
kind/discussion Category issues related to discussion Nacos3.0 Nacos 3.0 Architecture Evolution

Comments

@KomachiSion
Copy link
Collaborator

Is your feature request related to a problem? Please describe.
For the past version of Nacos, The namespace Id is the unique identity for namespace, some users' use namespace show name as id to config to application and cause problems.

And for other users, they are confused by the default namespace public(id is ''). The confusion comes from a bug from old version.
The naming module use public as namespace id and will handle '' as public to use, but in config module not. In one word, the way of namespace id handling is not same.

What's more, The auth plugin is depend namespace Id from 1.2.0 version, The different way of handling also cause the privilege has some problem for default namespace. And the datasource plugin also has some problem for adapt default namespace ''.

Relative Issue: #3525 , #9773 , #8774 , #9783 and so on.

Describe the solution you'd like
I suggess that add two Filter for http and grpc before handle request to unique handle the namespace id public and `` in server.
Make the input id=public to `id=`, or revert(id= --> id=public).
For `id=public` namespace create request, nacos server should stop it, and hint to use other namespace id.

And provide a fix way for those users which has use id=public.

For auth plugin, the auth check and resource extract do after namespace filter, the auth plugin can just compile id and not need to handle.

For datasource plugin, also need to discuss a way to adapt more datasource.

Describe alternatives you've considered
When we design the plan, I think we should consider the old client compatibility and server upgrade compatibility.

Additional context

Welcome all community join the discusion.

@KomachiSion KomachiSion added the kind/discussion Category issues related to discussion label Jan 13, 2023
@xzxiaoshan
Copy link
Contributor

我们公司因为空字符串也出现了数据源问题,团队在这个问题上进行了小范围讨论,最终大家一致认为统一使用 “public” 字符串,比空字符,相对更有意义。
官方未轻易做修改,是考虑到相关影响。如果抛开包袱我们来判断是有值和为空哪个在设计上更为合理,相信心里就会有答案了。
期望官方能早日统一,建议将空值统一处理为默认值 “public”,并出一个升级SQL脚本即可。

@CherishCai
Copy link
Contributor

CherishCai commented Jan 13, 2023

赞同在某个大版本里统一 "public" ,去除歧义;多数人应该去自定义命名空间,则不受大影响

@redscarfz
Copy link

我在适配Oracle数据源插件时,也注意到这个问题。个人感觉配置管理和服务管理默认值不统一是漏洞。命名空间调整为public合理,能解决因”“引起的一系列方言问题。支持更换,等待新版本。

@wilsonwu
Copy link
Contributor

我的问题也是类似的,如果能将默认namespace的id固定为public,那就完美解决相关的问题了。

@karsonto
Copy link
Contributor

我觉得默认就是public 不应该是空字符串 ,如果传入空字符串统一转为public

@Archilobe
Copy link

我认为public比""在设计上更为合理,更有意义,官方若是能将namespace的值固定为public,那么那么就能解决掉很多问题;

@KomachiSion
Copy link
Collaborator Author

我看都在说固定成public,但是考虑到原来的数据都是‘’来存储的,改为public固定需要有成熟的平滑升级方案,需要帮助社区设计一下。

@xzxiaoshan
Copy link
Contributor

我看都在说固定成public,但是考虑到原来的数据都是‘’来存储的,改为public固定需要有成熟的平滑升级方案,需要帮助社区设计一下。

我最近在关注这块,所以就多发表一下个人拙见:
1、关于服务那块不受影响,本来用的就是public。
2、在配置管理这块,因为配置管理全部都是基于数据库表数据的,大概数了下有7张涉及 tenant_id 的表,执行 7 条 update 语句即可,仅此而已( update tableName set tenant = 'public' where tenant_id = '' or tenant_id is null,都是比较简单的单字段修改SQL )。
3、至于 update 语句是自动触发(自动不合适),还是手工触发(推荐启动服务时,服务随便检测一张表,然后控制台给出明显提示,要求刷SQL即可 )。

甚至SQL都可以直接打印到控制台,复制直接用,也就几条SQL。

@wilsonwu
Copy link
Contributor

我看都在说固定成public,但是考虑到原来的数据都是‘’来存储的,改为public固定需要有成熟的平滑升级方案,需要帮助社区设计一下。

我最近在关注这块,所以就多发表一下个人拙见: 1、关于服务那块不受影响,本来用的就是public。 2、在配置管理这块,因为配置管理全部都是基于数据库表数据的,大概数了下有7张涉及 tenant_id 的表,执行 7 条 update 语句即可,仅此而已( update tableName set tenant = 'public' where tenant_id = '' or tenant_id is null,都是比较简单的单字段修改SQL )。 3、至于 update 语句是自动触发(自动不合适),还是手工触发(推荐启动服务时,服务随便检测一张表,然后控制台给出明显提示,要求刷SQL即可 )。

甚至SQL都可以直接打印到控制台,复制直接用,也就几条SQL。

然后把代码里面public namespace id相关的地方都改成public就完事了。

@hujun-w-2
Copy link
Collaborator

1.遇到的数据源的问题能在查询的时候兼容一下是最稳妥的
2.如果确定统一成public,修改的方案同时需要提供完善的测试方案,最好是可以做到对之前的配置方式做兼容,不然代码也得跟着升级也很头疼

@KomachiSion
Copy link
Collaborator Author

我看都在说固定成public,但是考虑到原来的数据都是‘’来存储的,改为public固定需要有成熟的平滑升级方案,需要帮助社区设计一下。

我最近在关注这块,所以就多发表一下个人拙见: 1、关于服务那块不受影响,本来用的就是public。 2、在配置管理这块,因为配置管理全部都是基于数据库表数据的,大概数了下有7张涉及 tenant_id 的表,执行 7 条 update 语句即可,仅此而已( update tableName set tenant = 'public' where tenant_id = '' or tenant_id is null,都是比较简单的单字段修改SQL )。 3、至于 update 语句是自动触发(自动不合适),还是手工触发(推荐启动服务时,服务随便检测一张表,然后控制台给出明显提示,要求刷SQL即可 )。

甚至SQL都可以直接打印到控制台,复制直接用,也就几条SQL。

  1. 升级过程是逐台轮训重启,你这种方式适合停服,如果是平滑升级的过程,一旦修改了数据库数据,整个旧版本就查不到数据了。同时直接改数据库并不能触发server的更新数据,需要手动再让server触发一次dump。因此这种方式不支持平滑升级。

@xzxiaoshan
Copy link
Contributor

xzxiaoshan commented Jan 13, 2023

我看都在说固定成public,但是考虑到原来的数据都是‘’来存储的,改为public固定需要有成熟的平滑升级方案,需要帮助社区设计一下。

我最近在关注这块,所以就多发表一下个人拙见: 1、关于服务那块不受影响,本来用的就是public。 2、在配置管理这块,因为配置管理全部都是基于数据库表数据的,大概数了下有7张涉及 tenant_id 的表,执行 7 条 update 语句即可,仅此而已( update tableName set tenant = 'public' where tenant_id = '' or tenant_id is null,都是比较简单的单字段修改SQL )。 3、至于 update 语句是自动触发(自动不合适),还是手工触发(推荐启动服务时,服务随便检测一张表,然后控制台给出明显提示,要求刷SQL即可 )。
甚至SQL都可以直接打印到控制台,复制直接用,也就几条SQL。

  1. 升级过程是逐台轮训重启,你这种方式适合停服,如果是平滑升级的过程,一旦修改了数据库数据,整个旧版本就查不到数据了。同时直接改数据库并不能触发server的更新数据,需要手动再让server触发一次dump。因此这种方式不支持平滑升级。

对数据库字段不做强制变更(只要不改数据库旧值,就不会对正在运行中的nacos版本产生影响)

  1. 新版本的代码中伪代码如下所示就可以兼容了,对平滑升级也不会有影响,即通过代码来兼容数据库并不要求数据库强制升级
// 新代码处理后,tenantId 只会是 public 或其他值
if("public".equals(tenantId)){
   String sql = "xxxxx where (tenant_id = '' or tenant_id = :tenantId) and xxx = :xxx
}else{
   String sql = "xxxxx where tenant_id = :tenantId and xxx = :xxx
}

2.新版本启动的时候同时对数据库做一个简单判断(可选)

判断如果数据库中如果存在 tenant_id = '' 的情况下,控制台日志给予一个 WARN 提示:提示内容大概就是如果 nacos-client 已经全部使用当前对应版本,且 nacos 服务端也已经全部部署启动到当前版本。则建议将数据库的空字段刷脚本升级为 public。

这种类似的提示,不影响程序正常兼容运行,只是为了长期考虑可以给用户一个提醒。

@KomachiSion
Copy link
Collaborator Author

针对id=public的用户,感觉损害会比较大,因为原来‘’和id=public是两个空间, 这样修改后是一个空间,数据会串,如果对原来id=public对数据修复成其他空间, 不仅需要停服还需要客户端一起修改。 可能需要看下有多少用户这么使用了。

@redscarfz
Copy link

id=public,只会有两种可能,一个是修改默认值,另一种是手动修改新增的命名空间为public。前者无影响,后者的设置,自身的配置管理和服务管理就不对应,因为在服务管理中public涵盖了默认public与修改public两个不同的命名空间,而配置管理中只有默认‘’。后者处理本身就有问题,因此大概率没有用户会这样操作。

@MajorHe1
Copy link
Collaborator

客户端和服务端的文件缓存目录名称也需要跟着更新吗。目前客户端文件缓存public命名空间对应的后缀是空

@xzxiaoshan
Copy link
Contributor

xzxiaoshan commented Jan 16, 2023

针对id=public的用户,感觉损害会比较大,因为原来‘’和id=public是两个空间, 这样修改后是一个空间,数据会串,如果对原来id=public对数据修复成其他空间, 不仅需要停服还需要客户端一起修改。 可能需要看下有多少用户这么使用了。

作为社区,首先无法避免真的有人创建了一个名称为 'public' 的命名空间,即便是没有关闭创建 public 入口是程序不够完善的一点。

再者就是,刚好这么使用的这类用户,预估一定是极少数用户。常规来说,相对富有经验的开发者都不会这么做。

最后就是,在我们无法避免存在这类用户的前提下,作为社区考虑到这类用户的升级问题也是应该的。只是针对这类极少数用户社区能提供给他们一个不停服升级方案即可。任何系统的升级不做任何工作都是不太可能的,升级这种中间件服务本不是高频行为,我们只要能保证让他可以不停服又能完成升级即可。


比如,可行性方案之一:

一、启动新版 nacos 服务时,检测数据库中是否同时存在空值和public值,如果同时存在,那么就是这类用户,为了不产生系统影响,nacos 给出错误提示告知原因终止服务启动(自动检测这个是可选的,程序是否在启动时做这种事最终取决于社区决定)。

二、这类极少数用户的不停服升级操作包括(如下操作全部完成满足了不停服要求):

  1. 创建一个新的命名空间,所有配置保持和 public 一致,例如叫 common,生产正在运行的老版本nacos上进行。
  2. 修改客户端配置,将原来使用的 public 修改为 common,客户端是可以完成滚动升级的。滚动升级过程中就算部分实例读取 common 同时部分实例读取 public,因为配置一致,则不存在问题。
  3. 所有服务都滚动升级完成后,此时所有服务均已经使用 common,已经没有服务使用 public,则可以删除数据库中所有 public 的内容(或者使用SQL批量将 public 修改为 public-back)。
  4. 至此,已经解决 public 被占用的问题,新版本的 nacos 服务即可正常启动。

以上内容通过文字陈述看起来挺多字实际上很容易操作,其实是一个可以落地的方案之一。升级之前做好准备工作,升级过程中很容易的(不允许停机的大规模系统,滚动升级和部署一般也配备对应的平台,通过平台方式部署的大规模应用,修改启动参数就更简单了)。

以上能解决不停机升级问题,这类用户一定是很少数用户,相对有经验的开发者都不会轻易使用 nacos 满界面都能看到的 public 关键字来当命名空间,即便是不绝对存在这类用户也一定是很少的。

@xzxiaoshan
Copy link
Contributor

针对id=public的用户,感觉损害会比较大,因为原来‘’和id=public是两个空间, 这样修改后是一个空间,数据会串,如果对原来id=public对数据修复成其他空间, 不仅需要停服还需要客户端一起修改。 可能需要看下有多少用户这么使用了。

我又想了一下,这种用户是不存在的,哈哈

如果用户创建了 ID 为 public 的命名空间(客户端 config 配置使用的是 ID),那么开发者要在客户端的配置文件config 配置中设置啥?岂不是还是要用 public。写了 public,nacos 服务端本来默认就是当做 "" 值处理的,因为naocs 默认客户端取空值命名空间就是要求客户端写 public的,这本身已经是 nacos 的保留字了。

故,假设的这类用户不存在。即便是用户在nacos UI上创建了ID=public 的命名空间,也是无法正常使用到的。

@KomachiSion
Copy link
Collaborator Author

针对id=public的用户,感觉损害会比较大,因为原来‘’和id=public是两个空间, 这样修改后是一个空间,数据会串,如果对原来id=public对数据修复成其他空间, 不仅需要停服还需要客户端一起修改。 可能需要看下有多少用户这么使用了。

我又想了一下,这种用户是不存在的,哈哈

如果用户创建了 ID 为 public 的命名空间(客户端 config 配置使用的是 ID),那么开发者要在客户端的配置文件config 配置中设置啥?岂不是还是要用 public。写了 public,nacos 服务端本来默认就是当做 "" 值处理的,因为naocs 默认客户端取空值命名空间就是要求客户端写 public的,这本身已经是 nacos 的保留字了。

故,假设的这类用户不存在。即便是用户在nacos UI上创建了ID=public 的命名空间,也是无法正常使用到的。

注册中心和配置中心这里不一致, 注册中心会把public当作‘’, 但是配置中心会直接透传。配置会被当作nsid:public , 如果真的全都执行了public当作‘’,那就不需要这个讨论issue了。

@xzxiaoshan
Copy link
Contributor

服务注册发现这块,好像不用"",用的是public,难道代码看错了?

@redscarfz
Copy link

redscarfz commented Jan 30, 2023

楼上说反了,配置中心默认“,注册中心默认public。例子可见NamespaceOperationService.java中getNamespace()

@KomachiSion
Copy link
Collaborator Author

意思表达的不准确啊, 主要意思是用户在传入nsid=public的时候, 注册中心会把‘’和‘public’当作同一个命名空间处理,但是配置中心是‘’和‘public’不同, 会透传public进行处理, 导致数据的nsid为public,如果不传入ns的话配置中心默认用的‘’,即会当作两个不同的命名空间处理。

@MajorHe1
Copy link
Collaborator

明确两个前提:
1、对于使用配置中心同时存在 “” 和 “public” 命名空间的使用方,给出报错提示,这种情况下需要使用方自己构建全新的集群然后做迁移。
2、最终目的是让配置中心的行为跟注册中心一致,即把 “” 都当做 “public”来使用,数据库里面不应该存在 “” 的字段。

这边有个建议,就是要在不禁写的情况下对客户端无感,服务端就不能一次性更新到位,要安排两个版本来发布。
先发布第一个版本,服务端对于所有的查询请求,兼容 “” 和 “public”的查询(兼容SQL查询好办,兼容对本地文件缓存的查询不好办)。此时,不对写操作做任何处理。
等上面的版本全量发布完成后,服务端再对于所有的配置写入请求,将“”都翻译成“public”写入。
等上面两个版本都全量发布完成后,再执行SQL命令,将数据库里面的存量“”字段都替换成“public”。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/discussion Category issues related to discussion Nacos3.0 Nacos 3.0 Architecture Evolution
Projects
None yet
Development

No branches or pull requests

9 participants