java基于keda事件驱动的k8s 容器自动伸缩

背景

当java程序在处理某一特定的任务时,大多是在同一jvm中,也就是在同一容器内,所以无可避免的会暂用一定的系统资源,造成原有业务上的系统卡顿.甚至是直接造成系统宕机,如果是直接在系统启动时增加系统资源,又会在任务空闲时造成资源上的空闲期,属于浪费系统资源,未能最大化的使用系统资源.

因此,在这一环境背景下产生了任务异构服务的架构方式,即任务单独执行的服务,可以在处理任务时不会争抢原有容器的cpu等硬件资源,但是这种架构方式在任务空闲期还是会任务容器内的线程空闲,照成系统资源的浪费情况.

所以,需要一种支持在有任务待执行的时候任务服务启动,当任务执行结束后线程关闭,任务执行容器下架,释放系统资源的架构方式,也就是本文要概述的事件驱动的自动伸缩.

架构优点

1.硬件资源最大化利用:当任务空闲时主动释放资源,供k8s集群内其他容器使用硬件资源,任务被调起时申请系统资源,快速的处理当前任务.

2.提高任务执行效率:由原本的线程级别,提高到进程级别,加快了任务执行速度,减少了cpu时间片分配.

3.不影响原有业务的服务状态:由于是新起的容器服务,加上k8s的资源隔离体系,因此在任务容器启动执行阶段不会对原有业务容器造成硬件资源上的争抢和占用.

架构方式

底层容器化环境:

k8s+docker

服务插件:

keda+mysql/redis 等作为事件消息的中间驱动层和消息存储层.

运行服务:

主java程序,例如java Web,keda监听程序,keda驱动程序,execute任务执行程序

KEDA 介绍

KEDA is a Kubernetes-based Event Driven Autoscaler. With KEDA, you can drive the scaling of any container in Kubernetes based on the number of events needing to be processed.

KEDA is a single-purpose and lightweight component that can be added into any Kubernetes cluster. KEDA works alongside standard Kubernetes components like the Horizontal Pod Autoscaler and can extend functionality without overwriting or duplication. With KEDA you can explicitly map the apps you want to use event-driven scale, with other apps continuing to function. This makes KEDA a flexible and safe option to run alongside any number of any other Kubernetes applications or frameworks.

KEDA地址:https://github.com/kedacore/keda

由于keda官方目前还没有对java api或是http等接入方式做出兼容,因此需要一种监听中间件的方式来对execute程序做出驱动,本文就以mysql作为中间件的驱动方式做一个example

example

java主程序

建立一张任务执行表,表中有相关任务的执行状态,初始状态为待执行.

然后启动一个mysql-scaledobject的触发程序容器,.xml容器主要内容有

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: mysql-scaledobject
  namespace: my-project
spec:
  scaleTargetRef:
    name: worker
  triggers:
  - type: mysql
    metadata:
      queryValue: "1"
      query: "SELECT status FROM task_instance WHERE state=0"
    authenticationRef:
      name: keda-trigger-auth-mysql-secret

 

然后还有一个连接中间件容器程序 keda-trigger-auth-mysql-secret

apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: keda-trigger-auth-mysql-secret
  namespace: my-project
spec:
  secretTargetRef:
  - parameter: connectionString
    name: mysql-secrets
    key: mysql_conn_str

 

然后就是任务的execute执行容器了

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secrets
  namespace: my-project
type: Opaque
data:
  mysql_conn_str: dXNlckB0Y3AobXlzcWw6MzMwNikvc3RhdHNfZGI= # base64 encoded value of mysql connectionString of format user@tcp(mysql:3306)/stats_db

 

执行过程

当mysql-scaledobject 获取mysql 的执行结果,并判定是否超出了筏值,如果是超出了筏值则驱动execute容器启动,变更任务的执行状态,当execute执行完毕后,更改相关mysql任务的状态,主动结束掉进程,execute容器销毁,资源释放.此时mysql中存储的相关任务的执行状态就由未执行,变为执行中,至为执行成功,或是其他状态,便不会再次的去触发筏值,execute容器也就不会被调度启动.

部署条件

可以部署到云原生的k8s集群内,也可部署到官方支持的相关k8s集群内.

keda对execute容器没有做过多的限制,因此可以对有状态副本集,或是无状态副本集都可以支持调度.

execute服务设计

可以在execute服务中兼容多种,可以采用java的事件处理机制,对不同的任务类型做出相关的实现.在容器运行时也只是该事件的单一处理流程在占用系统资源,其他的事件由于不匹配也就不会运行.

其他的事件在触发的时候也会调度execute容器启动,保证了容器内执行程序的单一性,极大的提高了处理能力,与系统资源的利用.而且避免的重复开发和execute容器镜像的冗余.

本文观点还未实践,目前是一种架构方式,参照相关调研结果,理论可行

上一篇:java 设计模式之-委派模式


下一篇:一句话***:ASP篇