分类目录: 架构设计

SQLite导入数据加速分析

声明:本文由AIGC生成,部分概念可能不准确,请注意甄别。

本文旨在探讨如何优化 SQLite 数据库中导入几亿条记录的性能,尤其是在数据量达到几千万时性能显著下降的情况。以下内容基于对相关资源和最佳实践的分析,提供了全面的优化策略和注意事项。

背景与问题分析

SQLite 是一种轻量级嵌入式数据库,适合处理大量数据,但当导入数据达到几千万条时,性能可能因以下因素下降:

  • 磁盘 I/O:写入大量数据到磁盘可能变慢,尤其在硬盘速度有限或有其他进程竞争时。
  • 内存限制:如果系统内存不足,可能导致交换(swap),显著降低性能。
  • 索引维护:如果表上有索引,每次插入都需要更新索引,数据量大时开销增加。
  • 事务管理:事务过大可能导致日志文件增长过快,影响性能。

用户已使用事务加速提交,但性能仍不理想,需进一步优化。用户明确表示不需要回滚功能,且使用 SSD,批量参数可调大,使用 GoLang 进行插入操作。

优化策略

1. 使用事务和预编译语句

研究表明,使用事务将多个插入操作分组到一个事务中,可以显著减少提交开销。例如,Improve INSERT-per-second performance of SQLite 提到,单事务插入可将性能从每秒 85 条提升到 23,000 条。此外,使用预编译语句(prepared statements)进一步优化。预编译一次 INSERT 语句,然后为每行绑定值,避免重复编译 SQL。测试显示,这可将性能提升至每秒 53,000 条。在 GoLang 中,虽然预编译语句的使用与批量插入结合效果有限,但通过构造多行 INSERT 语句(如 INSERT INTO table (col1, col2) VALUES (val1, val2), (val3, val4), …;)可以显著提高效率。

2. 批量插入与批量大小优化

批量插入是将多行数据在一次语句中插入,减少事务开销。Fast way to insert rows in SQLite 报告中,一位用户通过每批 100 行插入,成功在 33 秒内插入 1 亿行,约为每秒 3,030,303 行(尽管这一速度可能因硬件和设置而异)。建议实验不同批量大小(如 1000、5000、10000 行),找到系统最佳值。批量过小会导致频繁提交,过大可能耗尽内存。用户提到“批量参数可以调大”,表明他们有能力调整,建议从 1000 开始测试,逐步增加。在 GoLang 中,可以通过构建多行 INSERT 语句实现。例如:go

const batchSize = 1000
for i := 0; i < len(data); i += batchSize {
    end := i + batchSize
    if end > len(data) {
        end = len(data)
    }
    batch := data[i:end]
    var placeholders []string
    var params []interface{}
    for _, row := range batch {
        placeholders = append(placeholders, "(?, ?)")
        params = append(params, row.Col1, row.Col2)
    }
    sqlStr := fmt.Sprintf("INSERT INTO table (col1, col2) VALUES %s", strings.Join(placeholders, ","))
    _, err = tx.Exec(sqlStr, params...)
    if err != nil {
        // handle error
    }
}

需注意 SQLite 的 SQL 语句长度限制(默认 1,000,000 字节),根据行大小调整批量。

3. 调整 PRAGMA

设置SQLite 的 PRAGMA 设置可显著影响性能,以下是关键选项:

  • 同步模式(synchronous):设置 PRAGMA synchronous = OFF 可将性能提升至每秒 69,600 条,但如果操作系统崩溃,可能导致数据损坏。Improve INSERT-per-second performance of SQLite 提供数据对比。
  • 日志模式(journal_mode):
    • PRAGMA journal_mode = MEMORY:将日志保存在内存,速度快(每秒 64,000 条),但应用崩溃同样有风险。
    • PRAGMA journal_mode = OFF:禁用回滚日志,最高速度,但应用崩溃时数据库可能不一致,适合用户“不需回滚”的场景,但风险极高。
    • PRAGMA journal_mode = WAL:写前日志模式,安全性较高,且可翻倍插入速度,适合并发场景。SQLite Optimizations for Ultra High-Performance 推荐此模式。
  • 缓存大小(cache_size):设置 PRAGMA cache_size = 1000000 可提高事务性能,需根据可用内存调整。
  • 锁定模式(locking_mode):设置 PRAGMA locking_mode = EXCLUSIVE 减少锁定开销,适合批量插入。
  • 临时存储(temp_store):设置 PRAGMA temp_store = MEMORY 使用内存存储临时表,加速相关操作。

用户使用 SSD,磁盘 I/O 较快,适合上述高风险设置,但需权衡性能与数据完整性。如果是单次导入且能重做,建议使用 synchronous = OFF 和 journal_mode = MEMORY;若需更高安全性,可选择 WAL。

4. 延迟索引创建

如果表上有次要索引,每次插入都需要更新索引,数据量大时开销显著。Improve INSERT-per-second performance of SQLite 提供数据对比:

  • 插入前创建索引:每秒 47,700 条。
  • 插入后创建索引:每秒 63,300 条。

建议在批量插入前删除次要索引,完成后重建,显著减少插入时开销。用户可根据表结构决定是否适用。

5. 系统资源与 GoLang 特定优化

用户使用 SSD,写入速度较快,适合较大批量大小。GoLang 中,使用 mattn/go-sqlite3 驱动可能存在性能瓶颈(如字符串拷贝开销),但通过多行 INSERT 语句可缓解。Slow performance on bulk insert 提到,驱动在处理大批量语句时可能变慢,建议使用 Exec 方法构造多行 INSERT。确保系统有足够 RAM,避免交换。监控内存使用,调整批量大小以防内存不足。6. 其他注意事项

  • 多线程:研究显示,多线程插入未显著改善,可能因 SQLite 单文件锁机制限制。Fast way to insert rows in SQLite 测试结果表明,单线程批量插入已足够快。
  • 内存数据库:使用 :memory: 数据库可快速插入(33.08 秒插入 1 亿行),但不适合持久化存储。
  • 触发器和约束:检查表是否有触发器或约束,可能拖慢插入。

性能对比表

以下是关键优化技术的性能对比(基于 Improve INSERT-per-second performance of SQLite 和论坛数据):

优化技术 每秒插入条数 备注
单条插入(无优化) 85 使用 sqlite3_exec,性能最差
使用事务 23,000 基础优化,减少提交开销
预编译语句 53,000 进一步提升,减少 SQL 编译开销
PRAGMA synchronous = OFF 69,600 风险高,OS 崩溃可能损坏数据
PRAGMA journal_mode = MEMORY 64,000 应用崩溃风险高,日志在内存
PRAGMA journal_mode = WAL ~双倍 安全性能平衡,具体数值视场景
插入后创建索引 63,300 比插入前创建索引快(47,700),减少实时更新开销
批量插入(每批 100 行) ~3,030,303 论坛报告,需验证硬件和设置,实际可能低于此 (Fast way to insert rows in SQLite)

实施建议

  • 优先尝试事务、多行 INSERT 语句和 PRAGMA 设置,结合 MEMORY 模式,确保速度提升。
  • 如果性能仍不理想,逐步启用风险设置(如 synchronous = OFF),并确保有备份以防崩溃。
  • 监控内存和磁盘使用,调整批量大小,避免资源耗尽。
  • 测试 JSON1 插入是否适用,若数据源能以 JSON 格式提供,可能显著提升效率,但 GoLang 中需额外处理。

结论

通过上述优化,SQLite 导入几亿条记录的性能可显著提升,尤其在数据量大时。建议用户根据具体场景权衡性能与数据完整性,实验不同设置找到最佳组合。

关键引用

| 1 分2 分3 分4 分5 分 (5.00- 1票) Loading ... Loading ... | 同时归档在:数据库, 编程基础, 软件技术 | 标签: , , |

3FS Usrbio 简介

3FS 是一个为 AI 训练设计的分布式文件系统,USRBIO 是其原生客户端的关键功能。研究表明,usrbio 允许用户态应用程序直接提交 I/O 请求,绕过内核和 VFS,提升性能。它使用 Iov 作为大型共享内存进行零拷贝读写,Ior 则像 Linux 的 io-uring,处理批处理 I/O 请求。USRBIO 通过零拷贝和异步 I/O 减少开销,特别适合高吞吐量场景,如 AI 数据处理。

传统的FUSE客户端与服务端的数据交互流程为:

图片源自:https://juicefs.com/zh-cn/blog/engineering/fuse-file-system-design

可以看到数据流在内核和用户态之间要反复拷贝才能传递到应用中。而3FS的USRBIO则卸载了数据流,直接通过3FS的SDK从远端拉取数据,结合RDMA等高效网络,做到了零拷贝。

图片来源:https://developer.volcengine.com/articles/7480397583173877797

总的来说,USRBIO 通过以下方式提升了 I/O 性能:

  1. 零拷贝 I/O:通过共享内存 Iov,数据无需在用户态和内核态之间拷贝,减少了内存拷贝开销。
  2. 批处理 I/O 请求:Ior 允许一次性提交多个 I/O 请求,减少系统调用次数。例如,设置 io_depth=1024 可以批处理 1024 个请求,显著降低上下文切换开销。
  3. 异步 I/O:应用程序可以继续执行其他任务,而不必等待 I/O 操作完成,提升了并发性能。
  4. 高性能网络支持:Iov 内存注册为 InfiniBand,支持 RDMA 等高性能网络传输,特别适合分布式 AI 训练场景。

这些特性使得 USRBIO 特别适合需要高吞吐量和低延迟的 AI 工作负载,例如处理 PB 级数据集的排序任务(如 GraySort 基准测试,3.66 TiB/分钟吞吐量)。

参考链接:
https://developer.volcengine.com/articles/7480397583173877797
https://zhuanlan.zhihu.com/p/30602759754
https://github.com/deepseek-ai/3FS/blob/main/docs/design_notes.md
https://github.com/deepseek-ai/3FS/blob/main/src/lib/api/UsrbIo.md

| 1 分2 分3 分4 分5 分 (5.00- 1票) Loading ... Loading ... | 同时归档在:AI技术, 存储技术, 软件技术 | 标签: , , , , , |

整理了一个程序员必读书籍和文档清单

所有电子书籍都是从网络收集的,参考自己的阅读习惯和技术论坛的推荐,主要是近10年来的经典书籍。重点在3个方向:计算机系统基本原理(操作系统、编译原理、算法)、计算机网络和分布式架构。还有少量的数据库介绍。

收录的书都是比较早期的经典书籍,更多聚焦在基础知识上面。对于最新的云原生、微服务和低代码等技术涉及较少。

下载链接:必读书单

阅读全文 »

| 1 分2 分3 分4 分5 分 (5.00- 1票) Loading ... Loading ... | 同时归档在:IO编程, Linux内核, 算法数据结构, 编程基础, 职业发展 | 标签: , |

一图梳理大数据知识体系

转自阿里技术社区

简介: 对海量数据进行存储、计算、分析、挖掘处理需要依赖一系列的大数据技术,而大数据技术又涉及了分布式计算、高并发处理、高可用处理、集群、实时性计算等,可以说是汇集了当前 IT 领域热门流行的 IT 技术。本文对大数据技术知识体系进行划分,共分为基础技术、数据采集、数据传输、数据组织集成、数据应用、数据治理,进行相关的阐述说明,并列出目前业界主流的相关框架、系统、数据库、工具等。(文末福利:下载大数据知识体系图)

阅读全文 »

| 1 分2 分3 分4 分5 分 (5.00- 1票) Loading ... Loading ... | 同时归档在:云计算/云存储, 存储技术 | 标签: , , , , , |

基于Dlib、Flask和Sqlite的人脸检测和识别服务

这个十一原定的计划取消了,没有做好备份计划,也就不打算出远门了,关在家里,把一直都想做的一个本地化的人脸识别服务整了一下。提供人脸分析的开源服务似乎很多年都没有大的变化了,一直都是Dlib和OpenCV,对比了一下,Dlib更容易使用。一直没有正经写过Python代码,翻出N年前买的Python编程书,边翻书Google、边写代码。基本的代码流程比较简单,Dlib官方也有例子,很容易运行起来,但是要服务化,要做人脸比对,并且是增量的人脸比对和识别,并不容易。说做就做,最终整个服务形成如下架构。

架构图:
image

代码和部署使用方法在如下git工程:https://git.codefine.site:3000/Shentar/facerec

首先需要将探测的过的“人脸”存储起来,然后能输入一张人脸返回与该人脸近似的所有人脸,这样客户端好做人脸归集。很快做好了一个初步的框架:使用Flask提供REST接口接收照片,在响应中返回人脸的特征标识,使用SHA256对人脸68点位的描述向量进行HASH,返回给客户端。同时将HASH值和实际的token存储到Sqlite。第一天大概就完工了这个功能。

运行起来,发现单纯的Flask不能并发,第二个请求会报错,一次只能接受和处理一个请求。于是又按照网上的经验,使用Gunicorn和Gevent来做多线程的方案,因为习惯了单进程多线程的方式,多线程访问Sqlite需要加锁,按照通用的做法,使用一个队列来管理Sqlite实例。继续验证,发现多线程并不能加速Detect的效率,貌似Dlib不支持多线程加速。调整为多进程,四个CPU都能运用起来。

1d2dd2b5bcde40b6a563996821d84843

终于找到了一个能将这个3.2GHZ的四核CPU跑满的业务了 ^_^

Architecture: x86_64
CPU op-mode(s):                  32-bit, 64-bit
Byte Order:                      Little Endian
Address sizes:                   39 bits physical, 48 bits virtual
CPU(s):                          4
On-line CPU(s) list:             0-3
Thread(s) per core:              2
Core(s) per socket:              2
Socket(s):                       1
NUMA node(s):                    1
Vendor ID:                       GenuineIntel
CPU family:                      6
Model:                           94
Model name:                      Intel(R) Core(TM) i3-6100T CPU @ 3.20GHz

人脸检测的效果还不错,错误率的话,自己家用是够了。特别是在侧脸检测上面,比较准确。在人脸比对方面,错误率就要高一些了,反复验证,发现0.36的比对阀值比较合适。侧脸虽然检测率高,但是在比对上面,只用通用的拟合范数,结果会表现为差异很大。因此这里应该是需要有定制化的比对实现,只做部分比对。这块需要深入到人脸检测技术内部,去分析128D的特征值向量的每一个值,短时间内没办法去研究透了。

由于采用了多进程,因此没法共用一个Sqlite运行时实例,强行并发读写访问会导致数据库错乱,不得不又做了一个服务来封装Sqlite,多个检测进程输出的人脸特征值都发给该服务来顺序存储,同时也返回给客户端。两个服务之间同样采用REST接口交互。

准备大规模上量,将jAlbum目前使用的线上人脸识别服务切换到这个本地服务上面,又发现检测时长非常高,一张4M的图片,大概需要几秒的时间,并且还有些非常小的区块被检测到了。对于检测慢的问题,考虑降低输入的照片的像素,图片减小后,长宽的像素点都相应减少了,但是人脸的特征点并不会损失太多。因此先对图片进行降低像素和尺寸,识别完成后,对识别到的人脸在照片上的位置也要相应做缩放,对比了一下,原始大小检测和缩放后检测,再对结果做相反的缩放,最终结果误差不大,但是这样能极大提速。对于非人脸和质量不高的人脸被检测到的问题,做了一些粗浅的限制,人脸长宽必须大于100的阀值才认为是正常的人脸。Dlib应该有正统的输出人脸的质量的参数,查了很久,没有找到合适的方法,就只能先这样吧。在比对方面,还有一些重要的概念,没有弄明白,如人脸对齐、年龄、性别检测等,不清楚我的代码里面是否已经有调用已经做了这块。

具体的处理代码:

01data = np.frombuffer(data, np.uint8)
02if data is None:
03    raise Exception('image is required.')
04 
05zoom_ratio = 1
06if data.size > 6 * 1024 * 1024:
07    img = cv2.imdecode(data, cv2.IMREAD_REDUCED_COLOR_4)
08    zoom_ratio = 4
09elif data.size > 4 * 1024 * 124:
10    img = cv2.imdecode(data, cv2.IMREAD_REDUCED_COLOR_2)
11    zoom_ratio = 2
12else:
13    img = cv2.imdecode(data, cv2.IMREAD_COLOR)
14 
15faces = []
16dets = detector(img, 1)

总的来说,开源项目,适合做一下Demo,如果要尽善尽美,那么就要深入到源码,有针对性的去优化检测和比对模型。作为个人的实验和家用还是很不错的。至少在快速编程和服务化这方面。

| 1 分2 分3 分4 分5 分 (5.00- 2票) Loading ... Loading ... | 同时归档在:WEB网络, 数码硬件, 移动互联, 软件应用 | 标签: , , , , , |

一致哈希(Consistent Hashing)简介

一致哈希 是一种特殊的哈希算法。在使用一致哈希算法后,哈希表槽位数(大小)的改变平均只需要对 K/n个关键字重新映射,其中 K是关键字的数量n是槽位数量。然而在传统的哈希表中,添加或删除一个槽位的几乎需要对所有关键字进行重新映射。一致哈希的算法最早在如下论文中被提出:

一致哈希在分布式计存储架构中无处不在。是被证明的可以解决经典哈希视图发生变化时,数据搬迁尽可能少的算法。最早是在分布式缓存中提出,参考如下文档,这里提供原文的下载链接:《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》

阅读全文 »

| 1 分2 分3 分4 分5 分 (5.00- 4票) Loading ... Loading ... | 同时归档在:存储技术, 算法数据结构 | 标签: , , |

PostgreSQL 9.5 架构图及外存图

转自阿里云栖社区:链接。点击图片查看原图。

阅读全文 »

| 1 分2 分3 分4 分5 分 (5.00- 1票) Loading ... Loading ... | 同时归档在:存储技术, 数据库 | 标签: |

微信朋友圈技术之道

讲师简介

陈明,微信高级工程师、朋友圈负责人,2012年加入微信后台团队,负责微信后台核心服务的研发,包括朋友圈、即时通信、基础设施等。他获得清华大学计算机系学士和博士学位,研究方向是分布式系统。在加入微信前,他在腾讯搜索和微软亚洲研究院工作多年,内容包括搜索架构与分布式存储等。

概述

截止到2015年7月,微信每月活跃用户约5.49亿,朋友圈每天的发表量(包括赞和评论)超过10亿,浏览量超过100亿。得益于4G网络的发展,以上数据仍有很快的增长,而且相对于PC互联网时代,移动互联网时代的峰值要来得更加凶猛。比如,2015年元月的流量到了平时的2倍,而峰值则达到了平时峰值的2倍,相当于平时正常流量的5倍,这对整个系统的考验是很残酷的。本次分享将简单介绍微信后台团队的开发模式、微信朋友圈的架构以及在性能上的一些工作,供各位参考。

阅读全文 »

| 1 分2 分3 分4 分5 分 (4.73- 15票) Loading ... Loading ... | 归档目录:架构设计 | 标签: |

[转]图解分布式一致性协议Paxos

转载自:loop in codes

Paxos协议/算法是分布式系统中比较重要的协议,它有多重要呢?
<分布式系统的事务处理>

Google Chubby的作者Mike Burrows说过这个世界上只有一种一致性算法,那就是Paxos,其它的算法都是残次品。

<大规模分布式存储系统>

理解了这两个分布式协议之后(Paxos/2PC),学习其他分布式协议会变得相当容易。

学习Paxos算法有两部分:a) 算法的原理/证明;b) 算法的理解/运作。

阅读全文 »

| 1 分2 分3 分4 分5 分 (4.92- 12票) Loading ... Loading ... | 同时归档在:云计算/云存储, 算法数据结构 | 标签: , |

Intel芯片架构和指令集演化

从芯片架构谈系统优化

下载地址:《从芯片架构盘系统优化》

| 1 分2 分3 分4 分5 分 (5.00- 10票) Loading ... Loading ... | 同时归档在:数码硬件 | 标签: , , , , , , , , , , |