关于系统重构实践的一些思考与总结
文章目录
- 一、前言
- 二、系统重构的范式
- 1.明确目标和背景
- 2.兼容屏蔽对上层的影响
- 3.设计灰度迁移方案
- 3.1 灰度策略
- 3.2 灰度过程设计
- 3.2.1 case1 业务逻辑变更
- 3.2.2 case2 底层数据变更(数据平滑迁移)
- 3.2.3 case3 在途新旧流程兼容
- 3.2.4 case4 接口变更
- 3.2.5 case5 状态机兼容
- 三、系统重构过程中的风险控制
- 3.1 设计阶段
- 3.1.1 流量梳理
- 3.1.2 异常脏数据梳理
- 3.2 开发阶段
- 3.2.1 单元测试
- 3.2.2 代码CR
- 3.3 测试&预发线上回归阶段
- 3.3.1 线上线下流量回放&流量验证
- 3.3.2 核心主链路回归&异常case回归
- 3.3.3 BCP对账,反向验证数据结果
- 3.4 开城中
- 3.4.1 小批量验证
- 3.4.2 数据迁移过程中的反向校验sql
- 3.4.3 及时回滚
- 3.5 开城后
- 3.5.1 及时响应机制
- 3.5.2 BCP对账
- 3.6.开城后收尾
- 四、回顾与反思
一、前言
前段时间一个老的系统重构项目上线,在这个过程中出现了很多问题,遂想针对在这个过程中遇到的一些问题和实践,记录总结一套系统重构的范式,并回顾反思在这个过程是否有哪些值得改进的地方。
注:这里系统重构的定义,不仅是技术上的重构,更是产品逻辑上的重构。
二、系统重构的范式
系统的重构都需要考虑对原有系统的影响,不会另起一个项目,从头写到尾,还把上下游做相应的修改,这种做法虽然"彻底干净",但是成本太大,所以本文暂不讨论这种方案。
一般来说,老系统的重构都需要做到至少接口层面的兼容,这样可以保证系统的重构不会逸散到系统之外,对于上下游而言重构是无感的。
1.明确目标和背景
对于系统重构,需要最小化影响面,而这个前提就是需要我们明确我们的目标是什么,是字段迁移,还是业务模型的变动,亦或者是业务逻辑的变动。
- 底层存储变动?
- 数据模型变动?
- 业务逻辑变动?
- 迁移过程中是否不可用?
在这个阶段,需要梳理出你的改动对于整个项目的影响,比如影响到哪块业务逻辑,哪些接口。
如果是对整个项目大的重构,需要梳理现有系统的流量入口。
2.兼容屏蔽对上层的影响
核心思路就是尽量在最底层去屏蔽这些影响。
比如底层存储修改,那么是否能在dao层就去兼容,让上层的调用和之前一样。
不同语言有不同的技巧,核心就是方法增强,在原先逻辑上增加附加兼容逻辑。
对于Java而言,可以用切面、框架内注册处理器(如filter),亦或者重写get/set方法等等,
对于Go而言,也是类似,虽然没有切面,但也能利用结构体嵌入、接口和组合的方式实现类似的效果。
这样的好处就是
- 风险可控
- 修改成本低
坏处也有:
- 逻辑里夹杂着特殊逻辑,代码复杂度会提升
3.设计灰度迁移方案
系统重构必然存在新老系统切换的过程,尤其是如果需要灰度验证的话,那么新老系统切换的过程会很长,我们就需要考虑新老系统同时存在的影响。
3.1 灰度策略
系统重构往往需要灰度验证,出发点往往有以下几种:
- 控制影响面
小范围验证,避免新系统的问题对业务的影响过大
- 业务诉求
这点在B端业务里尤其常见,例如每开一些城市前,业务同学都需要和商户侧有对应的宣贯,周知到商户
灰度的策略也有很多,常见的有
by城市、by商户、by流量等,
这个决于业务倾向,这里面着重需要考虑的点在于
- 选用这种灰度是否会影响数据不一致
- 是否对业务有影响
常见的B端业务主要都是by城市维度去进行开城。
3.2 灰度过程设计
3.2.1 case1 业务逻辑变更
对于业务逻辑变更的场景,比较简单,我们往往是封装对应的开关逻辑,命中则走新逻辑,否则走老逻辑。
需要注意的就是在代码中的组织尽量封装成方法/函数,方便后续灰度全量时进行无用代码删除,降低代码复杂度。
3.2.2 case2 底层数据变更(数据平滑迁移)
这里的变更可能是同一张数据表字段使用迁移(典型场景就是敏感字段加密),也可能是不同表的数据。
双写方案
1.开启双写(老->新)
目的:让增量的数据也能同步更新到的新数据,
2.数据迁移脚本
目的:让存量的数据刷到新的数据中
经历第二步骤后,旧数据已经全量同步到新数据中。
3.开城(切读&写)
开启开城开关,流量入口开始从旧逻辑切换到新逻辑,新逻辑会读&写新数据,同时会双写老数据
双写老数据目的:切换开关后出现的数据也能同步老数据,如果出现问题,回滚开关时可以实现无损回滚
4.关闭双写
目的:双写毕竟还是冗余操作,当全量开城时,我们需要将这部分逻辑给去了,避免影响系统性能
5.下线老逻辑代码
目的:减少无用代码,降低代码复杂度
以上是较为完整的迁移过程,实际上可以根据自己的实际场景对步骤做一定程度上的简化。
比如我是典型的B端业务,实际迁移过程无需那么平滑,甚至允许一定时间内停止对外提供服务(比如停服维护),那么我们可以无需第一步的双写(老->新),只需在开城后再增量刷一遍数据即可。
3.2.3 case3 在途新旧流程兼容
旧系统中有一些流程结束并不是简单的通过开关就能进行新旧逻辑的切换,
比如B端的审批流,我们就需要考虑在切换新系统后,兼容老的审批回调。
这里主要有两种思路:
- 老回调逻辑生效,双写新逻辑
- 老回调逻辑失效,新逻辑重新推审
具体方案得根据具体业务而定。
3.2.4 case4 接口变更
原有接口如果无法承载新业务逻辑的交互,如果不能确定影响范围,那么只能在原有请求字段中新增字段,不允许修改和删减,保证向后兼容。
有一种case比较特殊,就是专门给前端交互用的接口,如果新的业务形态下,页面的交互已经变化,那么可以废弃原来的接口,另起接口去支持新的功能交互。
3.2.5 case5 状态机兼容
状态机变化需要明确新老状态之间的映射。其本质就是case2底层数据变更的思路。
三、系统重构过程中的风险控制
3.1 设计阶段
3.1.1 流量梳理
在系统重构,尤其是老系统重构的过程中,流量梳理是设计阶段必须要做的一件事情。
因为老系统往往存在大量无用逻辑,以及各种各样的复杂业务接口。在设计之前我们必须要梳理出当前系统对外部开放在使用的能力。
这里列举一些常见的流量入口:
- http(VIP、域名)
- rpc(如thrift&grpc、dubbo、kepler等)
有了范围,我们接下来做的就是考虑我们本次修改可能会对这些接口造成哪些影响。
3.1.2 异常脏数据梳理
线上脏数据梳理是非常容易被我们忽视的,而这造成的结果往往就是数据迁移/开城后会出现一些特殊case,严重的会引发事故。
在我们不熟悉旧系统迭代的情况下,我们很难考虑到线上数据有多少是在”我们意料的规则之外“的。
”我以为这个数据是这样的,可是线上有脏数据导致…“
”啊,还有数据是这样的?“
这往往是我们事后才发现的问题。
我们应该把这块前置,在设计阶段就要梳理出这个表/数据的用法,以及是否存在一些出乎我们意料的数据,尤其要多对比新旧逻辑下,这些数据可能造成的影响。
也许这个脏数据在老系统规则下能正常运行,但是在新系统规则下它就是会出问题!
我们需要多写sql,去统计当前线上库的数据分布,并去分析新旧逻辑下的影响。
3.2 开发阶段
3.2.1 单元测试
好的单测是可复用的,拥有完整的mock和断言能力。
系统重构设计修改的方法最好是要有对应的单测case。
3.2.2 代码CR
代码CR可以规避部分因代码bug引发的错误。
但是实际项目开发中,因为排期紧、代码改动量过大等原因,大型系统重构的实践效果往往不是很理想。
3.3 测试&预发线上回归阶段
3.3.1 线上线下流量回放&流量验证
流量回放是用于验证老接口是否发生变化的最好工具。
其核心是用线上的流量到线下测试环境进行流量验证,对比前后差异这里依赖基础设施的建设。
如果没有完善的流量回放工具,则可以写个脚本,用来对比流量的接口。
不过对于缺失的mock能力,可以通过copy线上的数据到线下来进行模拟。
3.3.2 核心主链路回归&异常case回归
核心主链路必须要回归,避免新系统对线上核心流程造成影响
3.3.3 BCP对账,反向验证数据结果
针对核心业务流程,以及数据迁移脚本中的数据对比,都可以用BCP对账来进行反向校验。
这里主要针对一些核心的流程去写对账,对账逻辑可以依据一些特定的数据规则来写,从结果层面去验证数据的正确性。
常见实现的方式有:
- binlog+sql
- binlog+延迟mq+sql
- 定时任务+hive
通过这样写反向的sql校验,可以低成本的去对结果进行兜底,及时感知到异常case。
需要注意的是,这种BCP对账的sql要注意sql耗时时间,虽然是离线库,但是性能太差也是不可接受的,运行时间过长的建议采用定时任务+hive表的方式。
3.4 开城中
3.4.1 小批量验证
正式开城时,我们必须要有小规模验证的过程。
比如数据迁移时,我针对单个商户进行迁移,然后回归具体的case,如果没有问题再逐步放量。
3.4.2 数据迁移过程中的反向校验sql
数据迁移脚本运行后,我们如何确定我们的执行结果是正确的,除了打印必要的日志和结果通知,还有准备对应的反向校验的sql,来验证我本次刷数是符合预期的。
BCP的报警其实也是同理(不过在大批量数据变更的情况下,BCP报警可能会出现延迟)。
3.4.3 及时回滚
如果出现问题及时回归,按照预期设定的回滚预案进行回滚。
具体的回滚策略如下:
- 代码回滚
- 灰度开关
- 数据库刷数回退(有的公司可能会支持这种能力)
3.5 开城后
3.5.1 及时响应机制
开城后,可以建立业产研开城群,方便开城后问题的沟通,及时跟进和止损。
3.5.2 BCP对账
同前面,略
3.6.开城后收尾
多次的重构,会留下很多无用代码,徒增代码复杂度,良好的习惯就是在新系统全部开城后,删除无用代码。
四、回顾与反思
真实项目中的挑战远不止这些,还有诸如对老系统不熟悉,排期压力大等挑战,这些buff叠加进而导致老系统重构中的风险不可控。
在最近的重构需求中,我大致统计了下本次重构记录的19个线上问题,其原因分布如下
- 未考虑到的线上脏数据 4
- 代码bug漏出 13
- 产品逻辑&技术方案问题 2
主要原因:
- 旧系统逻辑产研了解都较少,这个虽然不是直接原因,但确实很大程度影响了项目风险控制
- 无一个有效的流量回放&流量对比的工具来控制影响面
- 测试阶段回归不全面,导致bug漏出
- 设计阶段缺少统计线上数据分布,忽略了”脏数据“在新系统逻辑下的影响
大家说的脏数据,其实不单单是在原先系统中的不合规/不该存在的数据,也有一些是因为历史迭代而产生的”正常数据“,这些数据可能在老系统运行正常,但是在新逻辑下就不一定适用
对于及时感知线上问题方面,其中BCP报警起了不可或缺的作用,上述问题中有7个是通过BCP报警发现,由此可见BCP对账对于系统重构的重要性。
相关文章:
关于系统重构实践的一些思考与总结
文章目录 一、前言二、系统重构的范式1.明确目标和背景2.兼容屏蔽对上层的影响3.设计灰度迁移方案3.1 灰度策略3.2 灰度过程设计3.2.1 case1 业务逻辑变更3.2.2 case2 底层数据变更(数据平滑迁移)3.2.3 case3 在途新旧流程兼容3.2.4 case4 接口变更3.2.5…...
代码随想录-训练营-day17
235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode) /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/class S…...
C++,STL,【目录篇】
文章目录 一、简介二、内容提纲第一部分:STL 概述第二部分:STL 容器第三部分:STL 迭代器第四部分:STL 算法第五部分:STL 函数对象第六部分:STL 高级主题第七部分:STL 实战应用 三、写作风格四、…...
《数据可视化新高度:Graphy的AI协作变革》
在数据洪流奔涌的时代,企业面临的挑战不再仅仅是数据的收集,更在于如何高效地将数据转化为洞察,助力决策。Graphy作为一款前沿的数据可视化工具,凭借AI赋能的团队协作功能,为企业打开了数据协作新局面,重新…...
abc 390 D(暴搜 复杂度用 bell数 证明 n 的集合的划分方法的数目)
D题意: 将 长度为 N 的数组 划分为集合 有多少种不同的 异或和 这道题做出来和bell 数没什么关系,如果要证明复杂度那么就需要bell 数 #include <bits/stdc.h> using namespace std; typedef pair<int, int> PII; #define int long long i…...
AJAX综合案例——图书管理
黑马程序员视频地址: AJAX-Day02-10.案例_图书管理AJAX-Day02-10.案例_图书管理_总结_V1.0是黑马程序员前端AJAX入门到实战全套教程,包含学前端框架必会的(ajaxnode.jswebpackgit),一套全覆盖的第25集视频,…...
计算机网络 笔记 网络层 3
IPv6 IPv6 是互联网协议第 6 版(Internet Protocol Version 6)的缩写,它是下一代互联网协议,旨在解决 IPv4 面临的一些问题,以下是关于 IPv6 的详细介绍: 产生背景: 随着互联网的迅速发展&…...
Web服务器启动难题:Spring Boot框架下的异常处理解析
摘要 在尝试启动Web服务器时遇到了无法启动的问题,具体错误为org.springframework.boot.web.server.WebServerException。这一异常表明Spring Boot框架在初始化Web服务器过程中出现了故障。通常此类问题源于配置文件错误、端口冲突或依赖项缺失等。排查时应首先检查…...
在LINUX上安装英伟达CUDA Toolkit
下载安装包 wget https://developer.download.nvidia.com/compute/cuda/12.8.0/local_installers/cuda-repo-rhel8-12-8-local-12.8.0_570.86.10-1.x86_64.rpm 安装RPM包 sudo rpm -i cuda-repo-rhel8-12-8-local-12.8.0_570.86.10-1.x86_64.rpm sudo dnf clean all sudo dnf…...
计算机视觉和图像处理
计算机视觉与图像处理的最新进展 随着人工智能技术的飞速发展,计算机视觉和图像处理作为其中的重要分支,正逐步成为推动科技进步和产业升级的关键力量。 一、计算机视觉的最新进展 计算机视觉,作为人工智能的重要分支,主要研究如…...
Spring Boot 日志:项目的“行车记录仪”
一、什么是Spring Boot日志 (一)日志引入 在正式介绍日志之前,我们先来看看上篇文章中(Spring Boot 配置文件)中的验证码功能的一个代码片段: 这是一段校验用户输入的验证码是否正确的后端代码,…...
ComfyUI中For Loop的使用
研究了半天,终于弄明白了如何使用For Loop。 1、在For中节点,必须有输出连接到For Loop End的initial_value点,才能确保节点执行完毕后才 进入下一轮循环,否则,可能导致节点没执行完,就进入下一个循环了。…...
网站快速收录:利用网站导航优化用户体验
本文转自:百万收录网 原文链接:https://www.baiwanshoulu.com/44.html 网站快速收录与用户体验的提升密切相关,而网站导航作为用户访问网站的“指南针”,其优化对于实现这一目标至关重要。以下是一些利用网站导航优化用户体验&am…...
FLTK - FLTK1.4.1 - 搭建模板,将FLTK自带的实现搬过来做实验
文章目录 FLTK - FLTK1.4.1 - 搭建模板,将FLTK自带的实现搬过来做实验概述笔记my_fltk_test.cppfltk_test.hfltk_test.cxx用adjuster工程试了一下,好使。END FLTK - FLTK1.4.1 - 搭建模板,将FLTK自带的实现搬过来做实验 概述 用fluid搭建UI…...
c#aot做跨平台动态库
c#aot技术,很多人都觉得是垃圾,没有用,其实还是很有用的。.net发展这么多年,有很多很好的功能,你可以把这些功能做成动态库供rust调用,供c/c调用。你还真别看不起这些功能,当你需要,…...
使用Pygame制作“打砖块”游戏
1. 前言 打砖块(Breakout / Arkanoid) 是一款经典街机游戏,玩家控制一个可左右移动的挡板,接住并反弹球,击碎屏幕上方的砖块。随着砖块被击碎,不仅能获得分数,还可以体验到不断加速或复杂的反弹…...
Autosar-以太网是怎么运行的?(原理部分)
写在前面: 入行一段时间了,基于个人理解整理一些东西,如有错误,欢迎各位大佬评论区指正!!! 1.TCP/IP协议详解 TCP/IP协议包含了一系列的协议,也叫TCP/IP协议族(TCP/IP P…...
小程序-基础加强-自定义组件
前言 这次讲自定义组件 1. 准备今天要用到的项目 2. 初步创建并使用自定义组件 这样就成功在home中引入了test组件 在json中引用了这个组件才能用这个组件 现在我们来实现全局引用组件 在app.json这样使用就可以了 3. 自定义组件的样式 发现页面里面的文本和组件里面的文…...
线程池以及在QT中的接口使用
文章目录 前言线程池架构组成**一、任务队列(Task Queue)****二、工作线程组(Worker Threads)****三、管理者线程(Manager Thread)** 系统协作流程图解 一、QRunnable二、QThreadPool三、线程池的应用场景W…...
Cubemx文件系统挂载多设备
cubumx版本:6.13.0 芯片:STM32F407VET6 在上一篇文章中介绍了Cubemx的FATFS和SD卡的配置,由于SD卡使用的是SDIO通讯,因此具体驱动不需要自己实现,Cubemx中就可以直接配置然后生成SDIO的驱动,并将SD卡驱动和…...
NeetCode刷题第19天(2025.1.31)
文章目录 099 Maximum Product Subarray 最大乘积子数组100 Word Break 断字101 Longest Increasing Subsequence 最长递增的子序列102 Maximum Product Subarray 最大乘积子数组103 Partition Equal Subset Sum 分区等于子集和104 Unique Paths 唯一路径105 Longest Common Su…...
网站快速收录:如何设置robots.txt文件?
本文转自:百万收录网 原文链接:https://www.baiwanshoulu.com/34.html 为了网站快速收录而合理设置robots.txt文件,需要遵循一定的规则和最佳实践。robots.txt文件是一个纯文本文件,它告诉搜索引擎爬虫哪些页面可以访问ÿ…...
(超实用教程)利用MSF制作exe程序木马
msfvenom 是攻击载荷(payload)生成器 格式: msfvenom -p windows/meterpreter/reverse_tcp LHOST192.168.110.32 LPORT4456 -f exe -o payload1.exe -p:指定需要使用的payload -f:指定输出格式 -o:保…...
Spring Boot + Facade Pattern : 通过统一接口简化多模块业务
文章目录 Pre概述在编程中,外观模式是如何工作的?外观设计模式 UML 类图外观类和子系统的关系优点案例外观模式在复杂业务中的应用实战运用1. 项目搭建与基础配置2. 构建子系统组件航班服务酒店服务旅游套餐服务 3. 创建外观类4. 在 Controller 中使用外…...
4 [危机13小时追踪一场GitHub投毒事件]
事件概要 自北京时间 2024.12.4 晚间6点起, GitHub 上不断出现“幽灵仓库”,仓库中没有任何代码,只有诱导性的病毒文件。当天,他们成为了 GitHub 上 star 增速最快的仓库。超过 180 个虚假僵尸账户正在传播病毒,等待不…...
Java基础——分层解耦——IOC和DI入门
目录 三层架构 Controller Service Dao 编辑 调用过程 面向接口编程 分层解耦 耦合 内聚 软件设计原则 控制反转 依赖注入 Bean对象 如何将类产生的对象交给IOC容器管理? 容器怎样才能提供依赖的bean对象呢? 三层架构 Controller 控制…...
10 Flink CDC
10 Flink CDC 1. CDC是什么2. CDC 的种类3. 传统CDC与Flink CDC对比4. Flink-CDC 案例5. Flink SQL 方式的案例 1. CDC是什么 CDC 是 Change Data Capture(变更数据获取)的简称。核心思想是,监测并捕获数据库的变动(包括数据或数…...
F. Greetings
题目链接:Problem - F - Codeforces 题目大意:给你n个线段, 求有多少对(两个)线段满足完全覆盖, 例如: 设一个线段有a,b两点, 满足 ai < aj < bj < bi (i,j为每个线段的下…...
深度学习练手小例子——cifar10数据集分类问题
CIFAR-10 是一个经典的计算机视觉数据集,广泛用于图像分类任务。它包含 10 个类别的 60,000 张彩色图像,每张图像的大小是 32x32 像素。数据集被分为 50,000 张训练图像和 10,000 张测试图像。每个类别包含 6,000 张图像,具体类别包括&#x…...
Sqoop源码修改:增加落地HDFS文件数与MapTask数量一致性检查
个人博客地址:Sqoop源码修改:增加落地HDFS文件数与MapTask数量一致性检查 | 一张假钞的真实世界 本篇是对记录一次Sqoop从MySQL导入数据到Hive问题的排查经过的补充。 Sqoop 命令通过 bin 下面的脚本调用,调用如下: exec ${HAD…...
FastAPI + GraphQL + SQLAlchemy 实现博客系统
本文将详细介绍如何使用 FastAPI、GraphQL(Strawberry)和 SQLAlchemy 实现一个带有认证功能的博客系统。 技术栈 FastAPI:高性能的 Python Web 框架Strawberry:Python GraphQL 库SQLAlchemy:Python ORM 框架JWT&…...
AI编程:如何编写提示词
这是小卷对AI编程工具学习的第2篇文章,今天讲讲如何编写AI编程的提示词,并结合实际功能需求案例来进行开发 1.编写提示词的技巧 好的提示词应该是:目标清晰明确,具有针对性,能引导模型理解问题 下面是两条提示词的对…...
【LLM-agent】(task5)构建哲学家多智能体
note 通过编排动作设置哲学家智能体的"示例任务",目的是让 Agent 更好地理解如何回答问题。主要包括设置示例问题、定义思考过程、应用到所有哲学家。建立了一个"先思考,后总结"的回答模式,这种方式相当于给AI提供了一个…...
31. 下一个排列
参考题解:https://leetcode.cn/problems/next-permutation/solutions/80560/xia-yi-ge-pai-lie-suan-fa-xiang-jie-si-lu-tui-dao- 找到下一个排列,即找到下一个大于当前数的更大的数。 当没有比当前更大的数的时候,那么就返回最小的数&…...
牛客周赛 Round 78
题目目录 A-时间表查询!解题思路参考代码 B-一起做很甜的梦!解题思路参考代码 C-翻之解题思路参考代码 D-乘之解题思路参考代码 E-在树上游玩解题思路参考代码 A-时间表查询! \hspace{15pt} 今天是2025年1月25日,今年的六场牛客寒…...
100.1 AI量化面试题:解释夏普比率(Sharpe Ratio)的计算方法及其在投资组合管理中的应用,并说明其局限性
目录 0. 承前1. 夏普比率的基本概念1.1 定义与计算方法1.2 实际计算示例 2. 在投资组合管理中的应用2.1 投资组合选择2.2 投资组合优化 3. 夏普比率的局限性3.1 统计假设的限制3.2 实践中的问题 4. 改进方案4.1 替代指标4.2 实践建议 5. 回答话术 0. 承前 如果想更加全面清晰地…...
jEasyUI 转换 HTML 表格为数据网格
jEasyUI 转换 HTML 表格为数据网格 引言 随着互联网技术的飞速发展,前端框架和库的应用越来越广泛。jEasyUI 是一款功能强大的 jQuery UI 扩展库,它提供了丰富的 UI 组件,其中数据网格(DataGrid)是 jEasyUI 中一个非常重要的组件。本文将详细介绍如何使用 jEasyUI 将一个…...
好用的翻译工具
最近看到个好用的翻译工具,叫沉浸式翻译 沉浸式翻译 - 双语对照网页翻译插件 | PDF翻译 | 视频字幕翻译 我下载的是谷歌插件 点击下载插件会跳转到使用文档,跟着一步步操作即可 翻译的效果,我这里用的是免费版的,如果需要加强&…...
Selenium 使用指南:从入门到精通
Selenium 使用指南:从入门到精通 Selenium 是一个用于自动化 Web 浏览器操作的强大工具,广泛应用于自动化测试和 Web 数据爬取中。本文将带你从入门到精通地掌握 Selenium,涵盖其基本操作、常用用法以及一个完整的图片爬取示例。 1. 环境配…...
字节iOS面试经验分享:HTTP与网络编程
字节iOS面试经验分享:HTTP与网络编程 🌟 嗨,我是LucianaiB! 🌍 总有人间一两风,填我十万八千梦。 🚀 路漫漫其修远兮,吾将上下而求索。 目录 字节iOS面试经验分享:HTT…...
10.7 LangChain Models深度解析:解锁大模型集成与调优的全景攻略
LangChain Models深度解析:解锁大模型集成与调优的全景攻略 关键词: LangChain Models模块、大模型集成、LLM调用优化、多模型管理、本地模型部署 一、Models模块的定位:大模型应用的“中央调度器” 传统开发的痛点: 碎片化集成:每个模型需单独编写适配代码性能黑洞:缺…...
本地部署 DeepSeek-R1:简单易上手,AI 随时可用!
🎯 先看看本地部署的运行效果 为了测试本地部署的 DeepSeek-R1 是否真的够强,我们随便问了一道经典的“鸡兔同笼”问题,考察它的推理能力。 📌 问题示例: 笼子里有鸡和兔,总共有 35 只头,94 只…...
cf集合***
当周cf集合,我也不知道是不是当周的了,麻了,下下周争取写到e补f C. Kevin and Puzzle(999) 题解:一眼动态规划,但是具体这个状态应该如何传递呢? 关键点:撒谎的人不相…...
【机器学习理论】生成模型和判别模型
生成模型和判别模型是机器学习中两种不同的建模方式。生成模型关注的是联合概率分布 P ( X , Y ) P(X, Y) P(X,Y),即同时考虑数据 X X X和标签 Y Y Y的关系;判别模型则直接学习条件概率 P ( Y ∣ X ) P(Y|X) P(Y∣X)或决策边界。 生成模型 生成模型的目…...
图漾相机——C++语言属性设置
文章目录 前言1.SDK API功能介绍1.1 Device组件下的API测试1.1.1 相机工作模式设置(TY_TRIGGER_PARAM_EX)1.1.2 TY_INT_FRAME_PER_TRIGGER1.1.3 TY_INT_PACKET_DELAY1.1.4 TY_INT_PACKET_SIZE1.1.5 TY_BOOL_GVSP_RESEND1.1.6 TY_BOOL_TRIGGER_OUT_IO1.1.…...
如何在Windows、Linux和macOS上安装Rust并完成Hello World
如何在Windows、Linux和macOS上安装Rust并完成Hello World 如果你刚刚开始学习Rust,第一步就是安装Rust并运行你的第一个程序!本文将详细介绍如何在Windows、Linux和macOS上安装Rust,并编写一个简单的“Hello, World!”程序。 1. 安装Rust …...
基于VMware的ubuntu与vscode建立ssh连接
1.首先安装openssh服务 sudo apt update sudo apt install openssh-server -y 2.启动并检查ssh服务状态 到这里可以按q退出 之后输入命令 : ip a 红色挡住的部分就是我们要的地址,这里就不展示了哈 3.配置vscode 打开vscode 搜索并安装:…...
Redis 集合(Set)
Redis 集合(Set) 引言 Redis 是一款高性能的键值存储数据库,其支持多种数据结构,其中包括集合(Set)。集合是一个无序的、元素唯一的集合数据结构,它非常适合存储需要去重和高效检索的数据。本文将详细介绍 Redis 集合的数据结构、操作方法以及应用场景。 Redis 集合数…...
(笔记+作业)书生大模型实战营春节卷王班---L0G2000 Python 基础知识
学员闯关手册:https://aicarrier.feishu.cn/wiki/QtJnweAW1iFl8LkoMKGcsUS9nld 课程视频:https://www.bilibili.com/video/BV13U1VYmEUr/ 课程文档:https://github.com/InternLM/Tutorial/tree/camp4/docs/L0/Python 关卡作业:htt…...
stm32硬件实现与w25qxx通信
使用的型号为stm32f103c8t6与w25q64。 STM32CubeMX配置与引脚衔接 根据stm32f103c8t6引脚手册,采用B12-B15四个引脚与W25Q64连接,实现SPI通信。 W25Q64SCK(CLK)PB13MOSI(DI)PB15MISO(DO)PB14CS(…...