背景
我们在做拆分服务就是将算法和我们的业务代码拆分开来,因为业务代码要做全球部署,带的算法会增加成本,所以我们将算法从业务中剥离成一个grpc服务。
但是当qps升高以后,我们发现拆分以后的算法服务,没有很好的做到负载均衡,就是有些pod压力特别高,有些pod却一点压力都没有,多个pod依然会有旱的旱死,涝的涝死的情况。这是为什么呢?这时候我们就不得不说下grpc的特性了。
grpc连接特性
grpc连接是粘性连接,这意味着当从客户端到服务器建立连接的时候,相同的连接将被尽可能长时间地用于许多请求(多路复用),这样做是为了避免所有最初的时间和资源花费在TCP握手上。因此,当客户端获取与服务器实例的连接时,它将保持连接。
这时候,当同一个客户端开始发送大量请求的时候,他们都将转到同一台服务器实例上,这就是问题所在,将没有机会负载均衡到其他实例上。
如何解决呢?
我们的服务是在k8s上进行的部署,听说新版本的nginx-ingress已经对grpc有了较好的支持,于是乎我们进行了尝试。
ingress简介
在Kubernetes集群中,Ingress作为集群内服务对外暴露的访问接入点,其几乎承载着集群内服务访问的所有流量。Ingress是Kubernetes中的一个资源对象,用来管理集群外部访问集群内部服务的方式。我们可以通过Ingress资源来配置不同的转发规则,从而达到根据不同的规则设置访问集群内不同的Service所对应的后端Pod。
工作原理
为了使nginx ingress 资源正常工作,集群中必须要有个Nginx ingress controller来解析Nginx Ingress 的转发规则,Nginx Ingress Controller收到请求,匹配Nginx Ingress转发规则转发到后端Service所对应的Pod,由Pod处理请求。Kubernetes中Service、Nginx Ingress与Nginx Ingress Controller有着以下关系:
- Service 是后端真实服务(可以理解为具体的pod),一个Service可以代表多个相同的后端服务。
- Nginx Ingress是反向代理规则,用来规定HTTP/HTTPS请求应该被转发发到哪个Service所对应的pod上。例如根据请求中不同的Host和URL路径,让请求落到不同Service所对应的Pod上。
- Nginx Ingress Controller是一个反向代理程序(可以理解为套了壳的nginx),负责解析Nginx Ingress的反向代理规则。如果Nginx Ingress有增删改的变动,Nginx Ingress Controller会及时更新自己相应的转发规则,当Nginx Ingress Controller收到请求后就会根据这些规则将请求转发到对应Service的Pod上。
Nginx Ingress Controller通过API Server获取Ingress资源的变化,动态地生成Load Balancer(例如Nginx)所需的配置文件(例如nginx.conf),然后重新加载Load Balancer(例如执行nginx -s load重新加载Nginx)来生成新的路由转发规则。
Nginx Ingress Controller可通过配置LoadBalancer类型的Service来创建SLB,因此可以从外部通过SLB访问到Kubernetes集群的内部服务。根据Nginx Ingress配置的不同规则来访问不同的服务。
Nginx Ingress一些特点
- 支持金丝雀部署,蓝绿部署等
- 支持网关高度定制化场景,类似原生nginx一样所有参数可配置
- 提供七层流量处理能力与丰富的高级路由功能。
- 强大的路由功能
- 基于内容、源IP的路由。
- 支持HTTP标头改写、重定向、重写、限速、跨域、会话保持等。
- 支持请求方向转发规则和响应方向转发规则,其中响应方向转发规则可以通过扩展Snippet配置实现。
- 支持HTTP,HTTPS,WebSocket,WSS和gRPC等协议
- 非证书变更时可支持配置的热更新
- 具有较好的可观测能力
- 支持通过Access Log采集日志。
- 支持通过Prometheus进行监控和告警配置
- 较好的运维能力.自行维护组件,可配置HPA进行扩缩容等
- 良好的服务治理能力
- 服务发现支持K8s。
- 服务灰度支持金丝雀。
- 服务高可用支持限流。
操作上手:
使用命令安装ingress
- 先安装Helm
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 > get_helm.sh
chmod 700 get_helm.sh
./get_helm.sh
- 安装ingress Controller
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx \
--create-namespace
- 通过yaml来创建ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
field.cattle.io/publicEndpoints: '[{"addresses":[""],"port":80,"protocol":"HTTP","serviceName":"dsp-ns:dmp-pro","ingressName":"dsp-ns:dmp","hostname":"xxx-xxx.xxxxx.com","path":"/","allNodes":false}]'
nginx.ingress.kubernetes.io/backend-protocol: GRPC
nginx.ingress.kubernetes.io/proxy-read-timeout: "1"
nginx.ingress.kubernetes.io/proxy-send-timeout: "1"
nginx.ingress.kubernetes.io/service-weight: ""
nginx.ingress.kubernetes.io/ssl-redirect: "true"
creationTimestamp: "2023-11-09T09:05:35Z"
generation: 3
name: dmp
namespace: dsp-ns
resourceVersion: "107755586"
uid: 1187b7e0-05bf-4be5-aba8-127f7e0d7b9d
spec:
defaultBackend:
service:
name: dmp-pro
port:
number: 9019
ingressClassName: nginx
rules:
- host: us-dmp.tualta.com
http:
paths:
- backend:
service:
name: dmp-pro
port:
number: 9019
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- '*.xxx.com'
secretName: tuala
使用rancher创建ingress: