图数据库 | 19、高可用分布式设计(下)

相信大家对分布式系统设计与实现的复杂性已经有了一定的了解,本篇文章对分布式图数据库系统中最复杂的一类系统架构设计进行探索,即水平分布式图数据库系统(这个挑战也可以泛化为水平分布式图数据仓库、图湖泊、图中台或任何其他依赖图存储、图计算及图查询组件而形成的系统)​。

水平分布式系统

在开始探索之前,我们应该先明确一点,水平可扩展的图数据库系统构建的目的不是让更低配置的机器以集群的方式来承载原来单机才能完成的任务,也不是随着机器配置的降低以更大的集群规模来完成同样的任务。与此相反,在同样的机器配置下,多机构成的集群可以实现更大规模的数据吞吐,最好是实现系统吞吐率随硬件资源增长呈线性分布。

上面描述的两种路线,举例来说明。

· 路线1:原来1台机器8核CPU、128GB内存、1TB硬盘,现在要实现利用8台低配的机器,每台1核CPU、16GB内存、0.125TB硬盘来完成同样的任务,甚至效果更好。

· 路线2:原来1台机器8核CPU、128GB内存、1TB硬盘,现在以同样配置的8台实例来实现之前1台实例的数倍量级(理论上小于等于8)的挑战。

在路线1中,如果只是向客户端提供非常简单的微服务,那么1台拆分为8台是可行的,并且因为8台机器的8块硬盘提供潜在的更高的IOPS,简单数据字段的读写效率会提升,但是,1核CPU的算力可能会小于8核CPU的1/8,1核计算资源的限定会让任何操作只能以串行的方式进行,任何扩展都要与集群内其他实例进行网络通信,也会因此大幅降低任务执行效率。这意味着降配(低配)操作只适合短链条、单线程、简单类型的数据库查询操作,换言之,存储密集型或I/O优先类型的操作可以用“低配分布式”解决。这也是为什么过去在以关系型数据库为主流的数据库发展历程中,存储引擎是“一等公民”​,而计算是依附存储引擎而存在的,是“二等公民”​。

在对路线1的分析中,有个重要的概念:短链条任务,在互联网和金融行业中也称作短链条交易,如秒杀类操作、简单的库存查询等。它涉及的操作逻辑通常比较直白,即使在很大的数据集上,也只需要通过定位和访问极少量的数据即可返回,因此完全可以做到低延时和大规模并发。

对应于短链条任务,长链条任务则要复杂得多,它的数据访问和处理逻辑更复杂,即便在少量数据集上,也可能会牵涉相对大量的数据。如果采用传统的架构(如关系型数据库)​,长链条任务的操作时间会大大长于短链条,每个操作本身对于计算和存储资源的占用程度也更高,不利于形成规模化并发。图1形象地展示了这两种操作的差异性。在路线1中,短链条的任务可能被满足,但是长链条的任务则因每个实例的算力缺失而无法有效完成。典型的长链任务有在线风控、实时决策、指标计算等,对应图数据库上的操作有路径查询、模板查询、K邻查询,或者是多个子查询形成的一个完整查询任务等。

图1: 短链条任务与长链条任务

有鉴于此,在路线2中,在从1台实例扩增到8台实例时,我们不降低实例的配置,目标是让集群可以以水平分布式的方式应对如下3大挑战。

·挑战1:承载更大量的数据集。

·挑战2:提供更高的数据吞吐率(并发请求处理能力)​。

·挑战3:提供兼顾长链条与短链条任务的处理能力(算力提升)​。

如图2所示,在一个由多实例构成的集群内,每个实例都是典型的X86系统架构,在该架构中突出了围绕CPU的北桥(northbridge)算力部分,淡化了南桥(southbridge)相连的存储等I/O设备。事实上,每个实例都是一个可规模化并发的微系统,如CPU的多核(多线程)​、CPU指令缓存、CPU数据缓存、多核间共享的多级缓存、系统总线、内存控制器、I/O控制器、外存、网卡等。以路线1的1台8核CPU与8台1核CPU为例,在充分并发的前提下,后者的计算性能低于前者,前者的存储IOPS(I/O Operations per Second)则低于后者。而路线2的1台8核到8台8核则可能实现算力与存储能力倍增。水平分布式系统的挑战1、2主要通过南桥相连的设备解决(存储、网络)​;挑战2、3主要通过北桥相连的设备解决(CPU、内存)​。

在路线2中,算力终于成为了“一等公民”​,这一点对图数据库而言至关重要。在图数据库的架构设计中,算力引擎第一次和存储引擎平起平坐,这在其他NoSQL或SQL类型数据库中是非常罕见的。只有这样,图数据库才能解决其他数据库所不能解决的复杂查询实时化、深度遍历与下钻、复杂归因分析等棘手的问题。

在我们开始设计一款水平分布式(图)数据库系统架构前,需要厘清一组重要的概念,即分区(partitioning)与分片(sharding)​。一般把分片定义为一种水平分区模式,而分区则默认等同于狭义的垂直分区(或垂直分片)模式。在很多场景下,分区与分片被等同对待,但是通过水平或垂直前缀来修饰具体的切割模式。图5-20示意了一张原始数据库表如何被垂直分区及水平分区。

图2:分布式集群内的每个实例的系统架构示意图
图3:数据库的垂直分区与水平分区

 从图3中可以清晰地看出,在垂直分区(传统分区模式)中,不同的列被重新划分到不同的分区中;在水平分区中,不同的行则切分到不同的分片中。两者的另一个主要区别在于主键是否被重复使用,在垂直分区中主键在两个不同的分区中被100%复用,而在水平分片中则不存在复用。但是,水平分片也意味着需要一个额外的表(或其他数据结构)来对哪个分片中有哪些主键进行跟踪,否则无法高效地完成分表查询。因此,分区还是分片取决于设计者本身的喜好、具体业务查询场景中哪种方式能取得更好的效果、性价比等因素。 

· 顶点数据集如何切分;

· 边数据集如何切分;

· 属性字段如何切分;

· 完成以上切分后,如何实现具体的查询及效率。

之前老夫就介绍过在图数据集中如何进行切点或切边(见下图4、图5、图6)来实现水平分布式的图计算框架。下面我们来推演一种可能的点切与边切融合的水平分布式系统的构建方式。

切边与切点分图的区别示意图 a)切边 b)切点

图5:切点方式

 

图6:一种可能的切点切图计算数据结构切分示意图

 

下图展示了一种可能的多实例分布式系统的构建方式,其中每个实例内都有各自的顶点集、边集以及其他图集相关信息,另外最重要的一个组建就是分布式ID服务(如图5-21右上箭头出处所示)​,任何涉及定位任意点、边在哪个(可能存在多个)实例上可以访问都需要调用这个ID服务,ID服务器只负责以下几项工作:

图7:水平分布式图数据库集群

 

·插入点或边时,生成相应的ID及对应的实例ID;

·查询或更新时,提供相应的ID;

·删除时,提供相应的ID,并回收点或边的ID。

工作看似很简单,但是我们仅以插入点、边为例来分析一下可能的情况。

1)插入新的顶点。

·在唯一实例上;

·在HA主备实例对上;

·在多个实例上。

2)为顶点插入一条出边(outbound-edge)​。

·在唯一实例上;

·在HA主备实例对上;·在多个实例上。

3)为顶点插入一条入边(inbound-edge)​。

·在唯一实例上;

·在主备实例上;

·在多个实例上。

4)为顶点添加一个新的属性。

·在唯一实例上;

·在主备实例上;

·在多个实例上。

5)为边添加一个新的属性。

·在唯一实例上;

·在主备实例上;

·在多个实例上。

 仅仅是围绕点或边的插入操作就分拆出来如上15种可能的组合情况,其他操作如更新、删除等,要考虑的情况更为复杂。在图数据库中,边是依附顶点而存在的,意味着要先有两端的顶点,才会有边,且边存在方向。关于边的方向这一点非常重要,在图论中有无向边的概念,但是在计算机代码实现中,因为涉及图遍历的问题,从某个起始顶点到终止顶点途经一条边,边是有方向的。类似地,在存储一条边的时候,需要考虑如何存储另一条反向边,否则就无法实现从起点反向遍历到终点。图5-22示意了反向边存在的必要,当我们增加一条从点B指向点C的单向边后,系统需要默认同步增加一条反向边,否则从点D无法反向触达点B或其左侧的任何相连顶点,反之亦然。

图8:正向边与反向边

 

同样,删除边的时候无须删除顶点,但是删除顶点需要先从删除边开始,否则系统会立刻出现很多孤边,进而造成内存泄漏等严重问题。事实上,图数据库中批量删除顶点和边是个比较复杂的操作,特别是在分布式数据库中,操作的复杂度与点及边的数量成正比(删边还需要考虑反向边删除的问题)​。删除边的一种可能步骤如下:

1)根据边的ID定位被删除边所在的实例ID(可能存在因一条边的起点、终点在不同实例上的情况,会返回两个甚至多个实例的ID)​;

2)​(并发的)在上一步返回的每个实例上搜索定位该边ID在数据结构中的具体位置;

3)​(并发的)如果采用当前边所属顶点的全部边连续存储的数据结构,把当前位置所在边与尾部边置换,并删除置换后的尾部边;

4)如果每个实例存在多个副本,同步至副本;

5)以上所有操作全部成功后,确认并提交该条边被删除成功,整个集群内的状态同步;

6)​(可选的)回收该条边ID。 

考虑到具体的架构设计、数据结构和算法复杂度,删除边操作的时间复杂度可能有很大的差异。一种可能的实现方式的复杂度为O(3 log N),其中N为全部点的数量,3表示类似的定位查询与实例间同步操作重复的次数。显然,如果是一个有100万条边的超级节点的删除,一整套操作非常复杂,需要先在一个实例上删除100万条边,然后再删除全部反向的100万条边,如果这些边分布在不同的实例上,会触发100万次的边对应实例查询……我们当然可以把所有边的ID整体一次性(或打包分多次查询)提交给服务器来减少网络请求次数,但是这个操作的复杂度与传统数据库中需要大批量删除某些大表中一些行的复杂程度类似。

下面举一个具体例子展示如何对图数据集进行切分,并且如何把数据存储在不同的水平分布的实例上。以图9为例,在系统设计中需要考虑如何处理以下的情形:

·支持多边图,即允许任意两个顶点间可以有多条边。

·支持自环,即可以出现从某个顶点出发回到自身的边。

·允许点、边携带有各自的属性。

·允许从任一顶点出发沿出边或入边访问相邻的顶点(换言之,支持反向边、有向图)​。·允许对图数据集中的顶点进行水平切割(sharding)​。

·(可选的)所有顶点的邻居在同一实例存储。

·(可选的)任一顶点关联的全部边在同一实例存储(无论该实例是否有多个备份)​。

·(可选的)对图数据集中的边进行切割,被切割的边会在两个不同的实例中重复存在。

图9:带有自环的多边图的切图

下表列出了上图中全部顶点及属性的一种可能存储结构,以及将该图一分为三后每个实例上顶点的存储情况。

表1:顶点及属性及点切示意图

表2列出了一种可能的边近邻存储数据结构,注意我们是按照顶点顺序排列的,且每个顶点的所有相邻的边按照正向与反向聚合存储。 

表2:边主体数据结构示意图(不含属性字段)

边的切分逻辑同表1中的顶点切分逻辑,如表5-3所示。

表3: 点切条件下的边分片情况

下面验证这种简单的切图方式是否对图查询有显著的性能影响,有如下几种情况:

·查点(包括读、更新、删除,下逻辑同)​。

·查边。

·查某点的全部1度邻居。

·查某点的K度邻居(K≥2)​。

·查任意两点间的最短路径(假设边上权重相同、忽略方向)​。

·两点在同一实例上;

·两点在不同实例上。

·其他可能的查询方式。

·图算法;

·模板查询、其他方式的路径查询等。

查点又可以细分为很多种情况:

·按照ID查。

·按照系统全局序列化唯一ID查询(又称UUID)​;

·按照原始ID(输入时提供)查询。

·按照某个属性查。

·按照某个属性字段中的文字的模糊匹配(全文搜索)​。

·其他可能的查询方式,例如查询某个范围的全部ID等。

在最简单的情况下,客户端先向ID Server发送查询指令,通过顶点的原始ID,查询其对应的UUID以及对应的实例ID,这个查询的复杂度可以做到不大于O(log N)。

最复杂的是全文搜索,在这种情况下,客户端请求可能会被ID Server转发给全文搜索引擎,取决于引擎的具体分布式设计逻辑,该引擎可能有两种方案:

 ·继续向全部实例分发,并在实例上完成具体的搜索所对应的顶点ID列表;

·引擎返回含有对应顶点的ID所对应的全部实例ID以及顶点ID列表。

查边与查点类似,但是逻辑略为复杂,前面提到过由于每一条边涉及正向存储与反向存储,因此复杂度至少是顶点的2倍。另外,边隶属于顶点,可能会出现需要遍历某个顶点的部分甚至全部边才能定位某一条边的情况。当然,我们可以对所有可能出现遍历的情况进行优化,例如用空间换时间,但是依然要考虑实施的代价与性价比问题。

水平分布式系统最大的考验是如何处理关联数据查询(数据穿透)​,例如从某个点出发查找它的全部邻居。以图58和表5-3中的顶点1为例,要查询其全部1-Hop邻居,完整的步骤如下:

1)​(可选的)根据原始ID查询其UUID;

2)根据UUID查询其所在实例的ID;

3)在该实例上定位到边数据结构中该UUID所在位置;

4)计算该阶段的全部边的数量、关联的顶点ID;

5)对关联ID进行去重运算,并返回结果集。

上操作中,最核心的逻辑是步骤4)与步骤5)​。在步骤4)中,所有顶点1的出边和入边如果以连续存储的方式存在,则可以极低的复杂度O(1)计算出其出入度之和(数值为7)​;在步骤5)中,由于可能出现顶点1与其他顶点多次相连的情形,因此它的1-Hop的结果不是7,而是需要对与顶点1、2关联的3条边进行去重,得到的结果为4。示意如表4所示。

表4:在同一分片内计算顶点1的1-Hop

 

在上述的数据结构设计中,我们可以在任一顶点所在的实例中计算其全部的1-Hop邻居(隐含的也包括其全部的出度边、入度边)​,而无须任何与其他实例间的网络交互。这样相当于能把浅层(小于2层)的操作性能保持与非水平分布式架构持平,并发查询能力却倍增。

我们再来看一下如何计算顶点1的2-Hop邻居数量并返回结果集。依旧以图9为例,具体步骤如下:

1)获取并定位顶点1所在实例的ID。

2)在该实例上定位顶点1及其边数据结构,获取全部相邻顶点ID,对ID去重(获得2、3、5、6)​。

3)对上一步中的顶点集合进行“分而治之”​。

·对以上去重的ID查询其所在分片实例的具体服务器ID,并发送给相应的实例服务;

·顶点2、3因处于当前实例,以类似于步骤2)的方式处理;

·分片2所在实例处理顶点5、6,处理方法同上。

4)对结果集进行组装、去重。

5)向客户端返回。表5-7示意了在多个分片上计算顶点1的2-Hop邻居的流程,按照以上步骤可以分解推导如下结果:

1)顶点1处于分片1。

2)1-Hop:在分片1对顶点1操作去重后的邻居顶点为2、3、5、6。

3)2-Hop:以多线程并发的方式在各个实例上操作。

·顶点2的下一度邻居:4、1,其中1需要去重(因为已经在0度访问过)​;

·顶点3的下一度邻居:7、6、4、1,其中6、1需要去重(因为在1度和0度都访问过,但是此时如果不与同实例或其他实例的其他线程通信,并不知道顶点4需要去重)​;

·顶点5的下一度邻居:1、7、4,其中1需要去重(逻辑同上)​;

·顶点6的下一度邻居:1、3,其中1需要去重(逻辑同上)​。

4)上一步的结果需要全部汇总,逻辑如下。

·所有分片实例向实例1汇总数据;

·顶点序列如下。

·Hop-0:1;

·Hop-1:2、3、5、6;

·Hop-2:4、1;7、6、4、1;1、7、4;1、3。

·跨步去重后2-Hop结果:4、7。

5)向客户端返回去重后的计算结果:顶点1的2-Hop邻居为2个,包含顶点4、7。

表5:跨分片计算某顶点的2-Hop(去重)

在上面的具体操作步骤中,最复杂、最核心的算法逻辑在于如何对数据进行去重。重复的数据带来了几个显著的弊端:

·非去重的数据会导致结果错误,图计算是精准计算,不是概率问题。

·非去重的数据,特别是中间结果,会导致不必要的计算量增大,耗费算力、加大网络通信压力。

但是,如何对数据去重是个非常有技巧和挑战的问题。如前面所述的推导过程,我们在步骤2)​、3)及4)中对计算结果进行了去重,也就是说,在尽可能避免分片实例间通信的前提下,在每一层中都对结果集进行去重操作,并且可以在从上一层向下一层转播的过程中,把之前每一层的去重ID列表向下传播,这个操作可以以一种类似于递归的逻辑实现。

如果我们把这个K邻查询的深度扩展为3-Hop或4-Hop,或者是图的数据量级指数级增加,上面的算法是否还能够保持高效呢?

以图9为例,从顶点1出发,最大深度的Hop就是2-Hop,这时如果进行3-Hop的计算,返回的结果应当为0(空集合)​。但是如果不去校验、去重每一层的数据,在不完成2-Hop之前,无法得知该图数据集并不存在相对于顶点1的3-Hop非空结果集。

以上描述的去重算法的具体实现有以下两种:

1)当前层(跳)向下传播过程中,去重数据,并向下传递自上一层传递下来的数据。

·优点:在每一层内都可以尽可能实现部分去重,降低下一层重复运算的压力。

·缺点:可能会传递大量数据,造成网络压力,且当前分片实例仅能完成局部去重。

2)当前层数据去重,但是不向下一层传播,等待到最后一层做最终的汇总、去重。

·优点:逻辑较为简单。

·缺点:可能会出现大量重复的计算(算力浪费、网络带宽浪费)​,且最后一层汇总的数据量大,不符合分而治之的原理。

用同样的逻辑也可以完成前面描述的其他查询及算法。笔者在这里仅仅列出了一种可能的水平分布式的实现方式,相信聪明的读者可以设计出自己的水平分布式原生图架构。

最后总结一下本章分享的分布式图系统的一些重要理念:

·分布式不是试图用多台低配的设备来取代高配的设备,并寄希望于可以获得更好的效果。毕竟(高性能的)图数据库系统不是用Hadoop的理念与框架可以实现的——如果你还停留在Hadoop时代,那么你的知识栈与认知需要一次很好的升级了。

·分布式系统设计的最重要理念就是审慎地决策哪些图计算的场景需要分片、哪些不需要分片,换而言之,分片可以解决的场景是偏浅层的查询与计算,而深度的计算与分片反向而行。

·计算机体系架构发展到今天,每一个单机、单实例的系统在底层都是一整套可以支持高并发、规模化并发的系统。这个时候,决定系统能力的是其上层的软件。高并发的底层系统并不等于软件天然地做到了高并发。

·数据结构的特征、效率决定了数据库系统的最终效率,或者说是系统的效率上限。·编程语言是有效率之分的。Python和高并发C++程序之间有成千上万倍的性能差异。

·数据库系统的开发需要对操作系统、文件系统、存储、计算、网络等诸多组件深入理解,并且需要很多工程上的调优。学术界理论结合日常工程实践是非常必要的。

·图数据库区别于传统数据库的特性有很多,最重要的是高维性,设计和使用图数据库要有图思维方式。

·图数据库的高维性意味着它的挑战不仅仅是存储,更包括计算。

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

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

相关文章

OpenAI函数调用迎来重大升级:引入「最小惊讶原则」等软件工程实践,开发体验更上一层楼!

想玩转各种AI模型?chatTools 帮你搞定!这里有o1、GPT4o、Claude和Gemini等等,一个平台就能满足你所有的AI需求。快来开始你的AI冒险吧! OpenAI的函数调用功能再次迎来重大更新!新版指南不仅大幅精简了文档,…

Redis 中 TTL 的基本知识与禁用缓存键的实现策略(Java)

目录 前言1. 基本知识2. Java代码 前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 单纯学习Redis可以看我前言的Java基本知识路线!! 对于Java的基本知识推荐阅读: java框架…

前端实习第二个月小结

时间飞快,第一次实习已经过去两个多月,作一些简单的总结和分享。 注:文章整体会比较轻松,提及的经历、经验仅作参考。 一、关于实习/工作内容 1、工作内容 近期做的是管理后台方面的业务,技术栈:前端re…

QT笔记- Qt6.8.1 Android编程 添加AndroidManifest.xml文件以支持修改权限

1. 切换项目选项卡,找到构建的步骤下的最后一项构建安卓APK,展开后找到应用程序栏,点击安卓自定义中的创建模板. 2. 弹出对话框勾选图中选项后点完成 3. 回到项目,查看.pro文件,里面多了很多内容不管,在下…

【鸿蒙】0x02-LiteOS-M基于Qemu RISC-V运行

OpenHarmony LiteOS-M基于Qemu RISC-V运行 系列文章目录更新日志OpenHarmony技术架构OH技术架构OH支持系统类型轻量系统(mini system)小型系统(small system)标准系统(standard system) 简介环境准备安装QE…

【Linux系统编程】—— 深入理解Linux中的环境变量与程序地址空间

文章目录 环境变量常见的环境变量查看环境变量环境变量的修改与使用环境变量的组织⽅式环境变量的命令通过代码如何获取环境变量环境变量的继承 前言:在Linux系统中,环境变量和程序地址空间是系统管理和进程运行的重要组成部分。本文将详细探讨环境变量的…

深度学习 Pytorch 张量的线性代数运算

pytorch中并未设置单独的矩阵对象类型,因此pytorch中,二维张量就相当于矩阵对象,并且拥有一系列线性代数相关函数和方法。 在实际机器学习和深度学习建模过程中,矩阵或者高维张量都是基本对象类型,而矩阵所涉及到的线…

dl学习笔记:(4)简单神经网络

(1)单层正向回归网络 bx1x2z100-0.2110-0.05101-0.051110.1 接下来我们用代码实现这组线性回归数据 import torch x torch.tensor([[1,0,0],[1,1,0],[1,0,1],[1,1,1]], dtype torch.float32) z torch.tensor([-0.2, -0.05, -0.05, 0.1]) w torch.…

【Unity3D】利用Hinge Joint 2D组件制作绳索效果

目录 一、动态绳索 (可移动根节点) 二、静态绳索 三、利用Skinning Editor(Unity2022.3.15f1正常使用) 四、注意事项 一、动态绳索 (可移动根节点) 动态绳索 DynamicRope空物体 Anchor和whitecircle是相同位置的物体&#xff…

OSPF小实验

引言 在前面的博客中我们学习了ospf的基础理论知识与配置:ospf(2),相信大家对ospf已经有了一定的了解了,那么接下来我们就开始尝试做一个ospf的综合实验吧 实验拓扑 实验需求 r1-3为区域0,r3-r4为区域1&…

蓝桥杯刷题第二天——背包问题

题目描述 有N件物品和一个容量是V的背包。每件物品只能使用一次。第i件物品的体积是Vi价值是Wi。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。 输入格式 第一行两个整数,N,V&am…

mono3d汇总

lidar坐标系 lidar坐标系可以简单归纳为标准lidar坐标系和nucense lidar坐标系&#xff0c;参考链接。这个坐标系和车辆的ego坐标系是一致的。 标准lidar坐标系 opendet3d&#xff0c;mmdetection3d和kitt都i使用了该坐标系 up z^ x front| /| /left y <------ 0kitti采…

接口防篡改+防重放攻击

接口防止重放攻击&#xff1a;重放攻击是指攻击者截获了一次有效请求(如交易请求),并在之后的时间里多次发送相同的请求&#xff0c;从而达到欺骗系统的目的。为了防止重放攻击&#xff0c;通常需要在系统中引入一种机制&#xff0c;使得每个请求都有一个唯一的标识符(如时间戳…

流程与管理篇:IPD核心思想与框架

关注作者 IPD是英文&#xff08;Integrated Product Development&#xff09;的写&#xff0c;中文 翻译为“集成产品开发”&#xff0c;它是一套产品开发的模式、理念与方法。 IPD整合了客户需求、市场分析和产品开发&#xff0c;建立了需求和产品之间的联系&#xff0c;开辟…

阿里云通义实验室自然语言处理方向负责人黄非:通义灵码2.0,迈入 Agentic AI

通义灵码是基于阿里巴巴通义大模型研发的AI 智能编码助手&#xff0c;在通义灵码 1.0 时代&#xff0c;我们针对代码的生成、补全和问答&#xff0c;通过高效果、低时延&#xff0c;研发出了国内最受欢迎的编码助手。 在通义灵码 2.0 发布会上&#xff0c;阿里云通义实验室自然…

记录 idea 启动 tomcat 控制台输出乱码问题解决

文章目录 问题现象解决排查过程 1. **检查 idea 编码设置**2. **检查 tomcat 配置**3.检查 idea 配置文件4.在 Help 菜单栏中&#xff0c;修改Custom VM Options完成后保存&#xff0c;并重启 idea 问题现象 运行 tomcat 后&#xff0c;控制台输出乱码 解决排查过程 1. 检查…

微透镜阵列精准全检,白光干涉3D自动量测方案提效70%

广泛应用的微透镜阵列 微透镜是一种常见的微光学元件&#xff0c;通过设计微透镜&#xff0c;可对入射光进行扩散、光束整形、光线均分、光学聚焦、集成成像等调制&#xff0c;进而实现许多传统光学元器件难以实现的特殊功能。 微透镜阵列&#xff08;Microlens Array&#x…

企业级NoSQL数据库Redis

1.浏览器缓存过期机制 1.1 最后修改时间 last-modified 浏览器缓存机制是优化网页加载速度和减少服务器负载的重要手段。以下是关于浏览器缓存过期机制、Last-Modified 和 ETag 的详细讲解&#xff1a; 一、Last-Modified 头部 定义&#xff1a;Last-Modified 表示服务器上资源…

金融项目实战 06|Python实现接口自动化——日志、实名认证和开户接口

目录 一、日志封装及应用&#xff08;理解&#xff09; 二、认证开户接口脚本编写 1、代码编写 1️⃣api目录 2️⃣script目录 2、BeautifulSoup库 1️⃣简介及例子 2️⃣提取html数据工具封装 3、认证开户参数化 一、日志封装及应用&#xff08;理解&#xff09; &…

Redis可视化工具--RedisDesktopManager的安装

需要安装使用&#xff0c;0.9.4以上是要收费的 下载地址&#xff1a;https://github.com/uglide/RedisDesktopManager/releases/download/0.9.3/redis-desktop-manager-0.9.3.817.exe 详情&#xff1a;https://blog.csdn.net/u012688704/article/details/82251338 点击进行安…