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

设计实现 Redis API #608

Open
codedededi opened this issue May 26, 2022 · 30 comments
Open

设计实现 Redis API #608

codedededi opened this issue May 26, 2022 · 30 comments
Labels
area/api area/community help wanted Extra attention is needed kind/enhancement New feature or request

Comments

@codedededi
Copy link
Contributor

codedededi commented May 26, 2022

What would you like to be added:
设计实现 Redis API

@seeflood
Copy link
Member

Wait !
@wenxuwan is there anyone working on it?

@seeflood
Copy link
Member

@gdutChenxj Hi 不好意思,我去问了下这个任务被占用了(作为今年开源之夏的参赛课题)
感兴趣的话可以再看看别的任务或者issue哈

@codedededi
Copy link
Contributor Author

@seeflood 现在还有什么任务可以领取?很多都处于领完的状态

@seeflood
Copy link
Member

好问题,我整理下

@seeflood
Copy link
Member

seeflood commented May 26, 2022

@gdutChenxj hi, 我更新了一下
#438 飞船活动的列表里,没打勾的都没人领~
另外有社区新手任务列表: #108 (comment)
以及 CI 优化的待办列表: #532 (comment)

@codedededi codedededi changed the title 用 ceph 实现 File API 组件 设计实现 Redis API May 26, 2022
@codedededi
Copy link
Contributor Author

@seeflood 领取【设计实现 Redis API】任务

@seeflood
Copy link
Member

seeflood commented May 27, 2022

这个是 #530 的子任务

@gdutChenxj hi, 因为这个功能比较重要,需要先做设计(写个设计 proposal),大家讨论后达成一致了再开始编码~
可以先想想怎么设计,如果不太清楚的话我帮着写个初版设计proposal也行

如果方便的话可以来参加我们每周社区会议,这样沟通效率更高些

@codedededi
Copy link
Contributor Author

@seeflood 了解,昨天我也看到 #530 了解了大致背景,proposal会在这个issue下同步
另外,社区会议如何参加呢?

@seeflood
Copy link
Member

seeflood commented May 27, 2022

@gdutChenxj 棒!
有个社区会议的钉钉群,群号:41585216
之前是每周五晚8点,正在投票要不要把时间改成周末

每次的议题记录在 https://github.com/mosn/layotto/discussions
每次会有视频录像 https://mosn.io/layotto/#/zh/community/meeting

@seeflood
Copy link
Member

FYI
社区会议改成了周六晚8点,今晚8点就有

@kevinten10
Copy link
Member

Hi,我之前在capa项目中调研过一些Redis的API,可以作为参考

#530 ,在capa中我使用java接口进行api定义,主要参考了 http://redisdoc.com/index.html 文档和jedis的java api。

在做的过程中我发现完全的Redis原生命令可能有120+个,其中有的比较复杂,并且可能应用场景较少。

#530 中提到的,我遇到的常见的数据结构主要有:

  • string
  • hash
  • key
  • list
  • set
  • sorted set
  • geo

按照"starting simple"的思路,或许可以从这些数据结构的api开始设计。

最后,附上capa中的java redis api地址:https://github.com/capa-cloud/cloud-runtimes-jvm/tree/develop/cloud-runtimes-api/src/main/java/group/rxcloud/cloudruntimes/domain/nativeproto/redis

Best Wishes.

@codedededi
Copy link
Contributor Author

@kevinten10 3Q,有留意到 #530 这个帖子,感觉很有帮助

@wenxuwan
Copy link
Member

wenxuwan commented Jun 1, 2022

可以直接使用redis的多行文本协议多行文本,用户只需要将命令行以字符串的形式传递给Layotto,Layotto通过redis-go函数直接将string转换成redis指令。

@seeflood
Copy link
Member

seeflood commented Jun 1, 2022

@wenxuwan 说的是生产用户已经在用的方案,只需要设计一个 redis command 接口。
比如, 我们把接口设计成:

rpc RedisCommand(RedisRequest) returns (RedisResponse) {}

message RedisRequest {
	string store_name = 1;
	string cmd = 2;
	repeated bytes args = 3;
	map<string,string> metadata = 4;
}

message RedisResponse {
	repeated bytes values = 1;
}

思路类似于 dapr binding API (不过 dapr 的 redis binding 目前啥功能都不支持

pros:

  • 一个接口搞定,省去了自己实现100+接口的工作量
  • 用户只需要学习 redis 命令行工具的用法;不需要在应用中引入 redis 的库

@codedededi
Copy link
Contributor Author

@seeflood 个人理解,感觉直接暴露 redis 协议接口 low level api 对初级用户使用过程不太友好,可能会产生一些不太好的使用实践,另外哦如果设施底层可能是集群代理或者类redis协议的缓存组件,low level api无法限制用户使用不支持的命令

@seeflood
Copy link
Member

seeflood commented Jun 3, 2022

@gdutChenxj 你说的确实是个问题,上面的方案有缺点:

  • 对初级用户不太友好
  • 无法限制用户、限制组件开发者。口子”开太大“,可能导致组件夹带私活、塞一些没有可移植性的”私有指令“进去

方案b: cmd 改成用枚举值呢

rpc RedisCommand(RedisRequest) returns (RedisResponse) {}

message RedisRequest {
	string store_name = 1;
	command cmd = 2;
	repeated bytes args = 3;
	
   enum command{
    set = 0;
    get = 1;
    // ...
  }
}

message RedisResponse {
	repeated bytes values = 1;
}

解释:

  • cmd 改成用枚举值
  • 删掉metadata

pros:

  • 有一定的限制,避免使用私有指令

cons:

  • 工作量稍微大一些,需要定义一百多个枚举值,然后在runtime 层把这些枚举转成redis 字符串。但这属于能接受的范围,工作量比定义一百多个grpc 接口要小多了

@kevinten10
Copy link
Member

Hi,RedisCommand方式看起来很棒~我这里有一些想法,随便聊聊:

1. 用户应该不希望面向 多行文本 编程,而是面向语义清晰的api进行编程。

这样,还是需要定义很多in-process的api吧(比如我上面提到的capa的那一堆接口定义),最终需要映射到 一百多个grpc接口 或者 RedisCommand 上的。

  • 一百多个grpc接口:工作量主要在proto定义上,映射起来会比较方便,或者初期直接让用户调grpc的api也可以。
  • RedisCommand:工作量主要在in-process的api的参数转换上(要转换成 RedisCommand的数据格式),以及runtime里面写switch-case来区分命令上。

工作量感觉差不多

2. 考虑和Redis Mesh的混合形式呢

比如一种 RedisMesh ,未来可能有这种架构:layotto和x-mesh混用的架构,用户希望redis的功能在redis mesh/layotto之间做选择,或许:

  • 用户进程 -> grpc流量 -> Layotto -> Layotto Redis Component -> redis流量 -> redis
  • 用户进程 -> grpc流量 -> Layotto -> Layotto RedisMesh Component -> redis流量 -> Redis Mesh -> redis
  • 用户进程 -> redis流量 -> Redis Mesh -> redis
  • ......

这样的话,我感觉 RedisCommand 会好一点,因为layotto只需要把接收到的grpc参数,转成redis命令发出去就可以了。

@codedededi
Copy link
Contributor Author

@kevinten10 使用 RedisCommand 的实际开发量会少一些,对开发者比较友好,但是考虑到命令的参数在接口上的限制会变弱,使用体验上会稍微差些,我考虑的话虽然定义独立的 grpc 接口编写的代码会稍多,但总归是有限的一次性工作,长期来看更加合理,个人更倾向于 grpc 接口

@codedededi
Copy link
Contributor Author

@kevinten10 另外我在想,是不是能写个简单一个脚本,通过您之前在 capa 定义的 java 接口,初始化一波 grpc 接口定义,应该能减少一些工作量

@kevinten10
Copy link
Member

使用 RedisCommand 的实际开发量会少一些,对开发者比较友好,但是考虑到命令的参数在接口上的限制会变弱,使用体验上会稍微差些,我考虑的话虽然定义独立的 grpc 接口编写的代码会稍多,但总归是有限的一次性工作,长期来看更加合理,个人更倾向于 grpc 接口

看起来是的,一次性的工作

另外我在想,是不是能写个简单一个脚本,通过您之前在 capa 定义的 java 接口,初始化一波 grpc 接口定义,应该能减少一些工作量

哈哈,也可以试试idea的列编辑模式

@seeflood
Copy link
Member

seeflood commented Jun 11, 2022

比如一种 RedisMesh ,未来可能有这种架构:layotto和x-mesh混用的架构,用户希望redis的功能在redis mesh/layotto之间做选择,或许:

@kevinten10 恩恩 后续的演进方向是准备“既支持原生 redis协议,又支持 redis gRPC API”的,见#530

@seeflood
Copy link
Member

seeflood commented Jun 11, 2022

所以现在的争议焦点是:
100 个gRPC API vs RedisCommand vs RedisCommand (传枚举值)
对吧?

问题1. RedisCommand 没啥类型信息,会不会用户体验太差

image
(如上图,repeated bytes args = 3; 没有类型信息)

Q: 会不会因为 api没啥类型信息,导致用户不知道怎么用这个api?

这个问题,个人觉得还好,因为用户是对照着 redis 命令行工具的文档、社区资料来使用的,举个例子:
用户想增加一个计数器,那他需要做的是查 redis-cli 的文档, https://redis.io/docs/manual/cli/

$ redis-cli INCR mycounter
(integer) 7

文档上有写这条命令,那么调 gRPC API 就一一对应(伪代码):

&RedisRequest{
  storeName: "demo",
  cmd: INCR,
  args:["mycounter"],
}

再比如 redis-cli 的文档上有写:

$ redis-cli GETRANGE net_services 0 50
"#\n# Network services, Internet style\n#\n# Note that "

那对应的gRPC API传参就是(伪代码):

&RedisRequest{
  storeName: "demo",
  cmd: GETRANGE,
  args:["net_services",0,50],
}

我们只需要告诉用户“嘿,这个 API 传参和 redis-cli 一模一样,举两个例子blabla,剩下的你们自己去看 redis-cli 文档吧”,不用维护注释、大量文档,“白嫖” redis 社区所有现成的资料

问题2. 既然总归要在sdk 层面定义100 个 interface、总归有那么多工作量,不如定100个 gRPC API,反正没有让工作量增加?

我觉得分两个阶段:

阶段1. 我们可以先不管 sdk interface(比如 java interface),专注于做 gRPC API,用户可以直接用 gRPC;如果用户更喜欢用 jedis sdk 或者 capa sdk,可以修改sdk的内部实现、改成调用 layotto gRPC API ,但是对用户暴露的java interface不变(比如还是 capa interface)
image

阶段2. 有编译工具,把 proto 编译成 java interface。这正好是 sig-api 准备做的事情

100个 gRPC API 的后续维护成本

这个是我最担心的:定 100个 gRPC API 可能不是一次性工作,可能给后续带来很高的维护成本。

因为要:

  • 维护注释、文档、双语教程
  • 如果后续 redis API 有变更(或者新增 API) 我们要及时跟进、补充gRPC API的定义;

这个是比较可怕的,因为现在 Layotto 追求兼容 dapr API,而 dapr API 更新时(比如新增 workflow API, 比如 state API 新增查询接口),我们及时跟进、更新都觉得比较花时间,如果再来一百个,维护成本会更高……

@seeflood
Copy link
Member

@wenxuwan 给点意见?

@seeflood
Copy link
Member

seeflood commented Jun 11, 2022

像 redis API、aws S3 API 这类 "可信协议的 gRPC API"的设计目标、取舍逻辑是:

  1. 弱 SDK,无 SDK
    这个redis gRPC API 功能的价值是“用户不用引入 redis SDK 了”,直接用 gRPC API 就行
    而如果“用户就是想引入 redis SDK”,那可以用社区现成的sdk,用 redis 原生协议和 sidecar 通信,在 layotto/envoy 支持 redis 流量治理
  2. 保证可移植性的前提下,控制成本。
    像 redis API、aws S3 API 这类 "可信协议的 gRPC API"其实是在做“有可移植性的 dapr binding API”,解决 binding API 可移植性不强的问题,要支持的 API 特别多,所以不得不控制成本

@seeflood
Copy link
Member

seeflood commented Jun 11, 2022

action:

  • 调研一下有没有枚举值转字符串的方案

@seeflood
Copy link
Member

seeflood commented Jul 9, 2022

@gdutChenxj Hi, 你还在搞这个issue么?

@kevinten10
Copy link
Member

Hi, 有没有 app->(grpc)->layotto sidecar->(redis)->redis serverapp->(redis)->redis server的性能对比呢

@codedededi
Copy link
Contributor Author

@seeflood 最近没时间搞了,麻烦转给其他人吧

@seeflood
Copy link
Member

Hi, 有没有 app->(grpc)->layotto sidecar->(redis)->redis serverapp->(redis)->redis server的性能对比呢

@kevinten10 我们没专门压过state API,@wenxuwan 压过 grpc 的 invokeService 和 sayHello 接口。当时1000qps下,引入layotto后,(相比于用mosn)rpc耗时增加0.24ms

当然具体精确数字最好专门压测一下

@seeflood
Copy link
Member

@seeflood 最近没时间搞了,麻烦转给其他人吧

@gdutChenxj ok 欢迎有空了再来参与社区

@seeflood seeflood added the help wanted Extra attention is needed label Jul 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/api area/community help wanted Extra attention is needed kind/enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants