MongoDB应用设计调优

应用范式设计

什么是范式

数据库范式概念是数据库技术的基本理论,几乎是伴随着数据库软件产品的推出而产生的。在传统关系型数据库领域,应用开发中遵循范式是最基本的要求。但随着互联网行业的发展,NoSQL开始变得非常流行,在许多的应用实践中也涌现出一些反范式的做法。

  1. 三范式的定义

(1)第一范式:数据库表的每一列都是不可分割的原子项。 如下表,所在地一列就是不符合第一范式的,其中对于“广东省、深圳市”这样的字符串,实际上应该拆分为省份、城市两个字段。

编号所在地
001广东省、深圳市

第1范式要求将列尽可能分割成最小的粒度,希望消除利用某个列存储多值的行为,而且每个列都可以独立进行查询。

(2)第二范式:每个表必须有且仅有一个主键,其他属性需完全依赖于主键。这里除了主键,还定义了不允许存在对主键的部份依赖。如下表中订单的商品信息表,每一行代表了一个订单中的一款商品。为了满足主键原则,我们将商品ID和订单ID作为联合主键,除此之外,每一行还存放了商品的名称、价格以及商品类别。对于商品类别这个属性,我们认为其仅仅与商品ID有关,也就是仅依赖于主键的一部分,因此这是违反了第二范式的。改善的做法是将商品类别存放于商品信息表中。

订单号商品号商品名称单价(元)商品类别
o1g1洗衣液23家居

(3)第三范式:数据表中的每一列都和主键直接相关,而不能间接相关。如在下表中同时补充了城市的信息。

编号姓名性别城市城市人口
001张三北京市1300万人

这里的城市人口等属性都仅仅依赖于用户所在的城市,而不是用户,所以只能算作间接的关系。因此为了不违反第三范式,只能将城市相关的属性分离到一个城市信息表中。

  1. mongodb是反范式吗
    这种问题,笔者告诉大家一个标准的答案:因人而异、难形成定论。
  2. 优缺点
    (1)范式设计消除了冗余,因此需要的空间更少。而且,范式化的表更容易进行更新,有利于保证数据的一致性。但是,其缺点在于关联查询较慢,一些查询需要在数据库中执行多次查找,如果只考虑磁盘操作,则相当于增加了磁盘的随机I/O,这是比较昂贵的。
    (2)反范式的设计一般可以优化读取的性能,mongodb很少会使用数据库的关联查询,因此通过嵌套设计的方式还能减少客户端于数据库之间的调用此。此外,使用嵌入还能获得写入数据的原子性保证,即要么完全成功,要么完全失败。
    实际上,可以同时使用范式和反范式的做法,这也是大多数应用所能考虑的最佳实践。如果采用了反范式的做法,则务必要仔细考虑冗余和数据一致性的问题。如果是数据频繁变化,或者一致性要求非常高的场景,则建议使用范式设计。如果是读多写少,而且可以接受不一致性,则可以考虑反范式设计。
    还应该提到的一点是关于数据库的演讲,范式设计一般会更容易适应未来的一些变化。从管理角度看,建议将范式设计作为一种规范,而将反范式设计视为优化手段,并在使得的场景内使用。

嵌套设计

在文档内使用嵌套

尽管反范式的文档设计通常会使用嵌套设计,但并不代表两者是同一回事。正如前面所言,范式/反范式关注的是冗余问题,而嵌套则更多的是关注文档对象之间的结构化关系。通常,嵌套设计具有较强的表现力。
与嵌套设计相对的则是平铺式设计,但平铺式设计会使文档内的字段显得特别繁多。例如,为了对字段做出区分,我们可能会使用很多奇怪而冗长的命名,如label1,label2等。这些做法会导致后期很难维护,甚至还可能因为误用而产生一些bug。此外,在嵌套式的文档内查找属性还会更快一些。
在关于mongodb的设计模式种,一般鼓励使用嵌套设计,但不意味着可以滥用这种特性。初学者很容易出现的一种误区是,将大量无关的实体信息通过嵌套的方式堆砌到一个文档内。 这种做法不但破坏了文档的结构合理性,也为性能的扩展和数据库的管理带来了不少麻烦。正确的做法应该是根据业务有选择性地使用嵌套。

表达关联

如果按照引用数量来划分,那么表之间地关系一般有一对一、一对多、多对多这几种。然而,对文档数据库而言,引用数量的大小会影响文档的具体模式,一般常见的做法如下。

  1. 内嵌文档
    对于少量存在包含关系的文档(one to few),可以采用完全嵌入的形式,代码如下:

    {name:"张三",addresses:[{xxxxx},{xxxxx}]
    }
    

    嵌入设计提升了读性能,可以在查询表的同时获得其相关的地址列表,而且对于多个地址的更新也只需要一次性完成。但这样做的前提必须是:

    • “few”指向的文档数量必须是少量的,比如<1000个。
    • 整体文档的大小不能超过16MB。
    • 业务上是真正的包含,且总是以“one”作为主题在上下文出现,比如我们总是先查询用户,然后查看它的地址信息。
  2. 内嵌引用
    内嵌引用时内嵌文档的一个变种,不同点在于父文档只是记录子文档的ID字段引用,而不是全部内容。内嵌引用在查询关联文档时需要查找两次。
    使用内嵌引用的原因主要如下:

    • 内嵌文档的体积太大,可能超过16MB的限制。
    • 关联的子文档保持独立性,仅在父文档增加少量的引用,这样不需要在子文档种引入额外的索引。
  3. 引用模式
    引用模式类似外键(没有强制的约束),一般是以文档的某个字段(一般_id)作为引用。引用模式的好处是每个表相对独立,业务处理上也更加灵活;但性能会差一些,需要客户端指向多次数据查找。选择引用模式的原因主要如下:

    • 关联文档非常多,或者关联的增长是不受控制的,不再适合使用内嵌模式。例如在微博上,一条明星微博的评论数量是相当可观的,这就必须采取引用模式。
    • 业务实体关系层级过于复杂。
    • 多对多关系优先采用引用模式。
    • 对数据一致性要求很高,需要避免冗余的场景。

桶模式

桶模式是一种常见的“聚合式”的文档设计模式。简而言之,桶模式就是根据某个维度因子(通常是时间),将多个具有一定关系的文档聚合放到一个文档内的方式,具体实现时可以采用mongodb的内嵌文档或数组。
桶模式非常适合用于物联网、实时分析以及时间序列数据的场景。时间序列数据通常以时间为组织维度,并持续不断地流入系统中地一些数据,比如物联网平台所存储地传感器数据、运维系统对于虚拟机CPU、内存地监控数据等。随着时间的流逝,这些时序数据很容易达到非常大的量级。如果将这些时序数据以时间维度进行聚合存储(按时间分桶),则能达到明显的优化效果。

使用分桶方式有如下好处:

  • 文档高度内聚,查询操作一般只需要检索一个或少量的几个文档,可减少很多随机I/O操作。
  • 占用空间小,索引存储大小大幅度缩减,大大节省了mongodb的内存开销。
  • 易于使用,基于聚合文档之上可以做一些预聚合计算,减少实时计算消耗。

除此之外,桶模式在应用上仍然需要结合场景进行设计,除了增加开发复杂度,还需要考虑以下因素:

  • 避免文档的大小无限膨胀,一个BSON文档的大小不能超过16MB。
  • 相对于insert来说,update或upsert的性能有一点幅度的下降。
  • 多个数据的更新都发生在一个文档种,需考虑是否存在锁竞争的问题。

海量数据分页

传统分页模式

这是最常规的方案,假设我们需要对文章(articles)这个表进行分页展示,一般前端需要传递2个参数:

  • 页码(当前是第几页)。
  • 页大小(每页展示的数据个数)。

但是,这种方式随着页码的增多,skip操作跳过的条目也随之变多,而这个操作是通过cursor的迭代器来实现的,对于CPU的消耗会比较明显。而当需要查询的数据达到千万级时,响应时间就会变得非常长。

使用偏移量

  • 选取一个唯一的有序的关键字段作为翻页的排序字段,比如_id。

  • 每次翻页时以当前页的最后一条数据_id值作为起点,将此并入查询条件中。

    db.articles.find({_id:{$lt:new ObjectId("xxxxxx")}}).sort({_id:-1}).limit(20)
    

折中处理

时间轴的模式通常是做成“加载更多”、上下翻页的形式,但无法自由地选择某个页码。那么为了实现页码分页,同时也避免传统方案带来的skip性能问题,我们可以采取一种折中的方案。这里参考Baidu搜索结果页作为说明。
在这里插入图片描述
通常,在数据量非常大的情况下,页码也会有很多,于是可以采用页码分组的方式。以一段页码作为一组,每一组内数据的翻页采用ID偏移量+少量翻页(skip)操作实现。

批操作

对于mongodb来说,使用批量化api的关键在于,减少了客户端和数据库之间的数据传送次数,将多个文档或多个请求放入一次TCP传送任务往往能获得更高的效率。

批量读

  • 场景一:使用multi get模式
    对于集合种多个_id字段的查询,可以使用$in操作符简化为一次操作。multi get是一种常用的模式,一般指的是合并多个key进行查询,这里的key除了_id,还可以使用任何一个拥有唯一索引的字段。
  • 场景二:调整batchSize的值
    在客户端执行查询命令时,可以通过batchSize来指定返回结果集的批次大小。如果不指定,那么默认首次返回101。一般情况下,在大批量读取的场景种,建议明确指定合适的batchSize的值,具体可以根据文档大小,生产环境的网络带宽等因素来选择。

批量写

mongodb所提供的insertMany、updateMany或者Bulk API都属于批量写的命令。其中Bulk API是最灵活的,它可以将同一集合中的多个不同写操作合并为一次操作。一次Bulk批操作在mongodb服务器上仍然会被拆分为一个个的子命令,根据命令的执行顺序不同,分为以下两种。

  • 有序Bulk,数据库会严格按照顺序执行每个写入操作。在数据库内部,有序批次会根据当前顺序和写类型(insert、update)进行分组,每个分组最多为1000个。如果超过1000个,则会再次拆分。数据库按序对分组进行提交,如果某一个命令执行出错,则整个批次将立即停止并返回错误。
  • 无序Bulk,数据库会并发执行批次中的命令。无序批次在内部同样会进行分组(大小为1000个),但并不会保证执行顺序。无论是否存在执行失败的命令,整个批次都会继续进行直到结束。最终,数据库会在返回响应信息种包含具体的信息,包括哪些命令发生了错误。

默认的Bulk是有序的,但只要条件允许,建议尽量使用无序Bulk进行批操作。无序的处理效率更高,尤其是在分片集合中,执行有序的Bulk操作会变得非常缓慢,mongodb会将每个命令进行排序以保证有序。

读写分离与一致性

无论何时,我们应当将数据库集群看作一个整体。由于在分布式环境中存在多种不确定性,我们可能无法确保所写入的数据是否会丢失,或者刚刚写入的数据是否能马上读取。线性的读写通常可以解决一致性问题,但无法满足高吞吐量的要求。为此,mongodb提供了一些“弹性”的手段,可以让我们在读写一致性和性能吞吐量方面做出细粒度的权衡。

读写分离

副本集实现了数据在多个节点间的复制和实时同步,因此基本可以人为这些节点都包含了可用的数据副本。
默认情况下,数据的读写都会在主节点上进行,但这样一来主节点会承担最多的工作。在某些情况下,我们可能希望将业务的读操作指派到一些从节点上,以此来降低主节点的压力。这就是传统的读写分离模式。
读写分离的做法已经经历了大量项目的实践,同时也取得了比较好的效果。当这种方案的适用场景仍然是有限的,这体现在如下两个方面。

  • 读写分离仅仅分离了读操作,对于数据的写仍然需要在主节点上进行,因此对于写操作频繁的场景并不能受益。
  • 客户端从从节点读取的数据,可能并不是最新的,这是由于主从节点的数据同步存在时延导致的。

所以,读写分离方案一般用于读多写少、对数据一致性要求不是很高的场景,比如社区帖子、商品详情等。

对于采用了副本集的架构来说,客户端可以选择只读写主节点,或者写主节点、读从节点的方式。默认情况下,副本集采用仅读写主节点的模式,客户端可通过设置Read Preference来将读请求路由到其他节点,其中,Read Preference可以有多种选择,具体如下:

  • Primary:默认规则,所有读请求发送到Primary。
  • PrimaryPreferred:Primary优先,如果Primary不可达,则请求Secondary。
  • Secondary:所有的读请求都发送到Secondary。
  • SecondaryPreferred:Secondary优先,当所有的Secondary不可达时,请求Primary。
  • Nearest:读请求发送到最近的可达节点上。(通过ping命令探测出最近的节点)

一些特殊行为

  • 限制延迟读,通过设置maxStalenessSeconds参数来控制读取的延迟,一旦该节点落后主节点的时间超过该值,则放弃从该节点上读取,这个值设置必须大于90s,否则会报错,mongodb3.4及以上版本支持该特性。
  • 定向范围读,可以为从节点成员设定一些标签(TagSet),在读取时指定对应的TagSet,这样读取行为会指向对应的节点。TagSet是一种灵活的成员分组机制,可以根据需要来设定,比如按计算能力,或是地理位置。

读写关注

一般认为,mongodb的读写模式是弱一致性的。在默认配置下的确如此,为了保证性能优先,应用可能允许自己读取的数据并不是最新的,或者刚刚写入的数据存在极小的丢失风险。但是,这些仅限于默认行为的讨论。如果希望获得更强的一致性保证,还可以对写关注(WriteConcern),读关注(ReadConcern)进行调整。

  • 写关注
    客户端通过设置写关注来设置写入成功的规则。默认情况下WriteConcern的值为1,即数据只要写入主节点即认为成功并返回。可以将WriteConcern设置为majority来保证数据必须在大多数节点上写入成功。
    对于成功写入大多数节点的数据,即使发生主从节点切换,仍然保证新的主节点包含该数据,这意味着持久性又饿更高的保证。执行下面的命令,可以实现大多数节点写关注。

    db.users.insert(
    {name:"xxx",},
    {writeConcern:{w:majority,wtimeout:5000,j:true}}//wtimeout:表示写入等待的超时时间,单位为ms。j:保证数据成功写入磁盘的jouma日志,当w为majority时,如果没有明确指定j选项,则默认是true,可以通过writeConcernMajorityJournalDefault来控制该行为。
    )
    
    w说明
    0无须等待任何节点写成功,不保证可靠性
    1等待主节点写成功
    n等待n个节点写成功
    majority等待大多数节点写成功
  • 读关注
    读关注是mongodb3.2版本新增的一个特性,主要用来解决“脏读”的问题。例如,客户端从主节点上读了一条数据,但此时主节点发生宕机,由于这条数据没有同步到其他节点上,在主节点恢复后就会进行回滚。从客户端的角度看便是读到了“脏数据”(可能被回滚)。当ReadConcern设置为majority时,mongodb可以保证客户端读到的数据已经被大多数节点所接受,这样的数据可以保证不会回滚,从而避免脏读问题。
    mongodb对读关注定义了多个级别,具体如下。

    • local
      本地读级别,仅读取本地可用的数据,不确保读取的数据是否被大多数节点接受。对主节点的读操作、从节点在因果一致性会话中的读操作默认采用local级别。
    • available
      本地可用读级别,仅读取本地可用的数据,不确保读取的数据是否被大多数节点接受。该级别和local级别的区别在于,可能会返回分片迁移产生的“孤儿文档”。对从节点在非因果一致性会话中的读操作默认采用available级别。
    • majority
      大多数渡劫别,可读取已同步到大多数节点的数据,可确保读取到的数据不会被回滚。
    • linearizable
      线性读级别(mongodb3.4版本提供),该级别保证能读取到WriteConcern为majority,并且返回确认时间在当前读请求开始之前的数据。linearizable级别只支持单文档操作的线性关系,而且只在读主节点时有效。这意味着如果上一个节点对该文档的写入还未满足大多数写入时,mongodb会进行等待。因此linearizable通常要和maxTimeMS一起使用,以避免长时间的阻塞。linearizable级别中性能下降比较明显,而且其同时也不适用于因果一致性会话、事务等特性。
    • snapshot
      快照读级别,仅可用于多文档事务中,snapshot级别保证了集群级别的快照一致性。

使用ReadConcern=majority需要开启选择replication.enableMajorityReadConcern,从mongodb3.6版本开始,该选项默认是true。

读自身的写入

在一些严谨的业务流程中往往存在这样的需求。如果客户端开启了读写分离模式,那么大概率会读不到上一次写入的数据。

  • 写主节点、读从节点(w:1,rc:available)

    db.orders.insert({orderId:"10001",price:69})
    db.orders.find({orderId:"10001"}).readPref("secondary")
    

    主节点写入后,由于从节点可能未同步到该数据,因此这里读取到的数据可能是空的。

  • 写主节点,读主节点(w:1,rc:local)

    db.orders.insert({orderId:"10001",price:69})
    db.orders.find({orderId:"10001"})
    

    可以说,在绝大多数情况下,find操作会返回数据。但意外仍可能存在,假设在写入主节点成功之后,主节点宕机发生主从节点切换,此时新的主节点并不一定具有orderId:"10001"这条数据,可能返回null。

  • 写主节点,读从节点(w:majority,rc:majority)

    db.orders.insert({orderId:"10001",price:69},{writeConcern:{w:"majority"}})
    db.orders.find({orderId:"10001"}).readPref("secondary").readConcern("majority")
    

    写操作w:"majority"保证了大多数节点都收到了该数据,readConcern:"majority"保证了从从节点读取到的数据已经同步到了大多数节点,但是这并不能保证当前从节点一定包含刚刚写入的数据。

  • 写主节点,读主节点(w:majority,rc:local)

        db.orders.insert({orderId:"10001",price:69},{writeConcern:{w:"majority"}})db.orders.find({orderId:"10001"})
    

    写操作w:"majority"保证了大多数节点都收到了该数据,就算在下一次读之前发生了主从节点切换,也可以保证新的主节点一定包含了该条数据,因此可以保证读自身的写入。但是这种操作,由于读写操作都是针对主节点的,一旦读压力增加便无法兼用读写分离方案。为了在任意节点上也实现这种读自身的写入的特性,最好的办法是使用因果一致性会话。

因果一致性

mongodb3.6版本引入了会话的概念,并基于全局时钟实现了分布式集群上的因果一致性。
因果一致性是分布式数据库的一致性模型,它保证了一系列逻辑顺序发生的操作,在任意视角中都能保证一致的先后关系(因果关系)。例如只有当问题是可见的情况下才会出现对问题的答复,这样问题与答复就形成了依赖性的因果关系。

因果一致性所涉及的特性主要如下:

  • Read your writes,读自身的写入,读操作必须能够反映出在其之前的写操作。
  • Monotonic reads,单调读,如果某个读取操作已经看到过数据对象的某个值,那么任何后续访问都不会返回那个值之前的值。
  • Monotonic writes,单调写,如果某些写操作必须先于其他写操作执行,那么它们会确实先于那些写操作执行。
  • Writes follow reads,读后写,如果某些写操作必须发生在读操作之后,那么它们会确实在那些读操作之后执行。

为了支持因果一致性的全部特性,需要在会话中使用ReadConcern=majority,WriteConcern=majority的读写关注级别。另外,为了保证会话中的一组操作满足先后执行的因果一致性,客户端必须在同一个线程中执行这些操作。
因果一致性的上下文(逻辑时序)信息会被绑定到线程上下文中以实现跟踪。执行如下的命令,开启因果一致性会话,代码如下:

session=db.getMongo().startSession({causalConsistency:true,readConcern:"majority",writeConcern:"majority"})
db=session.getDatabase("appdb")

总结:应用如何选择合适的一致性级别呢?

  1. 如果系统数据并非不可丢失,对于单条信息丢失敏感度不大,则可使用readconcern:loal,writeconcern:1。
  2. 一些重要的ETL过程强调写入持久性,可使用writeconcern:majority。
  3. 金融应用中的订单、交易业务通常需要更高的一致性,可使用writeconcern:majority,readconcern:majority。在关键的流程操作中,使用因果一致性会话可以保证持久性和可见性。

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

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

相关文章

Mac安装配置Tomcat 8

一、官网下载 Index of /disthttps://archive.apache.org/dist/ 1、进入界面如下&#xff1a; 2、我们找到Tomcat文件夹并进入 3、找到Tomcat 8并打开 4、找到对应的版本打开 5、打开bin 6、找到“apache-tomcat-8.5.99.tar.gz”并下载 二、配置Tomcat 1、解压已经下载好的…

【论文精读】VLM-AD:通过视觉-语言模型监督实现端到端自动驾驶

论文地址&#xff1a; VLM-AD: End-to-End Autonomous Driving through Vision-Language Model Supervision 摘要 人类驾驶员依赖常识推理来应对复杂多变的真实世界驾驶场景。现有的端到端&#xff08;E2E&#xff09;自动驾驶&#xff08;AD&#xff09;模型通常被优化以模仿…

百度搜索,能否将DeepSeek变成“内功”?

最近&#xff0c;所有的云平台和主流APP都在努力接入DeepSeek。其中&#xff0c;搜索类APP与搜索引擎更是“战况激烈”。那么问题来了&#xff0c;接入DeepSeek已经变成了标准配置&#xff0c;到底应该如何做出差异化&#xff1f;接入DeepSeek这件事能不能实现11大于2的效果&am…

Flask实现高效日志记录模块

目录 一. 简介&#xff1a; 1. 为什么需要请求日志 二. 日志模块组成 1. 对应日志表创建&#xff08;包含日志记录的关键字段&#xff09; 2. 编写日志记录静态方法 3. 在Flask中捕获请求日志 4. 捕获异常并记录错误日志 5. 编写日志接口数据展示 6. 写入数据展…

25轻化工程研究生复试面试问题汇总 轻化工程专业知识问题很全! 轻化工程复试全流程攻略 轻化工程考研复试真题汇总

轻化工程复试心里没谱&#xff1f;学姐带你玩转面试准备&#xff01; 是不是总觉得老师会问些刁钻问题&#xff1f;别焦虑&#xff01;其实轻化工程复试套路就那些&#xff0c;看完这篇攻略直接掌握复试通关密码&#xff01;文中有重点面试题可直接背~ 目录 一、这些行为赶紧避…

查看已经安装的Python库,高效管理自己的Python开发环境

在日常的Python开发中&#xff0c;掌握如何管理和查看已经安装的库是非常重要的。这不仅能帮助你了解当前项目的依赖关系&#xff0c;还能避免出现版本冲突等问题。在这篇文章中&#xff0c;我们将详细介绍查看已安装Python库的方法&#xff0c;并提供一些实用的工具和技巧。 …

Selenium实战案例1:论文pdf自动下载

在上一篇文章中&#xff0c;我们介绍了Selenium的基础用法和一些常见技巧。今天&#xff0c;我们将通过中国科学&#xff1a;信息科学网站内当前目录论文下载这一实战案例来进一步展示Selenium的web自动化流程。 目录 中国科学&#xff1a;信息科学当期目录论文下载 1.网页内…

Visual Studio Code 2025 安装与高效配置教程

一、软件简介与下载 1. Visual Studio Code 是什么&#xff1f; Visual Studio Code&#xff08;简称VS Code&#xff09;是微软推出的免费开源代码编辑器&#xff0c;支持 智能代码补全、Git集成、插件扩展 等功能&#xff0c;适用于前端开发、Python、Java等多种编程场景。…

工业路由器和工业交换机,打造高效稳定的工业网络?

工业路由器和工业交换机各有千秋&#xff0c;但如何将它们完美结合&#xff0c;构建稳定高效的工业网络&#xff1f;答案就在这里&#xff01; 工业物联网&#xff08;IIoT&#xff09;是高效、稳定的工业网络成为智慧工厂、工业自动化和远程监控等场景的基础支撑。工业路由器…

DeepSeek 助力 Vue 开发:打造丝滑的二维码生成(QR Code)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

TSMaster【第七篇:千机百变——面板设计艺术】

武侠场景导入&#xff1a;唐门暗器阁的启示 江湖传言&#xff0c;唐门暗器之所以独步天下&#xff0c;全凭其「千机匣」中七十二种机关变化。TSMaster面板设计恰似打造暗器机关——控件如同飞镖、机簧、毒针&#xff0c;组合方式不同则威力迥异。昔日某新势力车型因仪表盘刷新…

提升 AI 服务的稳定性:Higress AI 网关的降级功能介绍

在使用 LLM 服务时&#xff0c;服务的稳定性和可用性至关重要。然而&#xff0c;由于网络问题、服务器故障或其他不可控因素&#xff0c;LLM 服务可能会暂时不可用。为了保障用户体验和业务连续性&#xff0c;Higress AI 网关提供了强大的模型降级和令牌降级功能。本文将介绍这…

提升C++项目编译速度

目录 一、问题背景 二、代码规范方面的解决方案 2.1 拆分头文件 2.2 拆分巨型类 2.3 使用前置声明 2.4 避免在头文件中包含实现 2.5 避免头文件重复包含 2.6 将常用且变动较少的独立到一个文件 三、代码业务重构方面经验 3.1 使用PIMPL&#xff08;Pointer to Imple…

【学术投稿-第四届材料工程与应用力学国际学术会议(ICMEAAE 2025】材料工程与应用力学的探讨

重要信息 官网&#xff1a;www.icmeaae.com 时间&#xff1a;2025年3月7-9日 地点&#xff1a;中国西安 简介 第四届材料工程与应用力学&#xff08;ICMEAAE 2025&#xff09;将于2025年3月7日至9日在中国西安召开。本次会议将重点讨论材料科学、应用力学等领域的最新研究进…

抓包工具(三)Wireshark代理抓包Java程序的HTTPS请求

目录 一、需求背景二、操作步骤2.1 jSSLKeyLog 工具下载2.2 jSSLKeyLog工具使用2.3 将sslkeylog导入Wireshark2.4 测试Demo2.5 测试结果1&#xff09;使用工具解密HTTPS前&#xff1a;2&#xff09;实用工具解密HTTPS后&#xff1a; 三、补充&#xff1a;如果出现未解密成功的情…

[VSCode]彻底卸载和重装,并搭建Java开发环境

VSCode彻底卸载 由于当初是朋友帮忙装的&#xff0c;所以准备卸载,自己装一遍 从控制面板找到 vscode 将其卸载。 此时仅仅是删除了应用软件 删除安装插件 在图示路径中找到 .vscode 文件夹&#xff0c;将其删除&#xff0c;即可彻底清除安装的插件 C:\Users\user\.vscode …

泛微OA编写后端Rest接口

泛微OA编写后端Rest接口 前言 具体实现 运行结果 注意要点 总结 前言 在泛微E9中&#xff0c;可以通过注解的方式来编写对外的接口&#xff0c;之前的版本都是通过编写servlet类&#xff0c;然后在web.xml文件中将这个类和访问路径进行编辑之后才好在浏览器中通过输入对应…

041集——封装之:新建图层(CAD—C#二次开发入门)

如图所示&#xff1a;增加一个图层“新图层”&#xff0c;颜色为红&#xff08;1&#xff09;&#xff0c;当图层颜色定义为黄&#xff08;2&#xff09;时&#xff0c;直接覆盖之前图层颜色&#xff0c;图层名不变。 代码如下&#xff1a; /// </summary>/// <param …

Redis存储⑪主从复制_分布式系统解决单点问题

目录 1. 主从复制的概念 1.1 分布式解决单点问题 1.2 主从复制的特点 2. 模拟配置主从复制 2.1 建立复制 2.2 断开复制 2.3 安全性 2.4 只读 2.5 传输延迟 3. 主从复制的拓扑 3.1 一主一从结构 3.2 一主多从结构 3.3 树形主从结构 4. 主从复制的原理 4.1 复制过…

XiaoMi Mi5(gemini) 刷入Ubuntu Touch 16.04——安卓手机刷入Linux

最近在研究个人用的小服务器&#xff0c;期间也搞了一台某讯的盒子&#xff0c;s905的芯片&#xff0c;28G&#xff0c;刷入了Armbian&#xff0c;在自己本地当linux服务器用用挺方便的&#xff0c;但总感觉性能不太够。 然后灵机一动&#xff0c;手上还有几台旧的安卓手机&am…