数据密集型应用学习笔记

第一部分:适用于所有数据系统的基本思想 第1章:术语与方法 数据库 高速缓存 索引:按关键字搜索数据并支持各种过滤 流式处理:持续发送消息至另一个进程,处理采用异步方式 批处理:定期处理大量的累积数据 设计数据系统时会遇到的问题 当系统内出现了局部失效时,如何确保数据的正确性与完整性? 当发生系统降级时,该如何为客户提供一致的良好表现? 负载增加时,系统如何扩展? 友好的服务API该如何设计? 目标 可靠性 硬件错误、软件错误、人为错误 可扩展性 本系统的负载是什么?(每秒请求处理次数?同时活动用户数量?平均值?峰值?) 负载增加但系统资源不变,系统性能会发生什么变化? 负载增加,如果要保持性能不变,需要增加多少资源? 本系统的性能指标如何衡量?(吞吐量?响应时间?) 负载增加时,如何保持良好的性能?(垂直拓展:升级到更强大的机器。水平拓展:将负载分布到多个更小的机器,无共享体系结构) 弹性拓展:自动检测负载增加,自动添加更多计算资源 手动拓展:人工分析性能表现,手动添加更多计算资源 无状态服务水平拓展比有状态服务更容易。 超大规模的系统要针对应用定制,没有一套通用的框架,所以说这种架构师的岗位是无法替代的,有出路,可以一直搞,从通用的组件定制出一个超大规模的系统。 可维护性 运维简单、项目复杂度低、易于改变 第2章:数据模型与查询语言 每层通过提供一个简洁的数据模型来隐藏下层的复杂性。 数据模型 层次模型: 不好用,基本用下面三种 关系模型: 写时模式(写时强制) 劣势:对象-关系不匹配(阻抗失谐,需要一个转换层也就是ORM) 文档模型: 读时模式(读时处理) 图模型 读时模式(读时处理) 所有数据都有可能相互关联 一个模型可以用另一个模型来模拟,但是在不同场景下,有的模型过于笨重,所以不同的系统用于不同的目的。 还有其他的模型(全文索引等) 查询语句 命令式 告诉计算机以特定的顺序执行某些操作,指定如何实现 声明式 只需指定所需的数据模式,不需要指定如何实现,系统自动选择 MapReduce 编程模型 查询的逻辑用代码片段来表示,这些代码片段可以被处理框架重复地调用。 基于函数语言中的map(也称collect)和reduce(也称fold或inject)函数 第3章:存储引擎 日志:表示一个仅能追加的记录序列集合。 墓碑:表示这个记录被删除的标记 索引结构 哈希索引: 必须全放进内存(放到磁盘基本没用) 不能简单支持区间查找 存储段key-value对不需要有序 值可以是实际行(文档,顶点),也可以是对其他地方存储的行的引用(这个用的多,因为存在多个二级索引的时候就可以避免复制数据),存储具体行的文件叫堆文件, 聚集索引: 在索引文件中保存行数据 非聚集索引: 索引文件中只存储数据的引用 覆盖索引: 多列索引: 全文索引和模糊索引: 日志结构 SSTable(排序字符串表) key-value对有序...

September 21, 2022 · 1 min

Python的路径和版本管理

我现在的mac上已经安装了如下几个python /opt/homebrew/opt/python@3.10/bin/python3.10 /usr/bin/python3 /Library/Frameworks/Python.framework/Versions/2.7/bin/python 这些包从哪里安装的 homebrew的安装包是通过homebrew使用brew命令进行安装的,可以使用brew uninstall进行卸载,如果brew安装的其他项目有使用python,就无法直接卸载了。 /usr/bin/python3这个python是系统自带的,不推荐卸载,/usr/bin/python3应该是一个硬链接。 python2是为了使用npm安装不得已下载的。 pip install安装的包放在哪里? 对于mac自带的python3,系统做了一些工作使得这个的安装包路径在/Users/<user_name>/Library/Python/3.8/lib/python/site-packages下 参考博客https://frostming.com/2019/03-13/where-do-your-packages-go/ Python 是如何寻找包的 现在大家的电脑上很可能不只有一个 Python,还有更多的虚拟环境,导致安装包的时候,一不小心你就忘记注意安装包的路径了。首先我们来解决找包的问题,这个问题回答起来很简单,但很多人不知道这个原理。假如你的 Python 解释器的路径是 $path_prefix/bin/python,那么你启动 Python 交互环境或者用这个解释器运行脚本时,会默认寻找以下位置1: $path_prefix/lib(标准库路径) $path_prefix/lib/pythonX.Y/site-packages(三方库路径,X.Y 是对应 Python 的主次版本号,如 3.7, 2.6) 当前工作目录(pwd命令的返回结果) 这里如果你用的是 Linux 上的默认 Python,$path_prefix 就是 /usr,如果你是自己使用默认选项编译的,$path_prefix 就是 /usr/local。从上面第二条可以看到不同 Python 版本的三方库路径不同,如果你把 Python 从 3.6 升级到 3.7 那么之前装的三方库都没法用了。当然你可以整个文件夹都拷贝过去,大部分情况不会出问题。 几个有用的函数 sys.executable:当前使用的 Python 解释器路径 sys.path:当前包的搜索路径列表 sys.prefix:当前使用的 $path_prefix 为什么vscode的终端使用的python3是brew的而系统的终端用的默认的python3 我重新打开了一个系统的终端之后也变成使用brew自带的了,说明是环境变量设置的问题。 使用echo $PATH查看环境变量,得到结果 /Users/chuhuilong/.nvm/versions/node/v10.15.3/bin:/Library/Frameworks/Python.framework/Versions/2.7/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin 管理python 使用python遇到的最大问题就是python的版本管理了,虽然使用其他的语言也会有版本管理问题,但是python最大的难点在于,python2和python3不兼容,并且它们的安装方式还有多种,安装下来的位置也都不同。另外有些系统比如mac自带python3,种种原因使得python的版本管理地位非常重要,没有好的版本管理,就不清楚自己在运行什么版本,下载的包也会丢在不同的地方。 pyenv 根据这篇文章https://opensource.com/article/19/5/python-3-default-mac,博主在安装另一个软件时也遇到了和我一样的问题,python版本太多太混乱。很多人遇到了这些问题,于是有了各种解决方案,其中pyenv受到了Moshe Zadka的推荐。 pyenv使用很简单 安装brew **install** pyenv 下载指定pythonpyenv install 3.10.0...

September 17, 2022 · 1 min

pwndbg练手

pwndbg pwndbg是gdb的一个拓展,使用体验比gdb好很多。使用文档。 查看static变量存储在哪儿 编写一个测试程序staticMemberInClass.cpp。 class TestClass { public: static int static_member; }; int TestClass::static_member = 20; int main() { TestClass::static_member = 30; } 编译g++ -g staticMemberInClass.cpp -o staticTest.o 调试gdb ./staticTest.o 在main函数处打断点,b main 运行r 这个输出结果就人性化很多了 vmmap查看虚拟内存映射 可以看到是没有堆的,使用heap查看堆 进一步证实了此时确实还没有堆 p &TestClass::static_member查看静态成员的地址 结合汇编代码 运行到此处时,p $rip+0x2ed5查看将0x1e也就是30存在哪个地址了 算上dword正好是static_member的地址 x/wd 0x555555558010查看一下该地址的值 多方面都印证了static_member存储在这个地址 vmmap查看一下0x555555558010在属于哪个部分 很明显存储在数据段中。

May 31, 2022 · 1 min

热更新demo

运行时加载 动态链接库提供的API 函数声明 /* Open the shared object FILE and map it in; return a handle that can be passed to `dlsym' to get symbol values from it. */ extern void *dlopen (const char *__file, int __mode) __THROWNL; /* Unmap and close a shared object opened by `dlopen'. The handle cannot be used again after calling `dlclose'. */ extern int dlclose (void *__handle) __THROWNL __nonnull ((1)); /* Find the run-time address in the shared object HANDLE refers to of the symbol called NAME....

May 31, 2022 · 3 min

ELF文件格式

ELF文件格式 建议下载下面这张图片,再对照下方的注释查阅。 [1]ELF文件类 Untitled Database [2]字节序 Untitled Database [3]文件类型 Untitled Database [4]机器类型 Untitled Database [5]段的类型 Untitled Database [6]段的标志位 Untitled Database [7]段的链接信息(sh_link&sh_info) 如果该段的类型与链接有关,则意义如下,否则无意义 Untitled Database [8]符号类型 Untitled Database [9]符号绑定信息 Untitled Database [10]符号所在段 如果符号定义在本目标文件中,那么这个成员表示符号所在的段在段表中的下标。 否则,如下表 Untitled Database [11]常见类型值 Untitled Database [12]重定位入口的偏移 Untitled Database 参考文献:《程序员的自我修养》

May 12, 2022 · 1 min

如何方便地阅读Arduino或Esp8266的源代码

如何方便地阅读Arduino或Esp8266的源代码 Windows(Sourcetrail+ArduinoCLI) 需要用到的工具 Sourcetrail ArduinoCLI 根据官方手册,下载windows下的压缩包,解压后的文件夹种有一个arduino-cli.exe,执行文件。假设改执行文件的路径为D:\arduino-cli\arduino-cli.exe,用管理员权限打开cmd进入该目录。 Arduino 根据官方手册,先使用arduino-cli core update-index更新一下缓存。将Arduino的板子插入电脑的接口后,使用arduino-cli board list后,core会告知改板子使用的核心,比如我用的Arduino UNO R3,core是arduino:avr,那么需要下载该corearduino-cli core install arduino:avr,如果这个时候出现Access is denied错误,根据issues723,关闭一下杀毒软件在尝试一次(我使用的火绒导致静默阻止)。core安装成功之后可以使用arduino-cli core list查看一下所有已经安装的core。其他使用方法可以参考官方文档,重点是如何更好地阅读代码。假设我们要阅读的代码是MyFirstSketch.ino,那么根据官方手册可以执行arduino-cli compile -b esp8266:esp8266:nodemcu HttpOTA --only-compilation-database -v,–only-compilation-database会在build目录下生成comile_commands.json文件,-v会显示具体的信息,而build目录就是输出最后arduino-sketch文件所在的目录。 找到comile_commands.json文件后就可以直接用Sourcetrail打开,创建新项目时选择CDB,里面选择comile_commands.json文件(建议复制到源文件目录下,sourcetrail的项目文件也选择源文件目录),解析头文件选择从cdb中导入就行,这样解析之后虽然还会有一些error和fatal,但是基本上不影响源码阅读。 esp8266 方法和Arduino使用差不多,根据官方手册安装esp8266的库文件用这个命令 arduino-cli core update-index --additional-urls https://arduino.esp8266.com/stable/package_esp8266com_index.json 注意连接板子查看具体的board型号。 WSL2 加入需要在Windows上的WSL2里面使用ArduinoCLI,vscode使用compile_command.json来解析的话,会遇到下面一些问题。 WSL2目前不支持串口映射,解决办法时根据微软的手册安装软件进行手动映射。 在Linux环境中遇到avrdude: ser_open(): can’t open device “/dev/ttyACM0”: Permission denied问题,sudo chmod a+rw /dev/ttyACM0 arduino-cli core install esp8266:esp8266 arduino-cli compile -b esp8266:esp8266:nodemcu HttpOTA --only-compilation-database -v C:\Users\18454\AppData\Local\Temp\arduino-sketch-776950451AE70DA4FF60E70254F9E1B8

April 27, 2022 · 1 min

NodeMCU远程点亮电灯泡

**目标:**远程点亮一个灯泡 硬件:ModeMCU 基础知识 ESP8266和NodeMCU: ESP8266是一块芯片,NodeMCU是以ESP8266芯片为核心的开发板 esp8266芯片 内置ESP8266芯片的nodemcu开发板 ESP8266的三种工作模式: STA(Station):ESP8266主动去连接WIFI AP(Wireless Access Point):ESP8266创建WIFI STA+AP:上面两个共存 API: WiFiServer,Serial.begin(),pinMode(),Serial.print() 板载小灯: GPIO2引脚与板载小灯相联 在esp8266的库文件中hardware/esp8266/3.0.2/variants/nodemcu/pins_arduino.h中定义了各种引脚 基本思路 ESP8266以STA模式工作,连接到WIFI后,自己内部启动一个TCP server,这个TCP server其实是写一个小型的HTTP服务器,客户端通过浏览器就可以访问到。 代码: #include <ESP8266WiFi.h> //此处设置您的wifi接入信息 #ifndef STASSID #define STASSID "WiFi" // wifi名称 #define STAPSK "password" //要连接的wifi密码 #endif const char *ssid = STASSID; const char *password = STAPSK; //创建TCP server对象,并将端口指定为80 WiFiServer server(80); void setup() { //打开串口 Serial.begin(115200); //初始化板载LED pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, 0); //连接WiFi Serial.println(); Serial.println(); Serial.print(F("Connecting to ")); Serial.println(ssid); WiFi.mode(WIFI_STA); WiFi....

April 21, 2022 · 1 min

算法导论第二章习题

2.1 1 2 INSERTION-SORT(A) for j = 2 to A.length key = A[j] i = j-1 while i>0 and A[i]<key A[i+1]=A[i] i=i-1 A[i+1]=key 3 for i = 1 to A.length if A[i]=v return i v = NIL A[1..i-1]表示位置1到i-1的元素都不等于v **初始化:**当i=1时,没有元素,自然也没有元素等于v **保持:**每次循环会将不等于v的元素加入到A[i..i-1]中 **终止:**如果遇到A[i]=v,循环终止。如果最后i=A.length时,A[1..i-1]中元素都不等于v也就是数组中所有元素都不等于v。 4 **输入:**两个二进制序列 $$A=<a_1,a_2,\cdots,a_n>,B=<b_1,b_2,\cdots,b_n>$$ **输出:**二进制序列 $$C=<c_1,c_2,\cdots,c_n,c_n+1>,C=A+B$$ carry = 0 for i = n downto 1 C[i] = A[i]^B[i]^carry if(A[i]+B[i]+carry>1) carry = 1 else carry = 0 c[1] = carry 2.2 1 $\theta(n^3)$...

April 18, 2022 · 3 min

TCP为什么使用三次握手协议

背景知识 TCP是一个高可靠的主机到主机之间的通讯协议,这些主机位于分组交换网络(基于IP协议)中,也可能位于由这些网络组成的通讯系统中。TCP需要在不可靠的网络通讯系统中提供可靠的服务必须满足一系列基本实现,其中包括可靠性和多路复用。 为了实现可靠性,TCP连接发送的每个字节都有一个序列号。因为每个字节都编号了,所以可以对每个字节进行确认。 为了实现多路复用,TCP提供了一系列端口,主机地址加上端口号称为socket。TCP协议没有限制同一个TCP连接的重复使用。一个连接由一对socket唯一确定。 使用三次握手的充分性 如果一条连接突然断开重连后,TCP 如何识别旧连接发送的包?为了避免混乱,我们要避免当前连接正在使用的序列号与旧连接发送的且仍在网络中传输的数据包的序列号相同。并且要在TCP协议无法记住以前的序列号的前提下实现这个功能(因为TCP可能崩溃并忘记之前的序列号)。 为了实现上述功能,可以使用ISN生成器。当一个新连接建立时,初始序列号( initial sequence number ISN)生成器会生成一个新的32位的 ISN。ISN生成器生成的初始序列号是唯一的。 每一个连接都有一个接收序列号和发送序列号。发送初始序列号由发送数据的TCP实体选择,接收序列号是在连接建立时确定的。 连接建立时,两端必须要同步对方的初始序列号。双方通过同步带有SYN标志和初始序列号的数据段来实现。所以为了实现上述目的,一般需要一个初始化序列号选择器并且需要一些握手机制来同步初始化序列号。 同步机制需要发送自己的初始化序列号给对方,并且接收对方发送过来的确认信息。连接的两端必须接收对方发送过来的初始序列号并且发回确认信息。 A --> B SYN my sequence number is X A <-- B ACK your sequence number is X A <-- B SYN my sequence number is Y A --> B ACK your sequence number is Y 因为第二步和第三步可以合并成一步,所以一般称为三次握手 the three way (or three message) handshake。 因为序列号并没有使用一个网络里的全局时钟来进行同步,而且不同 TCP实体会使用不同的机制来选择初始序列号。当一端接收到一个SYN连接请求时,无法确定这个连接请求是不是之前被网络延迟的连接请求(如果是之前的连接请求,应该拒绝连接),所必须向另一端确认这个序列号。所以三次握手是必须的。 使用三次握手的必要性 三次握手可以确保过期的连接请求即使重新送到了接收端也会被接收端抛弃。因为接收端每次接收到连接请求都会向发送方进行确认,而因为不会出现相同的序列号,所以接收端接受的这个过期的连接请求的序列号一定与发送方的初始序列号不同,所以这个过期的连接请求一定会被拒绝。 三次握手可以确保两端进行可靠的数据传输。因为连接时两端都知道对方的初始序列号,所以接下来的传输过程双方对整个传输过程的序列号都是完全掌握的。 参考资料: https://datatracker.ietf.org/doc/html/rfc793 https://book.douban.com/subject/10510747/(6.2.2节)

May 9, 2021 · 1 min

OpenCV的安装与环境配置(window10,Visual Studio 2019)

OpenCV的安装 **第一步:**下载OpenCv https://opencv.org/releases/,本文使用 OpenCV-4.5.0 。 **第二步:**下载得到 opencv-4.5.0-vc14_vc15.exe 文件,运行该文件,选择解压到目标地址,本文解压到目录 D:\Library 。 **第三步:**为了方便以及清晰,这一步添加系统环境变量 OPENCV_DIR 。方法为以管理员身份运行 cmd ,输入并运行命令setx -m OPENCV_DIR D:\Library\opencv\build\x64\vc15,(此处根据平台环境可能需要有所调整)。 第四步:添加系统环境变量Path中的环境变量,添加%OPENCV_DIR%\bin Visual Studio 2019项目的配置 解决方案配置为 Debug ,解决方案平台为 x64 。 项目属性 - VC++ 目录 - 包含目录,添加 D:\Library\opencv\build\include 路径 项目属性 - VC++ 目录 - 库目录,添加 D:\Library\opencv\build\x64\vc15\lib 路径 项目属性 - 链接器 - 输入 - 附加依赖项,添加 opencv_world450d.lib ,(此处lib文件可在 D:\Library\opencv\build\x64\vc15\bin 中查看,d表示debug,解决方案与平台需要根据实际情况做调整) 测试程序 #include <iostream> #include <stdio.h> #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" using namespace std; using namespace cv; int main() { // 设置窗口 Mat img = Mat::zeros(Size(800, 600), CV_8UC3); img....

April 17, 2021 · 1 min