-
Notifications
You must be signed in to change notification settings - Fork 698
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
unified stub and cluster configuration #65 #90
Conversation
please rebase your change in a commit. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
讨论是否 从redis.Client、redis.ClusterClient 层抽象接口?
将公共指令统一抽象成 XClient 接口 (即现有redis_cmd.go/cluster_cmd.go 的cmd都是公共指令 )
差异部分,可根据需要通过断言 client.(type) 获得具体类型
pkg/client/redis/redis.go
Outdated
var _ Redis = (*RedisClusterStub)(nil) | ||
var _ Redis = (*RedisStub)(nil) | ||
|
||
func StdRedisConfig(name string) RedisConfig { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
config 相关的方法是否考虑仍然放在config.go文件中?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, redis.go
文件只留一个Redis interface{}
pkg/client/redis/redis.go
Outdated
func newRedisStub(config *RedisConfig) *RedisStub { | ||
stub := &RedisStub{ | ||
conf: config, | ||
func RawRedisConfig(key string) RedisConfig { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
考虑配置文件采用下述格式更加显式:
[jupiter.redis.myredis]
addrs = ["one"]
return RedisStub
[jupiter.redis.myredis]
addrs = ["one","more"]
return RedisCluster
并且增加显示的指定用法
[jupiter.redis.myredis]
addrs = ["one"]
client = cluster
return RedisCluster
client = redis/cluster
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 我认为叫
client
不准确,不如改为mode
,redis
后续应该要支持sentinel
模式, 所以mode可以为stub
,cluster
,sentinel
三种 - 现阶段配置->结构的Map
addrs.length == 0
=> panic logaddrs.length == 1 & (mode == ''" | mode == "stub")
=> return stubClientaddrs.length == 1 & mode == "cluster"
=> warning log, return clusterClientaddrs.length > 1 & mode == "stub"
=> warning log, return stubClientaddrs.length > 1 & mode == "cluster"
=> return clusterClient
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👌我认为可以。
addrs.length > 1 & mode == "" => return clusterClient
以接口方式提供缓存服务肯定是应该的, 不过断言让使用者自己拿到结构体,然后调用方法,这样无法解决统一生产/测试,集群/单节点的矛盾,而是将这个问题抛给使用者进行运行时判断,这会带来两个问题
我觉得比较好的处理方式是,
|
像下面这样将接口抽象在内部,对用户暴露还是一个结构体。 //Jupiter's Redis
package redis
type IClient interface {
Get(key string) string
Set(...) ...
... common method ... redis.Client、redis.ClusterClient eg.
}
type Client struct {
conf *RedisConfig
Client IClient
}
func (c *Client) Get(key string) string {
return c.Client.Get(key)
}
func (c *Client) Cluster() (*redis.ClusterClient) {
if cluster,ok := c.Client.(*redis.ClusterClient); !ok {
return nil
}
return cluster
}
//若采用你提到的补充空的 ClusterFunc系列方法,即另外增如下系列的方法:
func (c *Client) ClusterFunc() {
if cc := c.Cluster() ;cc != nil {
return cc.ClusterFunc() // 存在就返回
}
nop := fakeCluster() //不存在就构造空操作的, 并在fakeCluster 中定义具体记日志的细节
return nop.ClusterFunc()//返回空操作
} |
Hello , 想确认一下 对用户暴露 我接触golang时间不久,可能会问一些白痴的问题,请谅解😄 因为我现在比较暴露
|
抱歉,我这里只是写了下伪代码,用来表达一下我的思路,没考虑具体变量的可读性等细节。 暴露api是用struct 还是interface, 肯定是interface 更灵活、也更符合interface的作用。 我描述中的 Client结构体 是 原stub_cmds.go 和 cluster_cmd.go 中的具体实现细节。 (stub_cmds.go、cluster_cmd.go 代码其实是重复的,只是调用的内部对象 Client 分别是 redis. Client 和redis.ClusterClient) 所以,也就是 我上面实现应该是代码最少的。 加了一点注释
上面可能描述的还是有点模糊。 底层: redis.Client、redis.ClusterClient 调用链路是: (称之:B+方案) (因为仅是伪代码描述,名称起的有点乱,可能具体还要斟酌,其中带I的表示接口,否则是具体实现) 另:之前描述,没有 IRedis提到这个接口。个人感觉这里可以不必做多余抽象成接口,直接暴露 Client struct 即可。 即最简链路:(称之:B方案) 现有链路:(称之:A方案) Redis---> RedisStub ---> redis.Client 对比差异: 以上仅是我的观点,仅先做讨论。 另外 warning log 的方式,@askuy 表示不建议这么做。 |
@OhBonsai |
这点我没考虑到,从变更安全的角度,开发者使用Cluster专有函数,应该要知道自己使用的是Cluster。 如果库只给了一个warning log,会把不稳定因素带到生产,把问题推迟到运行时爆发。 那不如采用B方案? B+把事情说复杂了,简单点最好 |
我认为可以。另外,感谢你的工作与讨论。 |
@askuy 我按照B方案提交了一版本,这不是最终的提交。所以我没有rebase. 暂时还有两个问题需要确认 兼容性考虑因为Jupiter暂时还在快速迭代中,暂时应该没有项目在生产环境中使用其开源版本把?是否需要兼容 测试
两者都有好处和坏处
我应该选择那种方式 编写redis的测试? |
我认为增加自动创建本地容器构建测试环境是非常cool的事情。 另外两种测试并不存在矛盾。即可以同时提供两种方案:
最后这些『最佳实践』可以写成文档,放在readme的如何贡献代码部分。 另外我现在使用的是一种偷懒的策略,去跑那些需要环境支持的测试用例,即: 关于https://github.com/ory/dockertest 我没有使用过,不了解机制,需要确认几个点:
考虑后续增加版本内容规划、Jupiter版本号的规划,以处理非兼容改动取舍的问题。 |
@mlboy dockertest实际上就是docker官方库包装了一层,方便在测试的时候使用。 对于你关切的两个问题
我加了一个case, 如果确认OK,我将用这种方法补充完成 |
引入 dockertest 还有个问题,普通开发没有docker环境时候还能否继续继续执行测试? 还有 既然有了 Redis Struct 里面的方法实现,为什么在 stub_cmds.go 中还有一遍相同的实现? 我发了一封邮件到到你在github个人主页所留的邮箱中,请查收。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for your job
unified stub and cluster configuration douyu#65
Describe what this PR does / why we need it
Unified redis single client and cluster client configuration
Does this pull request fix one issue?
Fixes #65
Describe how you did it
redis.go
tostub.go
,redis_test.go
tostub_test.go
interface
Redis
andRedisConfig
RedisStub
andRedisClusterStub
implementinterface Redis
function
RawRedisConfig
unified cluster and single configurationDescribe how to verify it
example/client/redis/main.go
run: go run main.go -config=config.toml
Special notes for reviews