聊点技术 | 架构瘦身,让Bonree ONE跑得更轻

2023-04-27

4月21日,博睿数据ONE有引力2023春季产品发布会圆满落幕,一体化智能可观测平台Bonree ONE 2023春季正式版正式发布,这一次发布的版本更轻、更强、更智能。

博睿数据

Bonree ONE在上一版基础上削减50%组件数量,下架两大高耗能组件,单机节省20G+内存,安装时间加快30%,磁盘消耗缩减80%;实现能力的5倍提升,单台16C 32G服务器稳定支撑100 APM探针数据接入或2万日活用户会话,帮助用户大幅降低配置成本。


架构瘦身,让Bonree ONE跑得更轻


本文作者

博睿数据

背景

在数据分析领域,OLAP引擎是整个服务的底座,是整个产品性能的发动机。它需要强悍的数据写入性能,用来支撑高时效的数据价值,同时也需要强悍的数据读取性能,满足我们在OLAP场景中的高效查询需求。高性能一般会伴随着更多资源需求量的产生。如果我们能在同等的数据量下,可以用更少的资源来满足需求,无疑会给产品带来更大的空间。我们从历史Druid繁重引擎切换到了更轻量级的Clickhouse。

同时,Bonree ONE作为强大领先的一体化智能可观测平台,融合了RUM、APM、数据分析、ETL、Alert告警、自适应AI等诸多微应用能力。起初众多组件整合在一起时,整体需要38个组件,组件多,资源占用多,维护成本高,非常繁重。每次POC需要单机64G内存的机器才能部署,且性能非常有限。基于这些痛点,需要对Bonree ONE架构体系做整体梳理,制定瘦身技术方案。

架构(四通一合)

首先,要解决架构问题,好的架构可以少走弯路。Bonree ONE架构体系讲究化繁为简,即四通一合:

● 对象通:采集。统一的对象采集能力,Bonree Agent可以统一采集多端、多源、多种类型对象,并且SmartGate提供了采集数据的汇聚、路由、压缩、缓存、批传、负载均衡、安全管理等智能化功能,让用户数据采的安心、用的舒心。

● 数据通:数据。OneData作为统一的数据平台,可以集成指标、调用链、拓扑、事件、日志等多种可观测性类型数据;OneService作为统一数据服务,自研统一的BPL语句,可以同时计算和查询多源异构的数据集,让数据真正的融合关联用起来,解决传统割裂数据拼凑的问题。

● 模型通:模型。基于数据标准化建模、AI多模态的湖仓一体化,支持开箱即用和AI自适应的在线模型。

● 应用通:标准。多个应用遵循一套OneAPI标准,通过OneFramework可以让微应用插件互相通信,互相赋能。应用也做到了插件化,微应用可以各自单独跑,也可以合并一起跑。能力开放,可以集成与被集成。

● 中融合:ONE架构也到了真正意义的融合。一套体系化的数据、服务、模型都是互通互联,能轻便支持上层业务场景需要的复杂数据模型抽象和计算。


2-1682584395711

OneData底座

架构轻

博睿数据架构

优势明显

● 数据平台组件较少,OLAP引擎只有Clickhouse单个组件,在写入和元数据协同上各有一个组件,且都支持高可用。

● 在POC场景下,Clickhouse精简部署,写入效率完全达到业务需要。

● 在小型集群的场景下,Clickhouse只需要单shard部署,在满足性能的前提下,支持高可用。

● 在晚回数据场景下,Clickhouse天然支持分区,在历史数据和实时数据上,没有区别对待,效率上是等同的。

● 在clickhouse上,通过物化视图和多粒度表的支持,较大范围时间的查询效率同样可以在毫秒级别完成,且是稳定的。

Feature开发

● 写入资源平衡。

● 表粒度入库攒批控制。

● 多租户的支持。

● 数据自治理。

● 复杂数据类型上查询效率的改进。

● 持续优化读写性能,和资源瘦身。

● 数据重分布特性,针对数据扩容情况下的数据分布改进。

● 扩展DDL能力,可以在线支持针对物化视图、projection的动态加减列。

● 轻量级运维能力建设。

效果

相比瘦身之前,ONE技术优化效果:

1.  整体组件从38个减少到19个。

2.  从内存看:

1)  POC配置规格从单机64G降到32G,单机可以支持运行100探针,运行时内存消耗在23G左右;

2)  业务各团队做全链路组件瘦身,POC版瘦身去掉所有hadoop、kafka、brfs、zookeeper等重组件;

3)  指标存储底座从Druid切换到Clickhouse,内存资源降了60%(集群版和POC版都适用);

4)  SwiftAI重构架构,所有服务合并到一个进程组件(集群版和POC版都适用);

5)  OneService作为新一代联邦数据服务,替代了传统较重的Presto大数据组件集合;

6)  OneAPI和OneView支持微应用插件合并,也可以单独部署,替代了传统的SSO和Cloud组件(集群版和POC版都适用)。

3.  从磁盘看,APM的磁盘占用存储降到了1/5(日增100G->20G):

1)  POC版去kafka会大量减少磁盘占用;

2)  trace也做了写入压缩优化(集群版和POC版都适用);

3)  Clickhouse没有Druid的二级hadoop存储占用(集群版和POC版都适用);

4)  Clickhouse本身较Druid压缩比会好些,各业务表的压缩比在8到20倍(集群版和POC版都适用);

5)  AI通过Iceberg湖仓一体和数据治理,按开箱默认指标两个月只需要40G的磁盘空间(集群版和POC版都适用)。

4.  从性能看,拿公有云统计性能数据,基于Clickhouse的OneData底座P99查询性能比历史Druid架构提高了6倍以上,平均耗时从秒级降到了毫秒级。同时在晚回数据场景,稳定性和效率比Druid体现的更加优秀,维护成本为0。

5.  从功能看,ONE较之前秋季版产品增加了一些功能,比如默认会开启AI和会话,AI和会话不再单独追加资源(集群版和POC版都适用)。

6.  从应用框架看,引入强大的插件容器框架OneFramework,提供了运行环境和基础通用能力支持(依赖管理、网关服务、连接池封装、common工具类、会话共享等)。OneFramework可以让业务只关注自己的业务代码开发,并且各自可以独立开发和部署,大大提高了开发迭代和发布效率。一套框架可以灵活应对公有云和私有化不同的环境场景。

博睿数据


文章标签

智能运维 前沿技术 一体化智能可观测

相关文章

FreeMarker template error (DEBUG mode; use RETHROW in production!): The string doesn't match the expected date/time/date-time format. The string to parse was: "2024年3月5日". The expected format was: "MMM d, y". The nested reason given follows: Unparseable date: "2024年3月5日" ---- FTL stack trace ("~" means nesting-related): - Failed at: #if "2024年3月5日"?date lt item.createTi... [in template "themes/halo_quickstarter/post_newsDetail.ftl" at line 106, column 25] ---- Java stack trace (for programmers): ---- freemarker.core._TemplateModelException: [... Exception message was already printed; see it above ...] at freemarker.core.BuiltInsForMultipleTypes$dateBI$DateParser.parse(BuiltInsForMultipleTypes.java:220) at freemarker.core.BuiltInsForMultipleTypes$dateBI$DateParser.getAsDateModel(BuiltInsForMultipleTypes.java:190) at freemarker.core.BuiltInsForMultipleTypes$dateBI$DateParser.getAsDate(BuiltInsForMultipleTypes.java:197) at freemarker.core.EvalUtil.modelToDate(EvalUtil.java:86) at freemarker.core.EvalUtil.compare(EvalUtil.java:270) at freemarker.core.EvalUtil.compare(EvalUtil.java:115) at freemarker.core.ComparisonExpression.evalToBoolean(ComparisonExpression.java:78) at freemarker.core.IfBlock.accept(IfBlock.java:49) at freemarker.core.Environment.visit(Environment.java:370) at freemarker.core.IteratorBlock$IterationContext.executedNestedContentForCollOrSeqListing(IteratorBlock.java:321) at freemarker.core.IteratorBlock$IterationContext.executeNestedContent(IteratorBlock.java:271) at freemarker.core.IteratorBlock$IterationContext.accept(IteratorBlock.java:244) at freemarker.core.Environment.visitIteratorBlock(Environment.java:644) at freemarker.core.IteratorBlock.acceptWithResult(IteratorBlock.java:108) at freemarker.core.IteratorBlock.accept(IteratorBlock.java:94) at freemarker.core.Environment.visit(Environment.java:334) at freemarker.core.Environment.visit(Environment.java:340) at freemarker.core.Environment.visit(Environment.java:340) at freemarker.core.Environment.process(Environment.java:313) at freemarker.template.Template.process(Template.java:383) at org.springframework.web.servlet.view.freemarker.FreeMarkerView.processTemplate(FreeMarkerView.java:391) at org.springframework.web.servlet.view.freemarker.FreeMarkerView.doRender(FreeMarkerView.java:304) at org.springframework.web.servlet.view.freemarker.FreeMarkerView.renderMergedTemplateModel(FreeMarkerView.java:255) at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:179) at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:316) at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1401) at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1145) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1084) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) at javax.servlet.http.HttpServlet.service(HttpServlet.java:497) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at javax.servlet.http.HttpServlet.service(HttpServlet.java:584) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799) at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1631) at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:230) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at run.halo.app.cas.UserInfoFilter.doFilter(UserInfoFilter.java:37) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at org.jasig.cas.client.util.AssertionThreadLocalFilter.doFilter(AssertionThreadLocalFilter.java:54) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at org.jasig.cas.client.util.HttpServletRequestWrapperFilter.doFilter(HttpServletRequestWrapperFilter.java:75) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at run.halo.app.cas.MyAbstractTicketValidationFilter.doFilter(MyAbstractTicketValidationFilter.java:215) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at run.halo.app.cas.MyAuthenticationNoLoginFilter.doFilter(MyAuthenticationNoLoginFilter.java:57) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at run.halo.app.security.filter.ContentFilter.doAuthenticate(ContentFilter.java:69) at run.halo.app.security.filter.AbstractAuthenticationFilter.doFilterInternal(AbstractAuthenticationFilter.java:229) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at run.halo.app.filter.CorsFilter.doFilter(CorsFilter.java:53) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at run.halo.app.filter.LogFilter.doFilterInternal(LogFilter.java:40) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:193) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1601) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:548) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:600) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501) at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.Server.handle(Server.java:516) at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487) at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131) at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883) at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034) at java.base/java.lang.Thread.run(Thread.java:834) Caused by: freemarker.core.UnparsableValueException: Unparseable date: "2024年3月5日" at freemarker.core.JavaTemplateDateFormat.parse(JavaTemplateDateFormat.java:51) at freemarker.core.JavaTemplateDateFormat.parse(JavaTemplateDateFormat.java:33) at freemarker.core.BuiltInsForMultipleTypes$dateBI$DateParser.parse(BuiltInsForMultipleTypes.java:213) ... 118 more Caused by: java.text.ParseException: Unparseable date: "2024年3月5日" at java.base/java.text.DateFormat.parse(DateFormat.java:395) at freemarker.core.JavaTemplateDateFormat.parse(JavaTemplateDateFormat.java:49) ... 120 more