Redis中数据存储模式有2种:cache-only,persistence;cache-only即只做为“缓存”服务,不持久数据,数据在服务终止后将消失,此模式下也将不存在“数据恢复”的手段,是一种安全性低/效率高/容易扩展的方式;persistence即为缓存中的数据持久备份到磁盘文件,在服务重启后可以恢复,此模式下数据相对安全。
持久化数据的方式很多,基于各种考虑面,可能最终导致的设计手段有所差异。针对互联网应用,服务提供者必须具备并发访问/数据安全/故障修复/集群与容错等,我先从如下几个方面引导一下:
- 单server情况下,一条数据被修改后,是立即持久化?还是按照时间戳“批量 + 增量”持久化?还是全量持久化?
- 对于密集的变更操作,持久化的性能开支是否会影响到服务输出能力?
- 数据如何恢复?
- 集群情况下,如何确保每个节点上持久化数据一致性?
Redis中采取了AOF/snapshot/vm三种手段来直接或者间接的持久化数据,其中VM策略已经被弃用。如下为设计思想:
一.AOF
1) AOF:Append-only file,将“操作 + 数据”以格式化指令的方式追加到操作日志文件的尾部,在append操作返回后(已经写入到文件或者即将写入),才进行实际的数据变更,“日志文件”保存了历史所有的操作过程;当server需要数据恢复时,可以直接replay此日志文件,即可还原所有的操作过程。AOF相对可靠,它和mysql中bin.log、apache.log、zookeeper中txn-log简直异曲同工。AOF文件内容是字符串,非常容易阅读和解析,它和redis-protocol具有一样的格式约束:
##AOF文件格式,其中"##"为注释,非文件实际内容
##选择DB
*2
$6
SELECT
$1
0
##SET k-v
*3
$3
SET
$2
k1
$2
v1
我们可以简单的认为AOF就是日志文件,此文件只会记录“变更操作”(例如:set/del等),如果server中持续的大量变更操作,将会导致AOF文件非常的庞大,意味着server失效后,数据恢复的过程将会很长;事实上,一条数据经过多次变更,将会产生多条AOF记录,其实只要保存当前的状态,历史的操作记录是可以抛弃的;因为AOF持久化模式还伴生了“AOF rewrite”。
AOF的特性决定了它相对比较安全,如果你期望数据更少的丢失,那么可以采用AOF模式。如果AOF文件正在被写入时突然server失效,有可能导致文件的最后一次记录是不完整,你可以通过手工或者程序的方式去检测并修正不完整的记录,以便通过aof文件恢复能够正常;同时需要提醒,如果你的redis持久化手段中有aof,那么在server故障失效后再次启动前,需要检测aof文件的完整性。aof文件默认位于src下appendonly.aof:
$ ./redis-check-aof --fix appendonly.aof
AOF analyzed: size=52, ok_up_to=52, diff=0
AOF is valid
2) 配置:
##此选项为aof功能的开关,默认为“no”,可以通过“yes”来开启aof功能
##只有在“yes”下,aof重写/文件同步等特性才会生效
appendonly no
##指定aof文件名称
appendfilename appendonly.aof
##指定aof操作中文件同步策略,有三个合法值:always everysec no,默认为everysec
appendfsync everysec
##在aof-rewrite期间,appendfsync是否暂缓文件同步,"no"表示“不暂缓”,“yes”表示“暂缓”,默认为“no”
no-appendfsync-on-rewrite no
##aof文件rewrite触发的最小文件尺寸(mb,gb),只有大于此aof文件大于此尺寸是才会触发rewrite,默认“64mb”,建议“512mb”
auto-aof-rewrite-min-size 64mb
##相对于“上一次”rewrite,本次rewrite触发时aof文件应该增长的百分比。
##每一次rewrite之后,redis都会记录下此时“新aof”文件的大小(例如A),那么当aof文件增长到A*(1 + p)之后
##触发下一次rewrite,每一次aof记录的添加,都会检测当前aof文件的尺寸。
auto-aof-rewrite-percentage 100
AOF是文件操作,对于变更操作比较密集的server,那么必将造成磁盘IO的负荷加重;此外linux对文件操作采取了“延迟写入”手段,即并非每次write操作都会触发实际磁盘操作,而是进入了buffer中,当buffer数据达到阀值时触发实际写入(也有其他时机),这是linux对文件系统的优化,但是这却有可能带来隐患,如果buffer没有刷新到磁盘,此时物理机器失效(比如断电),那么有可能导致最后一条或者多条aof记录的丢失。通过上述配置文件,可以得知redis提供了3中aof记录同步选项:
- always:每一条aof记录都立即同步到文件,这是最安全的方式,也以为更多的磁盘操作和阻塞延迟,是IO开支较大。
- everysec:每秒同步一次,性能和安全都比较中庸的方式,也是redis推荐的方式。如果遇到物理服务器故障,有可能导致最近一秒内aof记录丢失(可能为部分丢失)。
- no:redis并不直接调用文件同步,而是交给操作系统来处理,操作系统可以根据buffer填充情况/通道空闲时间等择机触发同步;这是一种普通的文件操作方式。性能较好,在物理服务器故障时,数据丢失量会因OS配置有关。
其实,我们可以选择的太少,everysec是最佳的选择。如果你非常在意每个数据都极其可靠,建议你选择一款“关系性数据库”吧。
AOF文件会不断增大,它的大小直接影响“故障恢复”的时间,而且AOF文件中历史操作是可以丢弃的,AOF rewrite操作就是“压缩”AOF文件的过程,当然redis并没有采用“基于原aof文件”来重写的方式,而是采取了类似snapshot的方式:基于copy-on-write,全量遍历内存中数据,然后逐个序列到aof文件中。因此AOF rewrite能够正确反应当前内存数据的状态,这正是我们所需要的;rewrite过程中,对于新的变更操作将仍然被写入到原AOF文件中,同时这些新的变更操作也会被redis收集起来(buffer,copy-on-write方式下,最极端的可能是所有的key都在此期间被修改,将会耗费2倍内存),当内存数据被全部写入到新的aof文件之后,收集的新的变更操作也将会一并追加到新的aof文件中,此后将会重命名新的aof文件为appendonly.aof,此后所有的操作都将被写入新的aof文件。如果在rewrite过程中,出现故障,将不会影响原AOF文件的正常工作,只有当rewrite完成之后才会切换文件,因为rewrite过程是比较可靠的。
触发rewrite的时机可以通过配置文件来声明,同时redis中可以通过bgrewriteaof指令人工干预。因为rewrite操作/aof记录同步/snapshot都消耗磁盘IO,redis采取了“schedule”策略:无论是“人工干预”还是系统触发,snapshot和rewrite需要逐个被执行。
AOF rewrite过程并不阻塞客户端请求。
二.Snapshot Snapshot,快照,这种思想被广泛的应用在多个技术领域,主要目的就是对当前数据的状态进行保存到文件中,有可能触发实际数据的copy过程,在整个时间线(time-line)上,同一个数据会有多个snapshot时间点(snapshot point),每个时间点都会持有相应的数据状态,可以根据需要,从各个snapshot时间点上恢复(重现)当时的数据,就像“照相”一样,每张照片都是某刻的风景的剪影;snapshot的变种以及实现手段很多,比如cop-on-write,fully-copy,内存级别的fuzzy-snapshot等等。 其中copy-on-write和fuzzy-snapshot在基于内存数据的snapshot中广泛使用.
1) copy-on-write是基于内存数据“指针”复制实现,在snapshot时,首先把“数据”copy一份(指针引用copy,指向同一个实际数据),然后将数据序列化到文件中,如果序列化过程中数据变更,那么将导致实际数据的copy。
A ---> data
SnapshotA ---> data
变更时:
data1 == data (实际数据copy)
A ---> data1
SnapshotA ---> data
结束后:
data = null
2) fuzzy-snapshot:和上述不同的时,此方式不需要引用copy,在snapshot时如果有变更操作,也不会copy数据。比如T1时刻开始snapshot,T2时刻对数据进行了变更,T3时刻snapshot结束,那么snapshot结束时T2时刻的新数据也会被记录在文件中;由此可见这种snapshot并没有正确反应T1时刻的数据状态,而是T1~T3区间(非严格),就像拍照时,人物的移动导致照片“模糊”一样。
废话半天,redis中snapshot最终将内存数据序列化到dump.rdb文件中(参考:redis存储与数据结构),此文件的作用仍然是“故障恢复”。Redis采用了copy-on-write的思路,将内存中数据(K-V,expire,数据结构类型等)以结构化的方式序列化到rdb文件中。snapshot和AOF只不过在一些策略上不同,其实工作原理非常类似。snapshot的主要目的,就是“数据备份”,比如每隔12小时备份一次数据,并把snapshot生成的rdb文件保存起来,我们可以根据rdb文件将数据恢复到任意时间点上。此外rdb文件也是作为master-slave中数据同步的一种手段,一个slave加入集群,那么master(也可以是其他“领导者”,--slaveof指定)将会立即执行一次“例外”的snapshot,并把snapshot期间的新变更操作收集起来(buffer),snapshot结束后,将rdb文件直接转发给slave,同时把收集的新变更操作依次同步给slave。(SYNC指令)
##snapshot触发的时机,save <seconds> <changes>
##如下为900秒后,至少有一个变更操作,才会snapshot
##对于此值的设置,需要谨慎,评估系统的变更操作密集程度
##可以通过“save “””来关闭snapshot功能
save 900 1
##当snapshot时出现错误无法继续时,是否阻塞客户端“变更操作”,“错误”可能因为磁盘已满/磁盘故障/OS级别异常等
stop-writes-on-bgsave-error yes
##是否启用rdb文件压缩,默认为“yes”,压缩往往意味着“额外的cpu消耗”,同时也意味这较小的文件尺寸以及较短的网络传输时间
rdbcompression yes
##rdb文件名称
dbfilename dump.rdb
##rdb/AOF文件存储的目录
dir ./
snapshot触发的时机,是有“间隔时间”和“变更次数”共同决定,同时符合2个条件才会触发snapshot,否则“变更次数”会被继续累加到下一个“间隔时间”上。snapshot过程中并不阻塞客户端请求,copy-on-write方式也意味着极端情况下可能会导致2倍内存的使用量,同时snapshot和aof rewrite一样文件操作也是很快速的。snapshot首先将数据写入临时文件,当成功结束后,将临时文件重名为dump.rdb(参考配置)
snapshot和aof的方式相比,它没有“everysec”文件同步,即在对磁盘文件的操作只会在snapshot时发生,而不是像AOF那样“每次变更”都会触发“文件同步”,从这方面说,snapshot是有优势的。此外snapshot的文件尺寸要比aof小,而且更加结构化,非常便于解析引擎快速解析和内存实施(比AOF要快)。但是因为snapshot的触发实际和“间隔时间”有密切关系,因此server失效后会导致上一个时间点之后的数据未能序列化到rdb文件,这和aof相比,安全性上稍弱。
可以使用bgsave指令手动触发snapshot,即使配置文件中关闭了snapshot(save ""),此指令仍然能够正确生成dump.rdb文件,你可以根据需要将此rdb文件转存到其他地方。
SAVE指令会阻塞Redis服务进程,直到RDB文件创建完毕,在阻塞期间,服务器将不能处理任何请求。BGSAVE命令会派生一个子进程,然后又子进程负责创建RDB文件,服务器进程(父进程)可以继续处理客户端请求。
三.总结:
AOF和snapshot各有优缺点,这是有它们各自的特点所决定:
1) AOF更加安全,可以将数据更加及时的同步到文件中,但是AOF需要较多的磁盘IO开支,AOF文件尺寸较大,文件内容恢复数度相对较慢。
2) snapshot,安全性较差,它是“正常时期”数据备份以及master-slave数据同步的最佳手段,文件尺寸较小,恢复数度较快。
可以通过配置文件来指定它们中的一种,或者同时使用它们(不建议同时使用),或者全部禁用,在架构良好的环境中,master通常使用AOF,slave使用snapshot,主要原因是master需要首先确保数据完整性,它作为数据备份的第一选择;slave提供只读服务(目前slave只能提供读取服务),它的主要目的就是快速响应客户端read请求;但是如果你的redis运行在网络稳定性差/物理环境糟糕情况下,建议你master和slave均采取AOF,这个在master和slave角色切换时,可以减少“人工数据备份”/“人工引导数据恢复”的时间成本;如果你的环境一切非常良好,且服务需要接收密集性的write操作,那么建议master采取snapshot,而slave采用AOF。
1) 如果master失效,那么slave可以人工的方式“提升”为master:
redis 127.0.0.1:6379> config set appendonly yes
OK
redis 127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started
redis 127.0.0.1:6379> SLAVEOF no one
OK
当然可以通过slaveof指令为当前server指定master。提升master的过程,首先开启slave的AOF功能,然后立即执行bgrewriteaof,然后将此slave提升为master。
如果此slave与master之间数据存在很大差异,那么需要把master中的aof文件copy一份到slave中,并重启slave:首先开启slave的appendonly,不执行bgrewriteaof,然后提升master,停止slave,将master的aof文件copy到slave中,然后重启slave。
2) 如果slave失效,这个非常好办,直接重启就行,slave重启后,会首先向master发送“SYNC”指令,那么master将会立即生成一份snapshot文件,并传输给slave,slave根据此snapshot文件恢复内存数据。
3) 在redis中master和slave的角色切换非常简单,可以通过指令将slaveof提升为master,反之亦然;事实上slave也可以接受write操作,只不过这些write操作,在和master进行“SYNC”之后,将会消失;建议将slave作为read-only模式。
4) 在redis中AOF和snapshot可以同时使用,但是在数据恢复时AOF会被优先采用,因为AOF比snapshot中数据更加完整。
在数据恢复时,如果开启了AOF,那么服务器端将优先使用AOF文件恢复数据,否则才会使用snapshot的RDB文件来恢复数据。
四、M-S模式下数据复制
M-S模式下,数据replicated机制也不复杂,不过在redis2.8前后版本稍有不同。旧版本:
1)slave向master发送“SYNC”指令
2)master使用BGSAVE,在后台为此slave生成一个RDB文件,同时使用一个专用的buffer来保存此期间新的变更操作。(BGSAVE基于copy-on-write)
3)master开启子进程,将RDB文件通过网络发送给slave,并将buffer中的新变更记录随后补充发送给slave(直到slave数据全部重放完毕后销毁)。
4)此后,slave接收RDB文件,并在接收时对数据进行内存重放。当数据恢复完毕后,即与master建立同步复制机制。
这种机制,我们称为“全量同步”,即使slave只是简单的网络闪断,它与master之间的数据同步,也是全量的,由此可见,性能稍差。
在redis 2.8之后,redis增加了“增量同步”机制,有点类似于mysql的binlog同步机制(GTID),使用“PSYNC”指令;这个指令兼顾“全量复制”、“增量复制”,即如果slave落后太多,则执行全量复制,如果只是短暂离开,则使用增量复制。这也要求redis在数据存储、同步时,需要有一个offset来标记数据游标的位置、backlog缓冲区、服务器运行ID。
1)master每次向某个slave同步N个字节的数据之后,将与此slave的复制offset值加N。此offset用来标记下一次replication的起始位置。(如果master有多个slave,每个slave均有各自的offset值,这个很好理解)
2)当slave收到master的N个字节数据后,将本地记录的复制offset值加N。当slave与master链接断开后重练时,此offset用来告知master需要replicaiton的起始位置。
3)backlog缓冲区,默认为1M,是一个FIFO队列,全局共享;在master上发生的数据变更,都会写入到backlog缓冲区,同时也会同步给slave。
当从服务器与master建立连接时,会通过PSYNC指令携带本地的offset值(也包括master ID),如果offset的数据仍然在backlog缓冲区中,那么只需要执行增量同步即可,即将backlog中的数据直接同步给slave即可;如果slave指示的offset数据已经从backlog中移除(这也意味着slave离线的时间过长了),此时将指示slave进行全量复制(SYNC)。
所以此时,我们需要评估backlog的大小,以尽可能的避免slave闪断后而全量复制,这个值的大小取决于redis的write操作的密度、slave网络稳定性不良带来的延迟时长。
我们还谈到服务器运行ID,每个redis实例在初始化时都会为自己创建一个server ID,而且此ID一旦创建则不会再改变,而且全局不会重复。在slave与master首次建立连接时,slave会保存master ID,此后,slave与master失去连接后,重连时(包括重新slaveof)将会把offset、master ID发送给master,此后master会判断,slave指示的masterID是否与自己的ID相同,如果相同,则进行增量复制机制(参见上述过程),如果不同,这意味着在slave断开期间,发生了failover、或者slave是迁移到新的master上,此时master将指示slave进行全量复制。
master与slave之间除了数据同步交互,可以判断链接的活性;此外还开启了心跳检测机制,slave会每隔一秒向master发送“replication ack <offset>”心跳检测指令,来判定链接的活性以及与master的数据间隔的步差;如果心跳检测失败,则会导致slave重建链接。
对于master而言,可以通过设置:
min-slaves-to-write 1
min-slaves-max-lag 10
##单位秒
当master持有的slaves个数少于“min-slaves-to-write”时,master将切换为readonly模式,即拒绝客户端的write操作。同样,当“min-slaves-to-write”个数的slaves写入延迟都大于“min-slaves-max-lag”时,master也切换为readonly。
分享到:
相关推荐
【作品名称】:基于servlet+jsp+mysql实现的影视管理系统【课程设计】 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】: 基于servlet+jsp+mysql实现的影视管理系统【课程设计】 基于servlet+jsp+mysql实现的影视管理系统【课程设计】 Java Web课程设计,基于servlet+jsp+ajax+mysql做的影视管理系统 运行环境: Tomcat 9.0 JDK 1.8 MySQL 8.0 后台管理账号密码均为:root,项目依赖:lib 目录 【资源声明】:本资源作为“参考资料”而不是“定制需求”,代码只能作为参考,不能完全复制照搬。需要有一定的基础看懂代码,自行调试代码并解决报错,能自行添加功能修改代码。
kernel-5.15-ky10-x86.tar.gz
【作品名称】:基于AT89C51 单片机为核心器件,程序设计采用C 语言,Keil 软件编译程序,配以相关外围接口电路,实现了方波、锯齿波、正弦波、三角波、梯形波五种特定波形的产生【论文+源码】 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】:本设计中的波形发生器系统要求基于51单片机,因此选用以AT89C51单片机作为整个系统的控制核心,应用其强大的接口功能,构成整个波形发生器的硬件系统。使用C 语言对单片机编程可产生相应的正弦波,方波,三角波,锯齿波梯形波波形信号。在程序运行时,当接收到按键信息后,需要输出某种波形时,调用相应的中断服务子程序和波形发生程序,经电路的数/模转换器和运算放大器处理后,从信号发生器的输出端口输出即可得到要求的波形。 当需要改变频率时只需要改变单片机的波形发生程序中的递增或者递减变量即可。 【资源声明】:本资源作为“参考资料”而不是“定制需求”,代码只能作为参考,不能完全复制照搬。需要有一定的基础看懂代码,自行调试代码并解决报错,能自行添加功能修改代码。
基于java的法律咨询系统设计与实现.docx
适用于元营销 API 的 Python SDK适用于 Python 的 Facebook Business SDK 介绍Facebook Business SDK是一站式服务,可帮助我们的合作伙伴更好地服务于他们的业务。合作伙伴正在使用多个 Facebook API 来满足其客户的需求。采用所有这些 API 并在各个平台上保持最新状态可能非常耗时,而且最终会造成高昂的成本。为此,Facebook 开发了 Business SDK,将其许多 API 捆绑到一个 SDK 中,以简化实施和维护。Business SDK 是 Marketing API SDK 的升级版,其中包括 Marketing API 以及来自不同平台(如 Pages、Business Manager、Instagram 等)的许多 Facebook API。快速入门商业SDK入门指南Python 目前是我们第三方开发人员最常用的语言。是一个 Python 包,它提供了您的 Python 应用程序与Business SDK 内的 Facebook APIfacebook_business之间的
数学建模培训资料 数学建模实战题目真题答案解析解题过程&论文报告 公交车调度的运作数学模型 共12页.pdf
smart-http 是一款可编程的 Http 应用微内核,方便用户根据自身需求进行 Server 或 Client 的应用开发。支持GET、POST的 HTTP 请求。提供了 URL 路由组件,可以快速搭建一套静态服务器。支持部分 RFC2612 规范,后续会逐渐完善。支持 Https 协议,由 smart-socket 为其赋能。具备文件上传的能力。支持 websocket、Cookie支持 Server、Client 开发
新闻资讯系统 微信小程序+SpringBoot毕业设计 源码+数据库+论文+启动教程 项目启动教程:https://www.bilibili.com/video/BV1oiBpYcEBp
高校师生工作室-JAVA-基于微信小程序的高校师生工作室管理系统的设计与实现
基于java的常见小儿疾病中医护理系统设计与实现.docx
本教程播放列表涵盖了 Python 中的数据结构和算法。每个教程都有数据结构或算法背后的理论、BIG O 复杂性分析和可供练习的练习。使用 Python 的数据结构和算法本教程涵盖了 Python 中的数据结构和算法。每个教程都包含数据结构或算法背后的理论、BIG O 复杂度分析以及可供练习的练习。要观看视频,您可以访问播放列表https://www.youtube.com/playlist?list=PLeo1K3hjS3uu_n_a__MI_KktGTLYopZ12订阅 codebasics youtube 频道https://www.youtube.com/c/codebasics
数学建模学习资料 蒙特卡罗方法课件教程 第2章.随机数 共29页.pptx
python实现基于CNN网络的新闻数据集文本分类源码+数据集(Python期末大作业),个人大三学期的期末大作业、经导师指导并认可通过的高分大作业设计项目,评审分98分。主要针对计算机相关专业的正在做大作业的学生和需要项目实战练习的学习者,可作为课程设计、期末大作业。 python实现基于CNN网络的新闻数据集文本分类源码+数据集(Python期末大作业)python实现基于CNN网络的新闻数据集文本分类源码+数据集(Python期末大作业),个人大三学期的期末大作业、经导师指导并认可通过的高分大作业设计项目,评审分98分。主要针对计算机相关专业的正在做大作业的学生和需要项目实战练习的学习者,可作为课程设计、期末大作业。python实现基于CNN网络的新闻数据集文本分类源码+数据集(Python期末大作业),个人大三学期的期末大作业、经导师指导并认可通过的高分大作业设计项目,评审分98分。主要针对计算机相关专业的正在做大作业的学生和需要项目实战练习的学习者,可作为课程设计、期末大作业。python实现基于CNN网络的新闻数据集文本分类源码+数据集(Python期末大作业),个人大
中小学知识产权教育试点学校申报表.doc
基于django的音乐推荐系统.zip
在建工程涉及专项行动情况检查表.docx
本项目是一个基于Python技术的学生管理系统,采用Django框架进行开发,旨在为计算机相关专业的学生提供一个实践性强、功能全面的管理系统,以帮助他们完成毕业设计或进行项目实战练习。 系统实现了对学生信息、课程信息、成绩、考勤等多方面的管理功能。学生信息管理包括学生基本信息的增删改查;课程信息管理允许管理员设置课程信息,包括课程名称、授课老师、学分等;成绩管理功能使学生和教师能够录入、查看和修改成绩;考勤管理则方便教师记录学生的出勤情况。 该项目采用B/S架构,前端使用HTML、CSS、JavaScript等技术,后端使用Python语言和Django框架,数据库采用MySQL。Django框架提供了强大的后台管理功能,使得系统管理更加便捷。 通过开发这个项目,学生不仅能提升自己的编程能力,还能学习到如何构建一个实际应用的系统,对于即将步入职场的学生来说,具有很高的实用价值。
适用于 Python 的 Splunk 软件开发工具包参考文档适用于 Python 的 Splunk Enterprise 软件开发工具包版本 2.1.0适用于 Python 的 Splunk Enterprise 软件开发套件 (SDK) 包含库代码,旨在使开发人员能够使用 Splunk 平台构建应用程序。Splunk 平台是一个搜索引擎和分析环境,它使用分布式 map-reduce 架构来有效地索引、搜索和处理大型时变数据集。Splunk 平台深受系统管理员的欢迎,用于聚合和监控 IT 机器数据、安全性、合规性以及各种其他场景,这些场景都需要有效地从大量时间序列数据中索引、搜索、分析和生成实时通知。Splunk 开发者平台使开发人员能够利用 Splunk 平台所使用的相同技术来构建令人兴奋的新应用程序。开始使用 Python 版 Splunk SDK开始使用 Python 版 Splunk Enterprise SDKSplunk Enterprise SDK for Python 包含库代码,其示例位于splunk-app-examples存储库
分布式事务练习
家庭财务管理系统 微信小程序+SSM毕业设计 源码+数据库+论文+启动教程 项目启动教程:https://www.bilibili.com/video/BV1BfB2YYEnS