6.分布式数据库与分库分表
目录
一、分库分表核心概念
• 核心目标:突破单库性能瓶颈,应对海量数据与高并发 • 垂直拆分:按业务模块拆分(用户库、订单库、商品库) • 水平拆分:单表数据分片(用户ID取模、时间范围分片)
二、分片策略与避坑指南
• 分片键选择:高基数字段(用户ID)、业务关联性、数据均衡性 • 分片算法:哈希取模(均匀分布)、一致性哈希(扩容友好)、范围分片(冷热分离) • 避坑要点:禁止无分片键查询、避免后期改分片键、分片数预留扩容空间
三、ShardingSphere 企业级实战
• 技术选型:Sharding-JDBC(轻量级) vs Sharding-Proxy(多语言支持) • Spring Boot整合:分片规则配置、读写分离、分布式主键(Snowflake) • 高阶功能:数据脱敏、柔性事务(BASE)、多租户隔离
四、分布式事务解决方案
• 刚性事务:Seata AT模式(全局锁+反向SQL回滚) • 柔性事务:TCC(Try-Confirm-Cancel)、本地消息表(最终一致) • 大厂实践:支付宝异步通知补偿、美团分布式事务中间件
五、数据迁移与动态扩容
• 全量迁移:DataX工具、停机窗口控制 • 增量同步:Canal监听binlog、双写过渡校验 • 在线扩容:虚拟节点动态迁移、用户无感知切换
六、生产监控与调优
• 核心指标:连接池水位、慢SQL率、分片路由耗时 • 调优手段:避免跨分片查询、异步化聚合统计、热点数据二级分片 • 工具链:Prometheus监控、SkyWalking链路追踪
七、大厂真实案例
• 电商订单库:用户ID取模分片 + 冷热数据归档HBase • 社交Feed流:用户ID+时间联合分片 + 读写分离 • 物流轨迹库:地理位置GeoHash分片 + Elasticsearch检索
八、高频面试题精选
• 分库分表后如何高效分页? • ShardingSphere如何解析SQL路由? • 分片键数据倾斜的应急方案? • 如何设计全局唯一ID(雪花算法 vs 号段模式)?
一、分库分表核心概念
核心目标
• 突破单库性能瓶颈: • 连接数限制:单库连接池上限(如MySQL默认151连接),高并发下易阻塞。 • 磁盘IO瓶颈:单机硬盘读写速率如SATA SSD 约500MB/s)。 • 锁竞争严重:高频更新场景(如秒杀库存)导致行锁/表锁冲突。
• 应对海量数据与高并发: • 数据量爆炸:单表数据超千万级后,B+树层级增加,查询性能指数级下降。 • 业务解耦需求:微服务架构下,不同业务模块需独立扩缩容(如用户服务与订单服务)。
垂直拆分
• 定义:按业务功能模块拆分数据库,每个库独立部署。 • 典型拆分方案: ◦ 用户库:存储用户信息、登录凭证。 ◦ 订单库:订单记录、支付流水。 ◦ 商品库:商品详情、库存信息。
• 优势: • 资源隔离:CPU、内存、磁盘资源按业务独立分配,避免互相影响。 • 专业优化:针对业务特性定制索引和存储引擎(如订单库用InnoDB,日志库用TokuDB)。
• 痛点与解决方案: • 跨库事务:避免跨库事务,改用最终一致性(如本地消息表)。 • JOIN操作难:通过业务层多次查询或数据冗余(如订单表冗余用户昵称)。
水平拆分
• 定义:将单表数据按分片规则(如用户ID、时间)拆分到多个库/表。 • 典型分片方案: ◦ 用户ID取模:分片号 = user_id % 分片总数
(均匀分布,用户查询精准路由)。 ◦ 时间范围分片:按月/年拆分(如order_202301
, order_202302
),天然支持冷热数据分离。
• 分片键选择原则: • 高基数:分片键值足够分散(如用户ID而非性别)。 • 业务相关性:高频查询条件字段(如订单查询常用user_id
和create_time
)。
• 挑战与应对: • 跨分片查询复杂:避免无分片键查询,改用ES聚合或业务层分批查询。 • 扩容成本高:分片数预分配为2的N次方(如16→32),用一致性哈希减少数据迁移量。
常见问题(QA)
Q1:什么时候该用垂直拆分,什么时候用水平拆分? • 垂直拆分优先:业务模块清晰、数据增长可控(如初期快速验证阶段)。 • 水平拆分必选:单表数据超千万且持续增长(如电商订单、社交动态)。
Q2:分片键选错如何补救? • 数据迁移:新建分片键正确的表,通过DataX/Spark迁移数据,逐步切换读写流量。 • 双写过渡:新旧分片键同时写入,直到旧数据淘汰。
Q3:如何保证跨库事务一致性? • 强一致场景:用Seata AT模式(性能要求不高时)。 • 最终一致场景:消息队列异步补偿(如订单创建后发MQ通知库存服务)。
大厂案例
-
支付宝用户库垂直拆分: • 拆分用户基础信息库、账户余额库、交易记录库。 • 结果:数据库负载下降60%,故障隔离能力提升。
-
淘宝订单表水平分片: • 按
user_id % 1024
分成1024张表,单表数据控制在500万以内。 • 结果:订单查询响应时间从2s降至200ms。
二、分片策略与避坑指南
分片键选择
1. 高基数字段优先
• 定义:分片键的取值可能性足够多(如用户ID、订单号)。 • 案例: • 错误示范:性别字段(基数2)作为分片键 → 数据集中在2个分片,无法扩展。 • 正确方案:用户ID(百万级基数)哈希分片 → 数据均匀分布。
2. 业务强关联性
• 原则:分片键必须是业务高频查询条件(避免全库扫描)。 • 场景: • 订单查询条件:user_id
(用户查订单)和 create_time
(运营统计)。 • 联合分片键:user_id + create_time
(兼顾查询与分布)。
3. 数据均衡性保障
• 算法优化:
// 用户ID哈希后取模(简单均匀分片) int shardNo = Math.abs(userId.hashCode()) % shardCount; // 增加随机因子防止热点 int shardNo = (userId.hashCode() + ThreadLocalRandom.current().nextInt(100)) % shardCount;
• 监控手段:通过ShardingSphere的 SHOW SHARDING TABLE RULES
检查各分片数据量。
分片算法
1. 哈希取模
• 原理:分片号 = hash(key) % 分片总数
• 优势:数据均匀分布,查询直接定位分片。 • 缺陷: • 扩容困难:分片数变化需全量数据迁移。 • 范围查询弱:如时间范围查询需遍历所有分片。 • 适用场景:用户表、订单表等无范围查询需求的数据。
2. 一致性哈希
• 原理:构建哈希环,节点虚拟化分散在环上,数据哈希值顺时针找到最近节点。 • 优势:扩容时仅迁移相邻节点数据,影响小。 • 生产配置(Java示例):
// 使用TreeMap实现一致性哈希环 TreeMap<Integer, String> hashRing = new TreeMap<>(); for (int i = 0; i < virtualNodes; i++) { for (String node : nodes) { hashRing.put(MurmurHash.hash(node + "#" + i), node); } }
• 适用场景:需要频繁扩容的社交动态、评论系统。
3. 范围分片
• 原理:按区间划分(如时间、ID范围)。 • 优势: • 冷热分离:历史数据归档低成本存储(如OSS)。 • 分页友好:按时间排序查询天然有序。 • 缺陷:易产生数据倾斜(如某时间段订单暴涨)。 • 案例:物流轨迹表按 YYYYMM
分片,每月自动创建新表。
避坑要点
1. 禁止无分片键查询
• 风险:全库全表扫描 → 性能雪崩。 • 解决方案: • 代码强制校验:DAO层拦截无分片键查询请求。 • 中间件拦截:ShardingSphere配置 allowRangeQueryWithoutShardingKey=false
。 • 大厂实践:抖音订单系统要求所有查询必须携带 user_id
或 order_id
。
2. 避免后期修改分片键
• 风险:数据迁移成本高,需停服或灰度切换。 • 应对策略: • 预分片设计:初期采用联合分片键(如 user_id + 预留字段
- 双写过渡:新旧分片键同步写入,逐步迁移。 • 案例:美团外卖订单表从 order_id
分片改为 rider_id + order_id
分片,耗时3个月。
3. 分片数预留扩容空间
• 经验公式:预估3年数据量,分片数按2的N次方设计(如16 → 32)。 • 弹性方案: • 虚拟分片:物理分片数少于逻辑分片数,动态调整映射关系。 • 自动迁移:阿里云DRDS支持在线分片数倍增,数据自动均衡。 • 监控指标:单分片数据量超过500万时触发报警。
高频面试题
-
分片键选择不合理导致数据倾斜怎么办? • 答案:临时方案:写入时加随机后缀;长期方案:改用一致性哈希重新分片。
-
如何实现跨分片分页查询? • 答案:业务层排序(如ES聚合结果)或折衷方案(禁止深度分页)。
-
ShardingSphere分片算法如何自定义? • 答案:实现
StandardShardingAlgorithm
接口,注入分片逻辑。
生产级代码片段:
// ShardingSphere 分片规则配置(按user_id哈希分片) shardingRuleConfig.getTableRuleConfigs().add( new TableRuleConfiguration("user", "ds${0..1_${0..15}") .setDatabaseShardingStrategyConfig( new StandardShardingStrategyConfiguration("user_id", "dbHashMod") ) .setTableShardingStrategyConfig( new StandardShardingStrategyConfiguration("user_id", "tableHashMod") ) ); // 自定义分片算法(哈希取模) public final class HashModShardingAlgorithm implements StandardShardingAlgorithm<Long> { @Override public String doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) { // 实现分片逻辑 } }
三、ShardingSphere 企业级实战
技术选型
• Sharding-JDBC(轻量级): • 定位:Java应用的JDBC驱动层扩展,透明化分库分表 • 优势:无代理层性能损耗,与Spring Boot深度整合 • 适用场景:中小团队快速落地分库分表(如电商订单分片) • Sharding-Proxy(支持): • 定位:独立部署的数据库代理,兼容MySQL/PostgreSQL协议 • 优势:支持多语言(PHP/Python可视化(如阿里云DMS) • 适用场景:跨技术栈团队(如Java+Go混合开发) • 选型建议: • 单语言技术栈优先Sharding-JDBC(性能最优) • 需运维管控或混合语言选Sharding-Proxy(牺牲10%~15%性能)
Spring Boot整合
1. 分片规则配置(YAML示例)
spring: shardingsphere: datasource: names: ds0, ds1 ds0: url: jdbc:mysql://db0:3306/order username: root password: 123456 ds1: url: jdbc:mysql://db1:3306/order rules: sharding: tables: order: actualDataNodes: ds$->{0..1}.order_$->{0..15} # 2库x16表 databaseStrategy: standard: shardingColumn: user_id shardingAlgorithmName: db-hash-mod tableStrategy: standard: shardingColumn: order_id shardingAlgorithmName: table-hash-mod shardingAlgorithms: db-hash-mod: type: HASH_MOD props: sharding-count: 2 table-hash-mod: type: HASH_MOD props: sharding-count: 16
2. 读写分离配置
spring: shardingsphere: rules: replica-query: dataSources: pr_ds: primaryDataSourceName: ds-primary replicaDataSourceNames: ds-replica1, ds-replica2 loadBalancerName: round-robin loadBalancers: round-robin: type: ROUND_ROBIN
3. 分布式主键生成
// flake算法(防止时钟回拨) @Bean public KeyGenerateAlgorithm keyGenerator() { return new SnowflakeKeyGenerateAlgorithm() .setProps(Collections.singletonMap("max-tolerate-time-difference-milliseconds", "60000")); }
高阶功能
1. 数据
• 场景:手机号、身份证号等敏感信息加密存储 • 实现:
spring: shardingsphere: rules: encrypt: encryptors: mobile_encryptor: type: AES props: aes-key-value: 123456 tables: user: columns: phone: cipherColumn: phone_cipher encryptorName: mobile_encryptor
• 查询处理:自动加解密,业务代码无感知
2. 柔性事务(BASE)
• 本地消息表实现:
-
业务事务提交时,写入本地消息表
-
定时任务扫描并发送消息到MQ
-
消费者处理成功后更新消息状态 • ShardingSphere集成:
spring: shardingsphere: rules: transaction: defaultType: BASE providerType: Local
3. 多租户隔离
• 场景:SaaS系统按租户分库(如企业ID分片) • 配置:
tables: report: actualDataNodes: ds_${0..9}.report_${0..9} databaseStrategy: standard: shardingColumn: tenant_id shardingAlgorithmName: tenant-mod shardingAlgorithms: tenant-mod: type: MOD props: sharding-count: 10
• 数据隔离:通过HintManager
强制路由租户上下文
HintManager.getInstance().setDatabaseShardingValue(tenantId);
生产经验
-
分片算法预热: • 启动时预加载分片路由规则,避免首次查询延迟
-
监控告警: • 通过
ShardingSphere-UI
监控慢查询与分片负载 -
灰度发布: • 新旧分片规则并存,通过AB测试逐步切流
四、分布式事务解决方案
刚性事务:Seata AT模式
核心原理
• 全局锁机制: • 事务协调器(TC)在事务开始时注册全局锁,锁定涉及的行记录。 • 其他事务修改同一数据时,需等待锁释放(默认锁超时时间30秒)。 • 反向SQL回滚: • 提交阶段:各分支事务提交本地事务,释放全局锁。 • 回滚阶段:生成反向SQL(如INSERT→DELETE)撤销已提交的操作。
Spring Boot整合配置
# application.yml seata: enabled: true application-id: order-service tx-service-group: my-tx-group registry: type: nacos nacos: server-addr: 127.0.0.1:8848 config: type: nacos nacos: server-addr: 127.0.0.1:8848
@GlobalTransactional // 开启全局事务 public void placeOrder() { orderService.create(); stockService.deduct(); }
适用场景与限制
• 适用场景:短事务(执行时间<1秒)、简单业务逻辑(如扣减库存+生成订单)。 • 限制: • 不支持嵌套事务。 • 高并发场景下全局锁可能成为性能瓶颈。
柔性事务:TCC与本地消息表
1. TCC(Try-Confirm-Cancel)
• 三阶段流程:
阶段 | 动作 | 案例(转账业务) |
---|---|---|
Try | 资源预留(冻结账户金额) | account.freeze(100元) |
Confirm | 确认操作(实际扣款) | account.debit(100元) |
Cancel | 取消预留(解冻金额) | account.unfreeze(100元) |
• Java实现示例:
@Transactional public boolean tryTransfer(String from, String to, BigDecimal amount) { // 冻结转出账户资金 accountService.freeze(from, amount); // 预增转入账户可用额度 accountService.prepareCredit(to, amount); return true; } @Transactional public boolean confirmTransfer(String txId) { // 实际扣减转出账户 accountService.debit(txId); // 实际增加转入账户 accountService.credit(txId); return true; } @Transactional public boolean cancelTransfer(String txId) { // 解冻转出账户资金 accountService.unfreeze(txId); // 撤销转入账户预增 accountService.cancelCredit(txId); return true; }
2. 本地消息表(最终一致性)
• 实现流程:
-
业务事务提交时,向本地消息表插入事件记录(与业务操作同一事务)。
-
定时任务扫描未处理事件,发送到消息队列(如RocketMQ)。
-
消费者处理成功后更新事件状态。
• Spring Boot集成:
@Transactional public void createOrder(Order order) { orderRepository.save(order); // 写入本地消息表(同一事务) eventRepository.save(new Event("order_created", order.getId())); } @Scheduled(fixedDelay = 5000) public void processEvents() { List<Event> events = eventRepository.findByStatus(EventStatus.PENDING); events.forEach(event -> { try { rocketMQTemplate.send("order_topic", event.getPayload()); event.setStatus(EventStatus.SUCCESS); } catch (Exception e) { event.setStatus(EventStatus.FAILED } eventRepository.save(event); }); }
大厂实践
1. 支付宝异步通知补偿
• 场景:支付成功后通知商户系统,确保最终到达。 • 实现: • 支付成功时写入本地消息表。 • 异步重试通知(1s、10s、1m、10m、1h间隔),最多重试24小时。 • 商户系统幂等处理(通过支付流水号去重)。
2. 美团分布式事务中间件
• 架构设计: • 事务协调器:基于Raft协议实现高可用。 • TCC适配层:自动生成Try/Confirm/Cancel接口模板。 • 监控看板:实时追踪事务状态,支持手动冲正。 • 核心指标: • 事务成功率:99.995%(依赖自动补偿机制)。 • 平均处理耗时:Confirm阶段<50ms,Cancel阶段<100ms。
选型决策树
场景特征 | 推荐方案 | 理由 |
---|---|---|
短事务、强一致性需求 | Seata AT模式 | 简单易用,无需业务改造 |
长事务、高并发(如金融转账) | TCC | 细粒度控制,避免资源长期锁定 |
允许延迟(如通知类业务) | 本地消息表 | 吞吐量高,对业务侵入性低 |
跨多语言服务(如Java+Go) | 消息队列+本地事务 | 无中心化依赖,兼容异构系统 |
五、数据迁移与动态扩容
全量迁移
1. DataX工具实战
• 核心能力: • 支持MySQL、Oracle、HDFS等20+数据源异构迁移 • 分布式架构(Job+Task)提升吞吐量(单机可达500MB/s) • 断点续传、脏数据跳过机制保障稳定性 • 迁移流程:
-
数据探查:统计表大小、主键分布(避免大事务超时)
-
作业配置:
{ "job": { "content": [{ "reader": { "name": "mysqlreader", "parameter": { "username": "root", "password": "123456", "column": ["id", "user_id", "amount"], "splitPk": "id", // 按主键分片读取 "connection": [{ "table": ["orders"], "jdbcUrl": ["jdbc:mysql://old-db:3306/order"] }] } }, "writer": { "name": "mysqlwriter", "parameter": { "username": "root", "password": "123456", "column": ["id", "user_id", "amount"], "connection": [{ "jdbcUrl": "jdbc:mysql://new-db:3306/order", "table": ["orders"] }] } } }] } }
-
执行与监控: ◦ 日志实时查看: -f datax.log
◦ 进度监控:
curl http://datax-server:port/job/metrics`
2. 停机窗口控制
• 步骤:
-
停写:关闭业务写入入口(如Nginx流量拦截)
-
增量追赶:通过Binlog同步最后N分钟数据
-
切换验证:对比新旧库数据checksum(
mysqldbcompare
工具) -
恢复写入:开启新库旧库下线 • 时间估算:
• 数据量100GB,网络带宽1Gbps → 全量迁移约15分钟 • 增量追赶(Binlog延迟) → 5~10分钟 • 总停机时间 ≈ 30分钟
增量同步
1. Canal监听Binlog
• 架构原理: • Canal Server伪装为MySQL从库,接收主库Binlog • MQ(Kafka/RocketMQ)解耦生产与消费速率 • Java客户端消费消息,写入目标库(如ES、分片后的MySQL) • Spring Boot整合:
canal: server: 192.168.1.100:11111 destination: example filter: .*\\..*
@CanalEventListener public class OrderEventListener { @ListenPoint(table = "orders") public void onEvent(EventType eventType, RowData rowData) { if (eventType == EventType.INSERT) { Order order = convertRowToOrder(rowData); orderRepository.save(order); // 写入新库 } } }
2. 双写过渡校验
• 双写策略: • 同步双写:事务内同时写入新旧库(强一致,性能低) • 异步双写:写入旧库后发MQ异步写入新库(最终一致,高吞吐) • 数据校验:
-- 新旧库数据比对(定时任务) SELECT COUNT(*) FROM old_db.orders UNION ALL SELECT COUNT(*) FROM new_db.orders; -- 差异数据修复 INSERT INTO new_db.orders SELECT * FROM old_db.orders WHERE id NOT IN (SELECT id FROM new_db.orders);
在线扩容
1. 虚拟节点动态迁移
• 一致性哈希优化: • 物理节点映射多个虚拟节点(如每个物理节点1000虚拟节点) • 扩容时新增虚拟节点,数据迁移仅影响相邻节点 • 迁移流程:
-
新节点加入:向集群注册,分配虚拟节点范围
-
数据迁移: ◦ 扫描旧节点数据,按新路由规则迁移至新节点 ◦ 迁移期间旧节点仍可读写(双写模式)
-
流量切换:更新路由配置,逐步切流至新节点
2. 用户无感知切换
• 灰度发布: • 按用户ID分流:10%流量切至新节点,观察错误率 • 按地域切流:先切非核心地区(如海外用户) • 回滚方案: • 监控新节点QPS/延迟,超阈值自动回退旧配置 • 数据双写期间保留旧节点数据,支持快速回滚
生产级Checklist
-
数据一致性验证: • 全量校验:
mysqldump
+md5sum
• 增量校验:对比新旧库Binlog位点 -
性能压测: • 模拟双写压力(如JMeter模拟200%流量) • 监控连接池等待、锁竞争指标
-
容灾演练: • 随机Kill节点,验证数据自愈能力 • 网络分区模拟(如iptables阻断节点通信)
六、生产监控与调优
核心指标
1. 连接池水位监控
• 关键指标: • 活跃连接数(active):实时处理请求的连接数 • 空闲连接数(idle):等待复用的空闲连接 • 最大等待时间(maxWait):获取连接的超时阈值(超过则抛异常) • 报警规则(Prometheus示例):
# prometheus-rules.yml - alert: HighConnectionPoolUsage expr: sum(shardingsphere_datasource_active_connections) / sum(shardingsphere_datasource_max_connections) > 0.8 for: 5m labels: severity: critical annotations: summary: "数据库连接池使用率超过80%"
• 优化手段: • 动态扩容:HikariCP的maximumPoolSize
根据QPS自动调整(需配合微服务动态配置中心) • 连接泄漏检测:Druid的removeAbandoned=true
+ 告警通知
2. 慢SQL率分析
• 采集方式: • MySQL慢查询日志: sql SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 2; -- 超过2秒的SQL记录
• ShardingSphere全链路追踪: yaml spring: shardingsphere: props: sql-show: true # 打印逻辑SQL与真实SQL
• 治理流程:
-
TOP N慢SQL定位:通过
mysqldumpslow
工具分析日志 -
执行计划分析:
EXPLAIN
查看索引使用情况 -
优化方案: ◦ 缺失索引 → 添加联合索引 ◦ 复杂JOIN → 冗余字段或拆分为多次查询
3. 分片路由耗时
• 监控项: • 路由计算耗时:ShardingSphere的sql_route_time
指标 • 跨分片查询比例:shardingsphere_routed_sql_total{type="select", is_broadcast="false"}
• 调优方案: • 强制分片键:拦截无分片键查询(ShardingSphere配置allowRangeQueryWithoutShardingKey=false
) • 本地缓存路由表:预热高频查询分片位置(如用户ID与分片映射关系)
调优手段
1. 避免跨分片查询
• 分片键强制校验:
// AOP拦截无分片键查询 @Around("execution(* com.example.repository.*.*(..))") public Object checkShardingKey(ProceedingJoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); ShardingKeyRequired annotation = signature.getMethod().getAnnotation(ShardingKeyRequired.class); if (annotation != null) { Object[] args = joinPoint.getArgs(); if (!hasShardingKey(args)) { throw new IllegalStateException("查询必须包含分片键"); } } return joinPoint.proceed(); }
• 冗余字段设计:订单表冗余user_id
,避免关联查询用户表
2. 异步化聚合统计
• 方案对比:
方案 | 优点 | 缺点 |
---|---|---|
MQ+Elasticsearch | 实时性高(秒级延迟) | 数据需同步到ES |
Flink实时计算 | 支持复杂计算(如UV统计) | 架构复杂度高 |
本地缓存+定时批处理 | 资源消耗低 | 实时性差(分钟级延迟) |
• 代码示例: |
// 订单金额统计异步化 @Async("statsThreadPool") public void asyncOrderStats(LocalDate date) { List<Order> orders = orderRepository.findByDate(date); // 直接查分片 BigDecimal total = orders.stream().map(Order::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add); statsCache.put(date, total); }
3. 热点数据二级分片
• 动态分片键: • 场景:某直播间用户评论突增导致单分片过热 • 方案:在原分片键(直播间ID)基础上追加随机后缀(如room_id:123#slot=5
) • 本地缓存:
// Caffeine缓存热点评论 Cache<String, List<Comment>> cache = Caffeine.newBuilder() .maximumSize(10_000) .expireAfterWrite(10, TimeUnit.SECONDS) // 短时间缓存降低DB压力 .build(); public List<Comment> getHotComments(String roomId) { return cache.get(roomId, key -> commentRepository.findHotComments(key)); }
工具链
1. Prometheus + Grafana监控
• 数据采集: • ShardingSphere Exporter:暴露shardingsphere_datasource_active_connections
等指标 • 自定义指标:通过Micrometer注册业务指标(如跨分片查询次数) • 看板配置:
// Grafana面板示例(分片负载均衡) { "panels": [{ "type": "graph", "title": "分片查询分布", "targets": [{ "expr": "sum(shardingsphere_routed_sql_total) by (datasource)" }] }] }
2. SkyWalking链路追踪
• 集成配置:
# skywalking-agent.config agent.service_name=order-service collector.backend_service=127.0.0.1:11800 plugin.mysql.trace_sql_parameters=true
• 链路分析: • 跨分片查询追踪:自动标记跨库查询的Span • 慢事务根因定位:分析事务链路中的慢SQL或远程调用 • 生产案例: • 美团外卖订单链路:通过SkyWalking定位到跨分片JOIN导致慢查询,优化后RT降低60%
高频面试题
-
如何快速定位慢SQL的瓶颈? • 答:SkyWalking链路追踪 +
EXPLAIN
执行计划分析,优先检查索引缺失与数据倾斜。 -
分片路由耗时过高可能是什么原因? • 答:路由规则复杂(如多分片键联合计算)、未预热路由缓存、跨分片查询过多。
-
如何设计一个高可用的监控系统? • 答:Prometheus联邦架构 + Thanos长期存储,配合Grafana多数据源聚合展示。
七、大厂真实案例
电商订单库:用户ID取模分片 + 冷热数据归档HBase
背景与挑战
• 业务场景:日订单量超千万,单表数据一年破百亿,查询性能从秒级跌至分钟级。 • 核心痛点: • 用户高频查询“我的订单”接口(强依赖user_id
)。 • 历史订单占用90%存储但访问频率低(冷热数据混杂)。
分库分表方案
-
水平分片: • 分片键:
user_id % 1024
(1024个分片,单分片控制在500万行内)。 • 路由规则:// 根据用户ID计算分片 int shardNo = Math.abs(userId.hashCode()) % 1024; String tableName = "orders_" + shardNo;
-
冷热分离: • 热数据:近3个月订单存MySQL,索引优化(
user_id + create_time
联合索引)。 • 冷数据:3个月前数据归档HBase,ROW_KEY设计为user_id|order_id
(范围扫描优化)。
技术细节
• 数据同步:Canal监听MySQL Binlog,触发冷数据迁移至HBase。 • 查询优化: • 热数据查询直接走MySQL分片。 • 冷数据查询走HBase的PrefixFilter
(user_id
前缀匹配)。
优化效果
• 查询性能:用户订单列表响应时间从12s降至200ms。 • 存储成本:HBase压缩比提升60%,存储费用降低75%。
社交Feed流:用户ID+时间联合分片 + 读写分离
业务场景
• 用户发布动态实时推送粉丝,读QPS峰值百万级。 • 单表存储用户动态,数据量日均十亿级。
分片方案
-
联合分片键: • 主分片键:
user_id % 256
(256个分片)。 • 二级分片键:create_time
按月分表(如feed_202301
)。 -
读写分离: • 写节点:主库处理发布请求,分片规则为
user_id
。 • 读节点:从库按user_id + create_time
分片,支撑粉丝Feed流拉取。
技术实现
• 动态发布:
INSERT INTO feed_{user_id%256} (content, user_id, create_time) VALUES ('Hello World', 123456, NOW());
• Feed流读取:
-- 查询用户关注列表的动态(按时间倒序) SELECT * FROM feed_* WHERE user_id IN (SELECT followed_user_id FROM follow WHERE fan_user_id = 123) ORDER BY create_time DESC LIMIT 100;
• 优化手段: ◦ 粉丝关系缓存Redis(Sorted Set存储关注列表)。 ◦ Feed流结果缓存CDN,降低DB压力。
性能提升
• 发布吞吐量:从5K TPS提升至50K TPS。 • 读延迟:Feed流加载从3s降至800ms。
物流轨迹库:地理位置GeoHash分片 + Elasticsearch检索
业务需求
• 存储全国物流轨迹点,每日新增轨迹数据十亿级。 • 需支持两类查询: • 精确查询:根据运单号查全链路轨迹。 • 区域查询:查询某地所有待派送订单。
分片方案
-
GeoHash分片: • 原理:将经纬度编码为字符串(如
wx4g0
),按前缀分片。 • 分片键:geohash.substring(0, 3)
(前3位作为分片键,256个分片)。 -
Elasticsearch辅助索引: • 空间索引(geo_point):支持半径1km内的订单搜索。 • 联合查询:
运单号
走MySQL分片,地理位置
走Elasticsearch。
技术实现
• 写入流程:
// 计算GeoHash(纬度31.23, 经度121.47) String geoHash = GeoHash.encode(31.23, 121.47, 5); // 插入MySQL分片 String table = "track_" + geoHash.substring(0, 3); jdbcTemplate.update("INSERT INTO " + table + " VALUES (?, ?, ?)", orderId, geoHash, time); // 同步到Elasticsearch esClient.index(new IndexRequest("track").id(orderId) .source(JsonUtils.toMap(new TrackPoint(orderId, geoHash, time))));
• 区域查询:
GET /track/_search { "query": { "geo_distance": { "distance": "1km", "location": "31.23,121.47" } } }
优化效果
• 精确查询:运单号查询走MySQL分片,RT<50ms。 • 区域查询:Elasticsearch百公里范围检索,RT<200ms。
八、高频面试题精选
1. 分库分表后如何高效分页?
问题分析
• 传统分页失效:LIMIT 10000, 10
需扫描并丢弃前10000行,跨分片时性能灾难。 • 解决方案: • 业务折衷: ◦ 禁止跳页(仅允许“下一页”按钮),用连续游标(如Search After
)。 sql -- 第一页 SELECT * FROM orders WHERE user_id=123 ORDER BY id LIMIT 10; -- 第二页(使用上一页最后一条ID) SELECT * FROM orders WHERE user_id=123 AND id > last_id ORDER BY id LIMIT 10;
• Elasticsearch辅助:复杂条件分页走ES,结果反查MySQL获取明细。 • 内存分页:若数据可缓存(如Redis),全量加载后内存中分页。
2. ShardingSphere如何解析SQL路由?
核心流程
-
SQL解析: • 解析引擎生成抽象语法树(AST),提取分片条件(如
user_id=123
)。 -
路由计算: • 精确路由:分片键等值查询(
user_id=123
)直接定位分片。 • 广播路由:无分片键的更新(如UPDATE config SET value=1
)全分片执行。 -
结果归并: • 跨分片查询结果在内存中排序、聚合(如
ORDER BY time DESC
)。
配置示例
rules: - !SHARDING tables: orders: actualDataNodes: ds_${0..1}.orders_${0..15} databaseStrategy: standard: shardingColumn: user_id shardingAlgorithmName: hash_mod shardingAlgorithms: hash_mod: type: HASH_MOD props: sharding-count: 2
3. 分片键数据倾斜的应急方案?
临时措施
• 虚拟节点再平衡:
// 原分片:user_id % 8 // 扩容后:(user_id.hashCode() + virtual_node) % 16 int newShard = (userId.hashCode() + slot) % 16;
• 热点数据二级分片: • 例如对热点用户(如网红)的订单按user_id + order_id
联合分片。
长期方案
• 分片键改造:联合业务高基字段(如user_id + city_code
)。 • 动态分片:根据数据分布自动调整分片映射(如一致性哈希)。
4. 如何设计全局唯一ID(雪花算法 vs 号段模式)?
方案对比
维度 | 雪花算法(Snowflake) | 号段模式(Segment) |
---|---|---|
唯一性 | 全局唯一(数据中心ID+机器ID+时间戳+序列号) | 依赖数据库唯一性保障(如自增主键) |
性能 | 本地生成,无网络开销(单机每秒百万级) | 需预取号段,DB宕机影响ID生成 |
缺点 | 时钟回拨导致ID重复(需处理NTP同步) | 号段耗尽时需访问DB,存在尖峰压力 |
适用场景 | 高并发分布式系统(如电商订单、支付流水) | 中小规模系统(如内部管理平台) |
Snowflake避坑实践
public class SnowflakeIdWorker { private long twepoch = 1288834974657L; // 起始时间戳 private long sequence = 0L; // 解决时钟回拨 public synchronized long nextId() { long timestamp = timeGen(); if (timestamp < lastTimestamp) { long offset = lastTimestamp - timestamp; if (offset <= 5) { // 允许回拨5ms内等待 Thread.sleep(offset << 1); timestamp = timeGen(); } else { throw new RuntimeException("时钟回拨超过5ms"); } } // ...生成ID逻辑 } }
总结:本章涵盖的案例与面试题均来自阿里、美团、字节等一线大厂真题,掌握这些内容可从容应对95%的分库分表相关技术挑战。
相关文章:
6.分布式数据库与分库分表
目录 一、分库分表核心概念 • 核心目标:突破单库性能瓶颈,应对海量数据与高并发 • 垂直拆分:按业务模块拆分(用户库、订单库、商品库) • 水平拆分:单表数据分片(用户ID取模…...
基于javaweb的SSM+Maven小区失物招领系统设计与实现(源码+文档+部署讲解)
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...
Kubernetes finalize | namespace卡Terminatingfinalizers删除失败
目录 1、为什么会卡住?2、强制删除卡住的 Namespace:操作步骤1:导出当前 namespace 信息2:启动代理(另一个终端)以便使用 Kubernetes API Server3:使用 curl 强制删除 finalize 3、进阶排查&…...
Java数组
目录 一、定义 二、使用 2.1遍历数组 2.2获取数组长度 三、Arrays类 3.1数组填充 3.2数组排序 3.3数组转为字符串 3.4数组比较 3.5二分搜索 3.6数组复制 二维数组 一、定义 数组表示一个相同类型元素的集合 对于一个数组,可以有以下几种定义方法 int[…...
高级java每日一道面试题-2025年4月22日-基础篇[反射篇]-如何通过反射创建一个对象实例?
如果有遗漏,评论区告诉我进行补充 面试官: 如何通过反射创建一个对象实例? 我回答: 在Java中,反射(Reflection)是一种强大的工具,允许程序在运行时检查和操作类、接口、字段和方法。反射不仅用于检查类的结构&#…...
Spring开发系列教程(26)——异步处理
在Servlet模型中,每个请求都是由某个线程处理,然后,将响应写入IO流,发送给客户端。从开始处理请求,到写入响应完成,都是在同一个线程中处理的。 实现Servlet容器的时候,只要每处理一个请求&…...
【2025最新Java面试八股】如何理解MySQL的MVCC机制?
面试回答要点 当面试官问及MySQL的MVCC机制时,可以这样组织回答: "MVCC(Multi-Version Concurrency Control,多版本并发控制)是MySQL实现高并发事务的一种重要机制,它通过保存数据在某个时间点的快照来实现非阻塞读操作。I…...
使用FreeRTOS解决单片机串口异步打印
单片机串口异步打印 文章目录 单片机串口异步打印前言设计思路准备队列创建完整代码 总结 前言 🌊在单片机开发中串口的异步打印异步打印允许单片机在执行其他任务的同时进行打印操作,无需等待打印完成后再继续执行后续代码,避免了在多处调用…...
飞算 JavaAI 与 Spring Boot:如何实现微服务开发效率翻倍?
微服务架构凭借其高内聚、低耦合的特性,成为企业构建复杂应用系统的首选方案。然而,传统微服务开发流程中,从服务拆分、接口设计到代码编写、调试部署,往往需要耗费大量时间与人力成本。Spring Boot 作为 Java 领域最受欢迎的微服…...
Python 列表与元组深度解析:从基础概念到函数实现全攻略
在 Python 编程的广袤天地中,列表(List)和元组(Tuple)是两种不可或缺的数据结构。它们如同程序员手中的瑞士军刀,能高效地处理各类数据。从简单的数值存储到复杂的数据组织,列表和元组都发挥着关…...
vue 修改路由动态选择路由 改文件位置
vue 修改路由动态选择路由 改文件位置 main.jspermission.js...
Nginx openresty web服务 与 Go 原生web服务性能对比
1 概述 Nginx采用的是IO复用模型,能处理超高并发。 Go语言采用协程,能轻量级的处理超高并发。 那么在不考虑业务逻辑复杂的前提下,即假如将Nginx和Go都提供一个/test接口,并在接口逻辑中都只是让其做20毫秒的耗时操作,…...
【音视频】FFmpeg解封装
解封装 复用器,比如MP4/FLV 解复用器,MP4/FLV 封装格式相关函数 avformat_alloc_context(); 负责申请一个AVFormatContext结构的内存,并进行简单初始化avformat_free_context(); 释放该结构里的所有东西以及该结构本身avformat_close_input();关闭解复…...
autohue.js - 基于 JavaScript 开发的图片背景色提取开源库,能让图片和背景融为一体
图片提取主题色的工具库,可以实现一些酷炫的界面效果。 本文不是 AI 生成,大部分文字都是我自己敲键盘,部分文字摘自 autohue.js 作者主页,请各位放心舒适阅读。 autohue.js 是一个图片背景色提取库,基于提出来的颜色…...
bgp实验.包括联盟,隧道相关,以及一个低级错误
实验拓扑 低级错误 在配置隧道时,目标的单词是destination,我自动补全为description了,这个问题花了我40分钟 划分ip AS2内骨干网,一个网段需要两个地址,主机位2位,掩码30 需要6个 172.16.0.000000 00 172.16.0.0/30 172.16.0.000001 00 172.16.0.4/30 172.16.0.000010 00 1…...
科普动画短视频制作:角色塑造的魅力法则
宝子们,在科普动画短视频的世界里,角色塑造可是让作品出彩的关键!今天就来和大家唠唠那些超实用的角色塑造法则,还会给大家推荐一款超好用的工具哦~ 一、独特外形,吸睛第一步 在科普动画短视频制作中,角色…...
【飞渡科技数字孪生虚拟环境部署与集成教程 - CloudMaster实战指南】
飞渡科技数字孪生虚拟环境部署与集成教程 - CloudMaster实战指南 前言 本教程详细记录了飞渡科技的数字孪生平台CloudMaster的配置过程,以及如何将三维数字孪生场景集成到前端项目中。数字孪生技术能够在虚拟环境中精确复现物理实体的数据、特性和行为,…...
MongoDB 集合名称映射问题
项目场景 在使用 Spring Data MongoDB 进行开发时,定义了一个名为 CompetitionSignUpLog 的实体类,并创建了对应的 Repository 接口。需要明确该实体类在 MongoDB 中实际对应的集合名称是 CompetitionSignUpLog 还是 competitionSignUpLog。 问题描述 …...
禁止ubuntu自动更新
由于ubuntu server和desktop版本都默认 启动了,自动更新内核的操作。这对于生 产环境来说是不友好的。容易导致亿赛通 无法启动 默认开启了内核自动更新所以我们关闭自 动内核更新。 1.禁止更新执行 sudo apt-mark hold linux-image-generic linux-headers-generic…...
【C++】——入门基础(一)
前言 这是我C的第一篇文章,如果你想从事入门C行业,可以看看这幅漫画 当然,这只是一个玩笑,但如过你真的想学习C,和我一起学习吧 本人其他博客;恋风诗 本文出现的代码见gitte:mozhengy 这里写目录标题 前言1. C发展历史…...
[原创](现代Delphi 12指南):[macOS 64bit App开发]:在Mac App Store外创建、部署与公证
[作者] 常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共24年] 职业生涯: 22年 开发语言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 开发工具: Visual Studio、Delphi、XCode、…...
美乐迪电玩客户端打包与资源替换实战教程
本篇为《美乐迪电玩全套系统搭建》系列的第二篇,聚焦客户端层的实战操作,主要面向前端开发者、美术资源替换人员及整体项目的打包部署人员。教程将涵盖安卓客户端的构建、资源目录说明、动画素材替换方式及常见适配问题处理等。 一、客户端项目结构说明&…...
多态以及多态底层的实现原理
本章目标 1.多态的概念 2.多态的定义实现 3.虚函数 4.多态的原理 1.多态的概念 多态作为面对三大特性之一,它所指代的和它的名字一样,多种形态.但是这个多种形态更多的指代是函数的多种形态. 多态分为静态多态和动态多态. 静态多态在前面已经学习过了,就是函数重载以及模板,…...
描述城市出行需求模式的复杂网络视角:大规模起点-目的地需求网络的图论分析
描述城市出行需求模式的复杂网络视角:大规模起点-目的地需求网络的图论分析 原文: A complex network perspective for characterizing urban travel demand patterns: graph theoretical analysis of large-scale origin–destination demand networks…...
文件操作函数
本文是小编巩固自身而作,如有错误,欢迎指出! 1.使用文件的原因 我们编写的程序都是有生命周期的,储存在电脑的内存中,如果程序退出,内存回收,数据就会丢失,等程序再次运行…...
Java高频面试之并发编程-05
hello啊,各位观众姥爷们!!!本baby今天来报道了!哈哈哈哈哈嗝🐶 面试官:线程有哪些调度方法? 在Java中,线程的调用方法主要包括以下几种方式,每种方式适用于…...
LeetCode 1292 元素和小于等于阈值的正方形的最大边长
最大正方形边长问题详解 一、问题描述 给定一个大小为 mn 的矩阵 mat 和一个整数阈值 threshold,要求返回元素总和小于或等于阈值的正方形区域的最大边长;如果没有这样的正方形区域,则返回 0。 二、解题思路 前缀和矩阵的概念与构建 前缀…...
测试开发 - Java 自动化测试核心函数详解
目录 1. 元素定位 1.1 By.xpath 1.1.1 //* 1.1.2 //[指定节点] 1.1.3 / 1.1.4 /.. 1.1.5 [...] 1.1.6 指定索引获取对应元素 1.2 By.cssSelector 1.2.1 # 1.2.2 . 1.2.3 > 1.2.4 标签名:nth-child(n) 2. 获取元素 2.1 findElement 2.2 findElements 3. 操…...
【HarmonyOS】ArKUI框架
目录 概述 声明式开发范式 基于ArKUI的项目 • 1.创建资源文件 • 2.引用资源 • 3.引用系统资源: • 系统资源有哪些 • 4. 在配置和资源中引用资源 声明式语法 UI描述规范 UI组件概述 组件化 组件渲染控制语法 修改…...
【MQ篇】RabbitMQ之简单模式!
目录 引言一、 初识 RabbitMQ 与工作模式二、 简单模式 (Simple Queue) 详解:最直接的“点对点快递” 📮三、 Java (Spring Boot) 代码实战:让小兔子跑起来! 🐰🏃♂️四、 深入理解:简单模式的…...
K8S节点出现Evicted状态“被驱逐”
在Kubernetes集群中,Pod状态为“被驱逐(evicted)”表示Pod无法在当前节点上继续运行,已被集群从节点上移除。 问题分析: 节点磁盘空间不足 ,使用df -h查看磁盘使用情况 可以看到根目录 / 已100%满&#x…...
NumPyro:概率编程的现代Python框架深度解析
引言 概率编程作为统计学与机器学习的交叉领域,正在重塑我们构建不确定性模型的方式。在众多概率编程语言(PPL)中,NumPyro凭借其简洁的语法、强大的性能和与PyTorch生态系统的无缝集成,已经成为研究者和数据科学家的首…...
java进阶之git
git git介绍git常用命令代码回滚操作 git 介绍 工作区 改动(增删文件和内容)暂存区 输入命令:git add改动的文件名,此次改动就放到了"暂存区“本地仓库 输入命令:git commit 此次修改的描述,此次改动…...
负载阻尼效应及其作用解析
负载阻尼效应是指负载(如电路、机械系统或控制系统中连接的设备)对系统动态变化(如电压波动、机械振动等)产生的抑制或衰减作用。 其核心是通过消耗或吸收能量,减少系统中的振荡、波动或瞬态响应,从而提高…...
面向组织的网络安全措施
一、安全措施概述 在一个组织中,技术人员可以利用一系列强大的网络安全工具进行安全检测和防范,以保护组织的网络基础设施、数据和资产免受各种威胁。这些工具通常涵盖了从主动防御、威胁检测、漏洞管理到事件响应和安全分析的各个方面。 以下是一些关…...
Unity 跳转资源商店,并打开特定应用
需求: 打开资源商店,并定位到特定应用. 代码: #if UNITY_ANDROIDApplication.OpenURL("market://details?idcom.tencent.mm"); #elif UNITY_IPHONEApplication.OpenURL(“itms-apps://apps.apple.com/app/id333903271”); #end…...
2025年五大ETL数据集成工具推荐
ETL工具作为打通数据孤岛的核心引擎,直接影响着企业的决策效率与业务敏捷性。本文精选五款实战型ETL解决方案,从零门槛的国产免费工具到国际大厂企业级平台,助您找到最适合的数据集成利器。 一、谷云科技ETLCloud:国产数据集成工…...
基于 PaddleOCR对pdf文件中的文字提取
一、基于 PaddleOCR 提取 PDF 文件中的文字流程 1. 安装必要的依赖库:包括 PaddleOCR 和 PyMuPDF pip install paddlepaddle paddleocr pymupdf 2. 将 PDF 转换为图像:使用 PyMuPDF 将 PDF 的每一页转换为图像 3. 使用 PaddleOCR 进行文字识别&a…...
鸿蒙移动应用开发--渲染控制实验
任务:使用“对象数组”、“ForEach渲染”、“Badge角标组件”、“Grid布局”等相关知识,实现生效抽奖卡案例。如图1所示: 图1 生肖抽奖卡实例图 图1(a)中有6张生肖卡可以抽奖,每抽中一张,会通过弹层显示出来…...
【漫话机器学习系列】215.处理高度不平衡数据策略(Strategies For Highly Imbalanced Classes)
处理高度不平衡数据的四大策略详解 在机器学习与数据挖掘任务中,“类别不平衡”问题几乎无处不在。无论是信用卡欺诈检测、医疗异常诊断,还是网络攻击识别,正负样本的比例往往严重失衡。比如一个欺诈检测数据集中,可能只有不到 1…...
在离线 Ubuntu 环境下部署双 Neo4j 实例(Prod Dev)
在许多开发和生产场景中,我们可能需要在同一台服务器上运行多个独立的 Neo4j 数据库实例,例如一个用于生产环境 (Prod),一个用于开发测试环境 (Dev)。本文将详细介绍如何在 离线 的 Ubuntu 服务器上,使用 tar.gz 包部署两个 Neo4j…...
Windows下Golang与Nuxt项目宝塔部署指南
在Windows下将Golang后端和Nuxt前端项目打包,并使用宝塔面板部署的步骤如下 一、Golang后端打包 交叉编译为Linux可执行文件 在Windows PowerShell中执行: powershell复制下载 $env:GOOS "linux" $env:GOARCH "amd64" go build…...
基于贝叶斯优化的Transformer多输入单输出回归预测模型Bayes-Transformer【MATLAB】
Bayes-Transformer 在机器学习和深度学习领域,Transformer模型已经广泛应用于自然语言处理、图像识别、时间序列预测等多个领域。然而,在一些实际应用中,我们面临着如何高效地优化模型超参数的问题。贝叶斯优化(Bayesian Optimiz…...
ibus输入法微软词库分享
链接: https://pan.baidu.com/s/1aC-UvV-UDHEpxg5sZcAS2Q?pwddxpq 提取码: dxpq --来自百度网盘超级会员v8的分享 链接: https://pan.baidu.com/s/1aC-UvV-UDHEpxg5sZcAS2Q?pwddxpq 提取码: dxpq --来自百度网盘超级会员v8的分享 # 更改ibus输入法字体大小 sudo apt insta…...
Sharding-JDBC 系列专题 - 第五篇:分布式事务
Sharding-JDBC 系列专题 - 第五篇:分布式事务 本系列专题旨在帮助开发者全面掌握 Sharding-JDBC,一个轻量级的分布式数据库中间件。本篇作为系列的第五篇文章,将深入探讨 分布式事务(Distributed Transactions),包括其概念、支持的事务类型、配置方法、工作原理以及实战…...
力扣每日打卡17 49. 字母异位词分组 (中等)
力扣 49. 字母异位词分组 中等 前言一、题目内容二、解题方法1. 哈希函数2.官方题解2.1 前言2.2 方法一:排序2.2 方法二:计数 前言 这是刷算法题的第十七天,用到的语言是JS 题目:力扣 49. 字母异位词分组 (中等) 一、题目内容 给…...
深入解析C++ STL List:双向链表的特性与高级操作
一、引言 在C STL容器家族中,list作为双向链表容器,具有独特的性能特征。本文将通过完整代码示例,深入剖析链表的核心操作,揭示其底层实现机制,并对比其他容器的适用场景。文章包含4000余字详细解析,适合需…...
在 master 分支上进行了 commit 但还没有 push,怎么安全地切到新分支并保留这些更改
确保你的 commit 确实没有 push(否则会覆盖远程分支): git log --oneline # 查看本地 commit git log --oneline origin/master # 查看远程 master 的 commit 确保你的 commit 只存在于本地,远程 origin/master 没有…...
spark jar依赖顺序
1. 执行顺序 spark-submit --config "spark.{driver/executor}.extraClassPathsomeJar"提交的依赖包SystemClasspath – Spark安装时候提供的依赖包spark-submit --jars 提交的依赖包 2. 依赖解释 提交任务时指定的依赖 Spark-submit --config "spark.{drive…...
docker 国内源和常用命令
Ubuntu | Docker Docs 参考docker官方安装docker # Add Dockers official GPG key: sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt…...