학습일지/Knative
KnativeCon 2022 NA - Achieving a highly Available / Scalable Multi-Tenant Eventing backend - Eventing Scheduler
inspirit941
2022. 12. 10. 13:30
반응형
Achieving a highly Available / Scalable Multi-Tenant Eventing backend
영상: https://youtu.be/PKuUXaDl7w0
발표자
- Ansu Varghese : IBM Senior SW Engineer within Hybrid Cloud Research.
- 현재 knative의 pull-based components (Eventing Sources / CR) / Eventing backend에는 크게 두 가지 문제가 있음
- Autoscaling out of box 기능을 지원하지 않음.
- Serverless Experience에 맞게 scale up / down되지 않음.
- 위 기능은 Enterprise Organization solution을 knative으로 구성하려면 꼭 필요한 기능임.
Eventing Scheduler 제안.
- scaling solution
- distribute consumers across the data plane pods, based on your priorities.
- 데모: kafkaSource를 scale out
- Ongoing: scheduler를 다른 knative component에 적용하기 / KEDA autoscaler에 통합하려는 작업을 진행중.
Knative로 Event-Driven Architecture 프로덕트를 구상하려는 사용자의 Expectation.
- Knative는 Serverless 프로덕트 => AutoScaling 기능.
- 쓰지 않게 되면 Scale Down to 0, pull로 들어오는 이벤트 양에 따라 Scale out
- 즉 Workload demand 변화에 따라 idle / fast 하게 반응할 수 있어야 한다.
- multi-tenant 환경
- Efficient Resources utilization.
- Data plane / Controller는 max throughput / compute density on running cluster.
- High Availablity, Resilient. 장애가 생겨도 영향도는 최소화할 수 있어야 함.
현재의 구조
- 하나의 dispatcher 당 하나의 knative resource가 할당됨.
- consumer가 늘어나면 dispatcher도 같이 늘어남.
- throughput 증가를 위한 parallelism이 지원되지 않음. scaling으로 throughput 증가시켜야 하는데 autoscale도 지원하지 않음
New Eventing Scheduler
- 하나의 dispatcher가 여러 consumer와 연결될 수 있도록 partitioning
- Delivery Parallelism
- KEDA autoscaler와 integration
대략적인 구조. kubernetes scheduler를 많이 참고한 구조.
- Duck Type API (Placement) : outcome resulting from scheduler.
- data plane architecture의 동적 타입
- 실제 pod에 연결되어 있는 virtual replicas의 정보를 기록한다.
- Sub Component
- scheduler / De-scheduler
- autoscaler : 관리해야 할 replicas가 많아지면 data plane pod의 개수를 늘린다.
- state collector : cluster 상태를 주기적으로 체크해서 scheduler가 최적의 판단을 내릴 수 있도록 함
- compactor / evictor : compactor는 주기적으로 distribution 상태를 체크하고, evictor는 lower ordinal pod에 공간이 있으면 higher pod에 있는 Replica를 lower로 옮긴다.
- 스케줄링 방법에 관련된 로직은 plugin 형태로 추가해서 쓸 수 있음. core logic을 간결하게 만들어서 유지보수 편의성을 높일 목적.
- 스케줄링의 절차는 stage 단위로 이루어진다.
- filter stage: filter plugin인 predicates에서 로직 수행.
- replica를 할당할 수 없는 Pod인지 아닌지 판단함.
- scoring stage: scoring plugin인 priorities에서 로직 수행
- filter 통과한 pod에 score를 부여함.
- 스케줄러는 score sum이 가장 큰 pod을 선택한다.
- filter stage: filter plugin인 predicates에서 로직 수행.
- plugin은 스케줄러에 register & compile되어 동작한다.
- 스케줄링의 절차는 stage 단위로 이루어진다.
- Recovery: unexpected domain failure / planned worker restart 등의 용도로 쓰임
- data plane replicas used for scheduling consumers -> statefulSet architecture.
- consumer 숫자의 변화로 rebalancing 동작... reconcile loop 로직으로 동작함.
기존 KafkaSource
- Consuming Messages for One or more kafka topics -> single Sink Service로 cloudevent 전달하는 컴포넌트.
- user가 사용하는 external API 역할.
새로운 컴포넌트 개념 도입 : ConsumerGroup / Consumers
- internal API. 사용자가 신경쓸 필요 없는 영역.
- kafka에서 쓰는 Consumer와는 다른 개념. (바꿀 생각도 하고 있음)
kafkaSource는 ConsumerGroup을 생성한다.
- ConsumerGroup은 Eventing Scheduler에서 사용할 virtual pod.
- virtual Pod의 Replica 개수에 따라 scale up / down 되고, KEDA autoscaler가 통제하거나 개발자가 수동으로 scale 조정할 수 있다.
Eventing Scheduler
- virtual replica를 data plane pod (real k8s pod)에 배치하고, kafkaSource의 status field로 값이 propagate(전파) 되도록 한다.
- (now, the job of scheduler is to place these virtual replicas onto real kubernetes pods, and then come up with a set of placements which is then propagated back to kafkasource status fields.)
- Consumer라는 Resource가 real pod에 매핑된다. (하나의 consumer는 하나의 pod에 매핑됨.)
화면 오른쪽의 configmap은 scheduler 설정.
- priorities / predicates는 요구사항아 맞게 설정하면 된다.
- General Standalone Eventing Scheduler를 설계한 가장 큰 이유는 Reusability.
- scheduler의 동작 방식에서 사용자의 Configurable 자유도를 제공함.
- 확장성이 높고 결합도를 낮춘 Resource Controller
- Availability / Scalability 제공
Demo
kafkaSource Autoscale - scale to zero
KafkaSource 설정값: https://github.com/aavarghese/eventing-kafka-broker/blob/knativecon-demo/source-demo.yaml
apiVersion: sources.knative.dev/v1beta1
kind: KafkaSource
metadata:
name: kafka-source-demo
annotations:
eventing.knative.dev/broker.class: Kafka
autoscaling.knative.dev/class: keda.autoscaling.knative.dev
autoscaling.knative.dev/minScale: "0"
autoscaling.knative.dev/maxScale: "12"
keda.autoscaling.knative.dev/pollingInterval: "3"
keda.autoscaling.knative.dev/cooldownPeriod: "10"
spec:
consumers: 12
consumerGroup: my-demo-group
bootstrapServers:
- kafka-0.mh-lbnyvywmvwwvpcmssqgl-4c201a12d7add7c99d2b22e361c6f175-0000.us-south.containers.appdomain.cloud:9093
- kafka-1.mh-lbnyvywmvwwvpcmssqgl-4c201a12d7add7c99d2b22e361c6f175-0000.us-south.containers.appdomain.cloud:9093
- kafka-2.mh-lbnyvywmvwwvpcmssqgl-4c201a12d7add7c99d2b22e361c6f175-0000.us-south.containers.appdomain.cloud:9093
topics:
- my-demo-topic
net:
sasl:
enable: true
type:
secretKeyRef:
name: kafka-secret-source
key: type
user:
secretKeyRef:
name: kafka-secret-source
key: username
password:
secretKeyRef:
name: kafka-secret-source
key: password
tls:
enable: true
sink:
ref:
apiVersion: v1
kind: Service
name: eventdisplay
kafkaSource를 배포한 다음 kubectl get consumergroup
으로 consumergroup 상태를 확인한다.
- kafkaSource에서 consumer를 12로 선언했으므로, replicas가 12개.
- placement 정보를 확인해보면, 12개의 replica가 4개의 kafka dispatcher와 연결된 것을 볼 수 있다.
- dispatcher pod를 multiple nodes in different zones -> HA 확보.
KEDA의 scale을 변경하면 (kubectl scale --replicas=1 deployment keda-operator -n keda
)
- keda Operator가 올라오면, consumergroup에서 볼 수 있는 replica 값이 12 -> 0으로 내려갔다.
- kafkaSource가 idle 상태이므로, event를 받지 않았으니 scale to zero로 내려간 것.
오른쪽 상단의 터미널에서 kafka에 메시지를 넣은 다음 consumergroup을 조회하면, replica값이 0에서 1로 변경된 걸 볼 수 있다.
- 하단 터미널에서 eventDisplay pod의 로그를 조회하면, kafka로 보낸 메시지가 cloudevent로 변환되어 정상적으로 sink에 들어온 것을 확인할 수 있다.
- 시간이 지나면 다시 scale to zero.
Recovery
- kafka로 10만 건의 메시지를 보내고,
kubectl scale --replicas=60 consumergroup <consumergroupName>
명령어로 replica를 60으로 지정.- 10만 건의 메시지를 처리하기 위해 replica가 60으로 올라간 걸 볼 수 있다.
kubectl describe pod kafka-source-dispatcher-2 -n knative-eventing | grep Node
명령어로 kafka dispatcher가 돌고 있는 노드의 ip주소를 확인- demo에서는 노드 버전을 업그레이드하는 식으로 해당 노드를 비활성화함.
- 다시 dispatcher의 노드를 확인하면, 다른 노드로 pod가 이동한 것을 볼 수 있다.
Lesson Learned
- kafkaSource는 'at least once ordered delivery'를 보장한다. 즉 return code가 돌아오지 않으면 retry를 수행하는 식으로 resiliency를 확보.
- 하지만 실제로 테스트해보면
- kafka가 아니라 다른 컴포넌트의 퍼포먼스 이슈로 duplicate event를 처리하는 상황이 종종 발생.
- 예컨대 queue로 받은 이벤트 처리에 시간이 오래 걸려서
- not enough concurrent clients to process events synchronosly
- kafka가 아니라 다른 컴포넌트의 퍼포먼스 이슈로 duplicate event를 처리하는 상황이 종종 발생.
- kafkaBroker를 써서 kafka Consumer Configuration을 configmap으로 설정할 수 있다. parameter tuning이 중요했음
- lower the number of duplicate messages
- speed up concurrent processing
- Eventing Scheduler와 knative-based kafka component (broker / channel) 를 연동하는 작업을 진행중.
- Autoscaling과 Scheduling을 동일한 api에서 처리할 수 있도록 만드는 것이 목표
반응형