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

负载均衡采用一致性hash算法时,增加虚拟节点数设置 #443

Open
someview opened this issue Jul 19, 2023 · 9 comments
Open

Comments

@someview
Copy link

Why do you need it?

情景一:
当集群内的服务A有本地状态例如本地缓存时,集群内的其他服务服务或者集群外通过higress访问服务A时,需要使用一致性hash算法.
以便让访问A服务的所有流量能转发一致.
情景二:
和增加虚拟节点数,当endpoint变更时,减少服务内部表示状态的数据的迁移

How could it be?

一致性hash算法有三个要素,节点列表,节点权重、虚拟节点数.

ingress 配置里

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    higress.io/upstream-hash-by: "$remote_addr"
    higress.io/upstream-hash-node: 160         //  虚拟节点数
    higress.io/upstream-hash-field:  ""            //  这里field表示的是权重,如何获取带权重的endpoint列表呢,也许可以指定在pod上
  name: demo
 ...

底层实现

  • 实现节点带权重、能设置虚拟节点数的一致性hash
  • 实现节点不带权重、能设置虚拟节点的一致性hash
@johnlanni
Copy link
Collaborator

johnlanni commented Jul 20, 2023

ring_size = std::min(std::ceil(min_normalized_weight * min_ring_size) / min_normalized_weight,
static_cast(max_ring_size))

其中 min_normalized_weight,因为目前 endpoint 都是相等权重的,所以如果有 N 个 endpoint,就是 1/N

目前 min_ring_size 默认值是 1024, max_ring_size 默认值是 8M,这个其实可以保障99.99%的需求了,我觉得加注解控制的意义不大

@someview
Copy link
Author

ring_size = std::min(std::ceil(min_normalized_weight * min_ring_size) / min_normalized_weight, static_cast(max_ring_size))

其中 min_normalized_weight,因为目前 endpoint 都是相等权重的,所以如果有 N 个 endpoint,就是 1/N

目前 min_ring_size 默认值是 1024, max_ring_size 默认值是 8M,这个其实可以保障99.99%的需求了,我觉得加注解控制的意义不大

首先,实际的应用中,配置的应用集群内多个pod之间不一定是平权的。另外,这里相当于提供给用户一种选择,能够让流量按照相同的规则打到集群内的服务去。
不能假设访问集群内的服务A的流量都是从higress网关转发过去的,也许是集群内部的服务转发过去的。这样,在相同的注册中心的情况下,能实现流量转发的一致

@johnlanni
Copy link
Collaborator

@fengyeall111 明白你的需求了,设置不同 pod 的权重,这个是个前置需求。使用 K8s service 的情况下,这块似乎没有合适的机制去设置。如果使用 istio service entry 倒是可以。

@someview
Copy link
Author

@fengyeall111 明白你的需求了,设置不同 pod 的权重,这个是个前置需求。使用 K8s service 的情况下,这块似乎没有合适的机制去设置。如果使用 istio service entry 倒是可以。

也不一定是pod的权重不同才会有这个需求。只需要有分发流量的一致性需求就会有这个问题。同样的一个服务,从higress进来,和从其他地方进来,都需要做相同的hash,higress的一致性哈希算法是不透明的,无法设置虚拟节点数和权重,所有会产生这个问题

@johnlanni
Copy link
Collaborator

@someview 这个可能太理想化和完美主义了,不同的代理使用的一致性hash算法不同,即使允许设置虚拟节点数,也未必能做到完全一致

@someview
Copy link
Author

someview commented Jul 28, 2023

@someview 这个可能太理想化和完美主义了,不同的代理使用的一致性hash算法不同,即使允许设置虚拟节点数,也未必能做到完全一致

为啥不一致呢,从同样的注册中心获取数据,同样的一致性hash算法。在实现的过程中,肯定不会修改更新获取的节点的列表顺序啊

@johnlanni
Copy link
Collaborator

@someview 我上面说的就是不同代理的hash算法会不一致哈,比如nginx和envoy的就不一样

@someview
Copy link
Author

someview commented Aug 1, 2023

@someview 我上面说的就是不同代理的hash算法会不一致哈,比如nginx和envoy的就不一样

这个就头疼了,我们在做一个单元化的系统,单元内服务的流量既有来自同一个集群的其他服务的,也有来自另外的集群通过higress打进来的流量。按照通常的理解,一致性hash算法,获取的node list一致,最终的结果不也是一致的吗,实现这种算法的时候应该不会颠倒node 顺序啊

@johnlanni
Copy link
Collaborator

@someview nginx 也是用的 ketama,但是具体hash ip port 时用的hash算法不同,nginx用的crc32,envoy用的xxhash64

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Todo
Development

No branches or pull requests

3 participants