关于redis集群
来源:15-11 完成ClusterDatabase

慕瓜9063200
2022-08-10
老师你好,我看完了课程的集群章节,然后有几个问题不太明白,向您请教。
-
consistenthash.go文件中NodeMap结构体是一致性哈希管理器对吗?
-
计算哈希值的时候,用的是例如 set key val中的key是吗?
-
NodeMap结构体中哈希函数是不是为了计算我们发送的key应该去到哪个节点执行?
-
NodeMap结构体中nodeHashs []int存储的是各个节点的哈希值,当我们计算key的哈希值后例如得到a,那么就在nodeHashs []int找到第一个大于a的哈希值,例如得到b,那么b就是这个key应该去的节点的哈希值,然后nodehashMap map[int]string中记录的是节点的哈希值到实际物理节点的映射,我们就可以根据刚才的哈希值b找到这个物理节点。
-
func (m *NodeMap) AddNode(keys …string) {}这个方法就是将物理节点添加到哈希环中,那么这个入参keys …string是不是就是我们配置文件redis.conf中的self和peer?
-
func (n *NodeMap) PickNode(key string) string {}这个方法是不是根据指令中的key到哈希环和nodehashMap找到物理节点?
-
type ClusterDatabase struct { self string nodes []string peerPick *consistenthash.NodeMap peerConnection map[string]*pool.ObjectPool db databaseface.Database }
集群中的每个节点都是一个ClusterDatabase,self就是他自己的ip+端口,nodes []string 记录的就是这个集群中所有节点的ip+端口。peerConnection: make(map[string]*pool.ObjectPool),这个map中key是这个节点的所有兄弟节点的ip+端口,而value就是这个节点对某个兄弟节点的一个连接池,这个连接池中默认的连接数量是8个(如果没做修改的话),这8个连接就是8个client.go,这样理解是不是正确的?
-
如果开启了集群模式,那么原来已经在单机版的redis注册的指令例如strLen key,set key val这样的指令需要在clusterDatabase再注册一次,不然开启了集群模式以后指令到clusterDatabase层就没法识别,这个指令也就没法传到下层的单机版database。
-
在单机版database中,当用户发送指令被resp解析器解析后得到例如set key val,为了避免大量的switch或者if语句,我们将各种指令对应的执行方法注册到了cmdTable中,但是我们需要在程序中使用init()函数将指令执行函数初始化, var cmdTable = make(map[string]*command),set指令在cmdTable中就是cmdTable[set] = func execSet(db *DB, args [][]byte) resp.Reply。而在单机版database上层也就是clusterDatabase我们也采用了类似的设计,routerMap := make(map[string]CmdFunc),那为什么clusterDatabase层不需要使用init()对执行方法初始化呢?
-
老师我把十五章的源码下载了,打开后发现在cluster包下的select.go中execSelect()是灰色的,应该是没有调用,是不是忘了在routerMap中注册这个方法。
-
集群之间转发指令,每个节点不仅是服务端而且还是客户端,按照课程中的思路是三个节点A,B,C,客户连接时,只连接其中的一个节点,假设是A,指令发送到A以后,发现是应该发送给B的指令,于是进行转发,转发的时候是将A节点作为B节点的客户端,可以理解为A节点使用netAssist(实际上就是项目中client.go)把用户的指令发送给了B节点,原版的redis也是这么实现转发的吗?
-
redis客户端client.go是GitHub上开源的吗,还是老师自己写的,需不需要把client.go每一步都弄懂,还是只需要知道怎么使用这个client.go就可以了?还有就是这个client.go是不是就和我们平常在项目中如何操作redis是一样的?
-
我们使用netAssist发送指令以后,A节点转发给B,通过Send方法发送给B节点,那么A节点发送的应该是解析后的set key value指令吧?那么B节点是在哪一层收到指令的呢,如果是在resp层的话,B节点解析指令应该是会出错的。
-
项目中引用的池化工具"github.com/jolestar/go-commons-pool/v2",这里面有个方法NewObjectPoolWithDefaultConfig(ctx context.Context, factory PooledObjectFactory),这个方法就是新建一个连接池吗?它的参数有个PooledObjectFactory,项目中的connectionFactory对他进行了实现,connectionFactory的方法MakeObject(ctx context.Context) (*pool.PooledObject, error) {}其实就是新建一个client.go客户端,所以说我们要建立A节点对B节点的连接池,直接调用NewObjectPoolWithDefaultConfig,传入connectionFactory,就会自动创建连接池,并且每个连接池中都创建了8个客户端,这样理解有没有什么问题或者有没有更清楚一点的表达。
15.这个方法就是创建连接池中对某个节点的连接(客户端),创建客户端后还调用了start()方法,也就是说A节点对B节点的连接池中有8个连接,也可以叫客户端,而这些连接创建之后就已经是处于连接状态了,还是说创建连接池后,连接池里面存在了连接,但是不是连接状态的,只有在需要进行转发指令的时候才会调用MakeObject()新建一个连接?
-
NewObjectPoolWithDefaultConfig(ctx context.Context, factory PooledObjectFactory),这个方法会对每个节点创建一个连接池,连接池中有8个客户端,那么他的并发能力是不是有点低,如果说并发能力低的话想提升并发能力,那么是不是只要增加连接池中的连接数量就可以了?
-
十五章源码中,在db层实现了MGet、MSet、StrLen、Incr、Decr等指令,而集群层clusterDatabase却没有实现这些指令,如果开启了集群模式,那么这些指令都没办法执行,是没有写呢还是这些指令在原版的redis不支持呢
这些差不多就是我看完集群章节的问题,后面回头复习的时候可能还会有许多问题,还望老师能给我这个菜鸡解答,非常感谢
1回答
-
1-8 对
9 cluster_database.go 里面使用下面的语句调用了初始化方法,其实效果和init()是一样的
var router = makeRouter()
10 对
11 原生的redis并不是这样,而是告诉客户端这个key不应该写在本节点,但是会返回正确节点的地址。
12 开源的,知道怎么用就可以了。用法和普通的redis客户端差不多的。只是数据结构上更适合这个项目
13 A发出来的指令会重新编码成RESP协议。
14 NewObjectPoolWithDefaultConfig方法严格来说是新建一个对象池。至于这个池子是连接池、内存池、还是其他什么池,取决于MakeObject方法返回的是什么对象。如果返回的是连接对象,他就是一个连接池。
15 处于连接状态了
15 对
16 课程里面确实没有实现完整
112022-08-11
相似问题