【OpenYurt 深度解析】边缘网关缓存能力的优雅实现

简介: 阿里云边缘容器服务上线 1 年后,正式开源了云原生边缘计算解决方案 OpenYurt,跟其他开源的容器化边缘计算方案不同的地方在于:OpenYurt 秉持 Extending your native Kubernetes to edge 的理念,对 Kubernetes 系统零修改,并提供一键式转换原生 Kubernetes 为 OpenYurt,让原生 K8s 集群具备边缘集群能力。

头图.png

作者 | 何淋波(新胜)
来源 | 阿里巴巴云原生公众号

OpenYurt:延伸原生 K8s 的能力到边缘

阿里云边缘容器服务上线 1 年后,正式开源了云原生边缘计算解决方案 OpenYurt,跟其他开源的容器化边缘计算方案不同的地方在于:OpenYurt 秉持 Extending your native Kubernetes to edge 的理念,对 Kubernetes 系统零修改,并提供一键式转换原生 Kubernetes 为 OpenYurt,让原生 K8s 集群具备边缘集群能力。

同时随着 OpenYurt 的持续演进,也一定会继续保持如下发展理念:

  • 非侵入式增强 K8s
  • 保持和云原生社区主流技术同步演进

OpenYurt 如何解决边缘自治问题

想要实现将 Kubernetes 系统延展到边缘计算场景,那么边缘节点将通过公网和云端连接,网络连接有很大不可控因素,可能带来边缘业务运行的不稳定因素,这是云原生和边缘计算融合的主要难点之一。

解决这个问题,需要使边缘侧具有自治能力,即当云边网络断开或者连接不稳定时,确保边缘业务可以持续运行。在 OpenYurt 中,该能力由 yurt-controller-manager 和 YurtHub 组件提供。

1. YurtHub 架构

在之前的文章中,我们详细介绍了 YurtHub 组件的能力。其架构图如下:

1.png

图片链接

YurtHub 是一个带有数据缓存功能的“透明网关”,和云端网络断连状态下,如果节点或者组件重启,各个组件(kubelet/kube-proxy 等)将从 YurtHub 中获取到业务容器相关数据,有效解决边缘自治的问题。这也意味着我们需要实现一个轻量的带数据缓存能力的反向代理。

2. 第一想法

实现一个缓存数据的反向代理,第一想法就是从 response.Body 中读取数据,然后分别返回给请求 client 和本地的 Cache 模块。伪代码如下:

func HandleResponse(rw http.ResponseWriter, resp *http.Response) {bodyBytes, _ := ioutil.ReadAll(resp.Body)go func() {// cache response on local diskcacher.Write(bodyBytes)}// client reads data from responserw.Write(bodyBytes)
}

当深入思考后,在 Kubernetes 系统中,上述实现会引发下面的问题:

  • 问题 1:流式数据需要如何处理(如: K8s 中的 watch 请求),意味 ioutil.ReadAll() 一次调用无法返回所有数据。即如何可以返回流数据同时又缓存流数据。
  • 问题 2:同时在本地缓存数据前,有可能需要对传入的 byte slice 数据先进行清洗处理。这意味着需要修改 byte slice,或者先备份 byte slice 再处理。这样会造成内存的大量消耗,同时针对流式数据,到底申请多大的 slice 也不好处理。

3. 优雅实现探讨

针对上面的问题,我们将问题逐个抽象,可以发现更优雅的实现方法。

  • 问题 1:如何对流数据同时进行读写

针对流式数据的读写(一边返回一边缓存),如下图所示,其实需要的不过是把 response.Body(io.Reader) 转换成一个 io.Reader 和一个 io.Writer。或者说是一个 io.Reader 和 io.Writer 合成一个 io.Reader。这很容易就联想到 Linux 里面的 Tee 命令。

2.png

而在 Golang 中 Tee 命令是实现就是io.TeeReader,那问题 1 的伪代码如下:

func HandleResponse(rw http.ResponseWriter, resp *http.Response) {// create TeeReader with response.Body and cachernewRespBody := io.TeeReader(resp.Body, cacher)// client reads data from responseio.Copy(rw, newRespBody)
}

通过 TeeReader 的对 Response.Body 和 Cacher 的整合,当请求 client 端从 response.Body 中读取数据时,将同时向 Cache 中写入返回数据,优雅的解决了流式数据的处理。

  • 问题 2:如何在缓存前先清洗流数据

如下图所示,缓存前先清洗流数据,请求端和过滤端需要同时读取 response.Body(2 次读取问题)。也就是需要将 response.Body(io.Reader) 转换成两个 io.Reader。

 

也意味着问题 2 转化成:问题 1 中缓存端的 io.Writer 转换成 Data Filter 的 io.Reader。其实在 Linux 命令中也能找到类似命令,就是管道。因此问题 2 的伪代码如下:

func HandleResponse(rw http.ResponseWriter, resp *http.Response) {pr, pw := io.Pipe()// create TeeReader with response.Body and Pipe writernewRespBody := io.TeeReader(resp.Body, pw)go func() {// filter reads data from response io.Copy(dataFilter, pr)}// client reads data from responseio.Copy(rw, newRespBody)
}

通过 io.TeeReader 和 io.PiPe,当请求 client 端从 response.Body 中读取数据时,Filter 将同时从 Response 读取到数据,优雅的解决了流式数据的 2 次读取问题。

YurtHub 实现

最后看一下 YurtHub 中相关实现,由于 Response.Body 为 io.ReadCloser,所以实现了 dualReadCloser。同时 YurtHub 可能也面临对 http.Request 的缓存,所以增加了 isRespBody 参数用于判定是否需要负责关闭 response.Body。

// https://github.com/openyurtio/openyurt/blob/master/pkg/yurthub/util/util.go#L156
// NewDualReadCloser create an dualReadCloser object
func NewDualReadCloser(rc io.ReadCloser, isRespBody bool) (io.ReadCloser, io.ReadCloser) {pr, pw := io.Pipe()dr := &dualReadCloser{rc:         rc,pw:         pw,isRespBody: isRespBody,}return dr, pr
}type dualReadCloser struct {rc io.ReadCloserpw *io.PipeWriter// isRespBody shows rc(is.ReadCloser) is a response.Body// or not(maybe a request.Body). if it is true(it's a response.Body),// we should close the response body in Close func, else not,// it(request body) will be closed by http request callerisRespBody bool
}// Read read data into p and write into pipe
func (dr *dualReadCloser) Read(p []byte) (n int, err error) {n, err = dr.rc.Read(p)if n > 0 {if n, err := dr.pw.Write(p[:n]); err != nil {klog.Errorf("dualReader: failed to write %v", err)return n, err}}return
}// Close close two readers
func (dr *dualReadCloser) Close() error {errs := make([]error, 0)if dr.isRespBody {if err := dr.rc.Close(); err != nil {errs = append(errs, err)}}if err := dr.pw.Close(); err != nil {errs = append(errs, err)}if len(errs) != 0 {return fmt.Errorf("failed to close dualReader, %v", errs)}return nil
}

在使用 dualReadCloser 时,可以在httputil.NewSingleHostReverseProxy的modifyResponse()方法中看到。代码如下:

// https://github.com/openyurtio/openyurt/blob/master/pkg/yurthub/proxy/remote/remote.go#L85
func (rp *RemoteProxy) modifyResponse(resp *http.Response) error {rambohe-ch, 10 months ago: • hello openyurt// 省略部分前置检查                                                          rc, prc := util.NewDualReadCloser(resp.Body, true)go func(ctx context.Context, prc io.ReadCloser, stopCh <-chan struct{}) {err := rp.cacheMgr.CacheResponse(ctx, prc, stopCh)if err != nil && err != io.EOF && err != context.Canceled {klog.Errorf("%s response cache ended with error, %v", util.ReqString(req), err)}}(ctx, prc, rp.stopCh)resp.Body = rc
}

总结

OpenYurt 于 2020 年 9 月进入 CNCF 沙箱后,持续保持了快速发展和迭代,在社区同学一起努力下,目前已经开源的能力有:

  • 边缘自治
  • 边缘单元化管理
  • 云边协同运维
  • 一键式无缝转换能力

同时在和社区同学的充分讨论下,OpenYurt 社区也发布了2021 roadmap,欢迎有兴趣的同学来一起贡献。

原文链接

本文为阿里云原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/513920.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python的类名一定要大写吗_python 类名

广告关闭 腾讯云11.11云上盛惠 &#xff0c;精选热门产品助力上云&#xff0c;云服务器首年88元起&#xff0c;买的越多返的越多&#xff0c;最高返5000元&#xff01; 如果我从中执行此操作的函数是实例的类派生的基类&#xff0c;我如何找到在python中创建对象实例的类的名称…

Elasticsearch生态技术峰会 | 阿里云Elasticsearch云原生内核

简介&#xff1a; 开源最大的特征就是开放性&#xff0c;云生态则让开源技术更具开放性与创造性&#xff0c;Elastic 与阿里云的合作正是开源与云生态共生共荣的典范。值此合作三周年之际&#xff0c;我们邀请业界资深人士相聚云端&#xff0c;共话云上Elasticsearch生态与技术…

剑指云原生数据库 2.0,阿里云发布全新一站式敏捷数据仓库解决方案

作为基础软件“三驾马车”之一的数据库&#xff0c;其发展历程可追溯到60年前&#xff1a;从上世纪50年代的层次数据库、网状数据库&#xff0c;70年代的关系型数据库&#xff0c;再到90年代的关系型数据库、数据仓库、PC单机数据库和 2000 年的开源数据库&#xff0c;Oracle等…

深度 | 面向云原生数据湖的元数据管理技术解析

简介&#xff1a; 作者&#xff1a;沐远、明惠 背景 数据湖当前在国内外是比较热的方案&#xff0c;MarketsandMarkets市场调研显示预计数据湖市场规模在2024年会从2019年的79亿美金增长到201亿美金。一些企业已经构建了自己的云原生数据湖方案&#xff0c;有效解决了业务痛点…

sql中“delete from 表名”表示_SQL查询语句知识点总结

为什么要学习SQL?数据分析岗位的基础技能&#xff1a;SQL语句和会使用SQL语句操纵数据库软件&#xff1b;数据量增大的工具需求&#xff1a;excel处理十万以内的数据&#xff1b;数据量增大&#xff0c;需要使用更快速便捷的工具分析数据。SQL知识点总结1数据库基础知识什么是…

Serverless 可观测性的过去、现在与未来

简介&#xff1a; 函数计算可观测性经历了 1.0 -> 2.0 的发展&#xff0c;从闭门造车的可观测发展成开源的可观测&#xff0c;从平台的可观测发展为开发者的可观测&#xff0c;从FaaS Only 的可观测演进成了云原生的可观测。 作者&#xff1a;夏莞 背景 Serverless 将成为…

Gartner:全行业投入人工智能,计算机视觉占比最高

编辑 | 宋慧 供稿 | Gartner Gartner最近一项新调研发现&#xff0c;三分之一拥有人工智能&#xff08;AI&#xff09;技术计划的技术和服务提供商企业机构表示&#xff0c;他们在未来两年对人工智能技术的投资将达到100万美元以上。绝大多数将人工智能技术作为主要投资领域的…

爱奇艺大数据生态的实时化建设

简介&#xff1a; 实时化是大数据未来最重要的方向之一。 作者&#xff5c;爱奇艺大数据团队 数据作为互联网时代的基础生产资料&#xff0c;在各大公司企业拥有举足轻重的地位。数据的价值在互联网公司的体现&#xff0c;大致而言可以分成三类&#xff1a; 发掘数据中的信息…

python机械臂仿真_基于Python的3R机器人运动仿真

一、问题描述 如右图所示的三自由度机械臂&#xff0c;关节1和关节2相互垂直&#xff0c;关节2和关节3相互平行。如图所示&#xff0c;所有关节均处于初始状态。 要求: (1) 定义并标注出各关节的正方向&#xff1b; (2) 定义机器人基坐标系&#xff5b;0&#xff5d;及连杆坐标…

AI 事件驱动场景 Serverless 实践

简介&#xff1a; 事件驱动是指事件在持续事务管理过程中&#xff0c;进行决策的一种策略。可以通过调动可用资源执行相关任务&#xff0c;从而解决不断出现的问题。通俗地说是当用户触发使用行为时对用户行为的响应。在 Serverless 场景下&#xff0c;事件驱动完美符合其设计初…

运维质变育新机,华为云能否引领政企运维破局?

头图 | 付费下载于视觉中国 提到IT运维&#xff0c;我们马上想到的&#xff0c;就是“7*24小时待命”、“救火”。作为IT安全运行的保障&#xff0c;长久以来&#xff0c;运维一直都是“不出事看不到价值&#xff0c;一出事全是锅”的角色。例如某企业自动化运维失效导致宕机…

封神-运维大脑 | 日志检测工具

简介&#xff1a; 封神-运维大脑 | 日志检测工具1. 背景目标 阿里云应用业务有问题&#xff0c;云平台监控可以发现问题&#xff0c;但并不能定位到问题根本原因&#xff0c;运维大脑监控底层日志&#xff0c;可快速定位问题原因&#xff0c;帮助现场运维同学解决问题。 运维大…

hive sql练习_经典的SparkSQL/Hive-SQL/MySQL面试-练习题

经典的SparkSQL/Hive-SQL/MySQL面试-练习题​mp.weixin.qq.com第一题需求&#xff1a;已知一个表order&#xff0c;有如下字段:date_time&#xff0c;order_id&#xff0c;user_id&#xff0c;amount。 数据样例:2020-10-10,1003003981,00000001,1000&#xff0c;请用sql进行统…

世纪联华的 Serverless 之路

简介&#xff1a; 2019 年 双11 过后&#xff0c;世纪联华快速上云&#xff0c;将线上核心业务改造为全 Serverless 架构的中台模式&#xff0c;采用“函数计算API 网关OTS”作为计算网络存储核心&#xff0c;弹性支撑日常和大促峰谷所需资源&#xff0c;轻松支撑 618 / 双11 /…

“5G+AI”到底有啥用?这篇漫画告诉你答案…

作者|小枣君来源|鲜枣课堂根据工信部最新的数据&#xff0c;截至8月份&#xff0c;我国5G基站数量已超过百万&#xff0c;达到103.7万个。面对这张全球规模最大的5G网络&#xff0c;我们不禁会思考——它究竟会发挥怎样的作用&#xff1f;它的价值到底体现在哪&#xff1f;它会…

Kubernetes 稳定性保障手册 -- 可观测性专题

简介&#xff1a; 伴随大家对稳定性重视程度的不断提升、社区可观测性项目的火热&#xff0c;可观测性成为了一个很热门的话题&#xff0c;站在不同的角度会产生不同的理解。 我们从软件开发的生命周期出发&#xff0c;尝试形成对可观测性的一个宏观理解&#xff0c;并从 SRE 和…

读懂 Redis 源码,我总结了这7点心得

作者|Magic Kaito来源|水滴与银弹阅读本文大约需要 8 分钟。你好&#xff0c;我是 Kaito。用了这么久的 Redis&#xff0c;也翻了很多次源码&#xff0c;经常有人问我到底怎么读 Redis 源码。一提到读源码&#xff0c;很多人都会比较畏惧&#xff0c;认为读源码是高手才会做的事…

linux c url下载文件,OpenCV教程之使用cmake生成MakeFile时下载文件

在编译OpenCV以及其附加模块时&#xff0c;有时会需要一些第三方的库&#xff0c;如果本地没有&#xff0c;会自动下载&#xff0c;下载地址一般为GitHub&#xff0c;结果当然就是卡死在那里&#xff0c;根本无法下载&#xff0c;下面教大家如何解决这种问题。问题重现比如我在…

OpenTelemetry 简析

简介&#xff1a; OpenTelemetry 是 CNCF 的一个可观测性项目&#xff0c;旨在提供可观测性领域的标准化方案&#xff0c;解决观测数据的数据模型、采集、处理、导出等的标准化问题&#xff0c;提供与三方 vendor 无关的服务。 2021.02.10&#xff0c;OpenTelemetry 的 tracing…

涨姿势 | 一文读懂备受大厂青睐的ClickHouse高性能列存核心原理

简介&#xff1a; 本文尝试解读ClickHouse存储层的设计与实现&#xff0c;剖析它的性能奥妙 作者&#xff1a;和君 引言 ClickHouse是近年来备受关注的开源列式数据库&#xff0c;主要用于数据分析&#xff08;OLAP&#xff09;领域。目前国内各个大厂纷纷跟进大规模使用&…