当前位置: 首页 > 工具软件 > Tendis > 使用案例 >

redis mysql tendis nginx kafka等中间件

白烨煜
2023-12-01

—-
分布式锁:(一般3种实现方式)
1.数据库乐观锁; 2.基于redis的分布式锁。 3.基于zookeeper的分布式锁。

分布式锁 区分于 进程锁, 线程锁。。
进程锁(系统中多个进程之间对资源使用到的管理)
线程锁(进程中多个线程对资源共享)
分布式锁:分布式系统中多个进程之间互相干扰。用分布式协调技术管理进程调度。(这个技术就是分布式锁)

—-
mysql的并发控制(用到了很多策略)
1.锁
锁的粒度: 表级锁, 行级锁, 页级锁 (越来越细) 不同级别锁 保证冲突。

2.多版本控制(MVCC)
保证只读事务 不用等待锁,提高事务并发性。
每行记录后面保存两个列(行创建时间,行过期时间) 事务也有版本号。

共享锁(又叫读锁):读操作可以并发;
排他锁(又叫写锁):写操作互斥。

—-
使用腾讯 tendis:优势 (基于rdis改版,继承了redis优势,又弥补了redis的不足)
1.也是 k-v存储, k是我们的id, v是数据内容。(很方便)
2.大容量存储,分布式,pb级存储能力,
我们使用性能 p99 30ms左右,

bin log同步,实现主从复制,

缓存和数据库读写一致性的问题

比较好的方案:缓存双删(写之前删缓存, 写之后删缓存(延时1秒),(保证写的过程中 1秒内的脏数据也被清理掉)

nginx:
nginx原理:
会有一个master进程和多个worker进程,master进程主要用来管理worker进程;
当一个连接过来的时候,每一个worker都能接收到通知,但是只有一个worker能和这个连接建立关系,其他的worker都会连接失败,nginx提供一个共享锁accept_mutex,有了这个共享锁后,就会只有一个worker去接收这个连接。当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接。
事件驱动机制:几个worker进程(每一个worker进程里面其实只有一个主线程)能同时接收上万的请求呢?这是因为nginx事件处理机制是异步非阻塞的。(用了epoll,将过程分为多个阶段。)

nginx的作用:

  1. 反向代理,将多台服务器代理成一台服务器,
  2. 负载均衡,将多个请求均匀的分配到多台服务器上,减轻每台服务器的压力,提高服务的吞吐量;
  3. 动静分离,nginx可以用作静态文件的缓存服务器,提高访问速度

—-
数据处理, 大数据相关

1.离线数据流:日常周期性的(每周执行一次、每日、或者每小时),将某些数据源的数据(全量或增量)迁移到存储引擎上(hbase mysql tendis等)。
2.实时数据流(在线):该数据流一直保持运行状态,实时抽取(pull/push)数据源的数据,毫秒级写入存储引擎。

大数据处理 计算框架。(建立一个流程,数据源、处理、分析和计算,还可以训练模型 等等,输出最终结果。 上面可以跑很多任务)

flink: 支持批处理和流处理。
1.高吞吐、低延迟、高性能。(同时支持,spark那边都不行)
2.支持事件时间概念(event time),基于时间事件时间(event time)语义进行窗口计算,时间产生的时间。即使乱序到达,事件乱序到达,流系统也能计算出精确结果。保证时序性。
3.有状态的计算, 中间结果保存,下一时间段进入算子后可以直接用这个结果。
4.灵活的窗口统计功能(多少次内的统计、多少秒内。)
5.分布式快照(checkpoint)
可以分布式运行在上千节点上,大型计算任务分解成一个个小任务,在所有节点上并行处理。(其中节点小任务出现问题,快照保存。自动恢复)
6.独立内存管理。flink自己管理自己的内存,序列化为二进制内存存储。(不会让gc带来性能下降等等)


数据库三大范式:
为了建立冗余较小、结构合理的数据库,建立一些规范标准,常用于关系数据库。
1.第一范式:最基本的范式,确保每列保持原子性,数据库表中所有字段值都是不可分解的原子值,
2.第二范式:确保表中每列都和主键相关,一个表中只存一种数据,保证减少冗余。
3.第三范式:确保表中每列都和主键直接相关,而不是间接相关。(进一步的解耦、独立。)

缓存命中率:
缓存查询次数中,得到正确结果的次数,叫做命中率。缓存命中率=缓存命中次数/缓存查询请求次数。(命中率越高,缓存的使用率越高)。
缓存:一次写入,多次读出。(适合高频读 低频写的应用场景)
影响缓存命中率的三个因素:1.缓存键集合大小,2.内存空间大小,3.缓存寿命。

redis:
优势:1.支持数据持久化,写入磁盘,重启时重新加载再次使用;2.支持的数据类型丰富,key-value,还有list,set,hash等等;3.支持数据备份,master-slave 主从模式的备份。
1.读写查询的性能特别高,2.原子性,单个操作都是原子性的,多个操作也支持事务,multi和exec包起来。 3.丰富的特性,支持消息队列 分布和订阅,通知机制 和 过期机制。

redis做缓存的缺点: 常见的那些问题都算是缺点
1.缓存和数据库不一致;
2.缓存雪崩、击穿、
3.物理内存受限(海量数据受限)
4.在线扩充不灵活,一般都尽量保证单台内存够用。
5.主从机数据不一致,宕机时 主机同步从机时。
6.没有自动容错和恢复功能,主从宕机时 就无法完成请求。

redis的zset:叫做有序集合,每个元素都带一个分数,底层实现用的跳跃表。。
set是无序的,

延时队列:进入该队列的消息,会被延迟消费的队列。(一般队列,消息一旦入队,就会被立马消费) zset实现延时队列:score为时间戳,有序队列,轮询时 达到执行时间就执行。

map等编程语言的数据结构 也叫做缓存,本地缓存。
redis:可以分布式缓存,多实例时,各个实例共用一份缓存数据,缓存一致性。(前提要保证服务高可用)

redis是单进程单线程的,利用队列技术把并发访问变为串行访问,消除传统数据库对串行控制的开销。(没有进程线程的切换,不需要考虑锁的问题

redis持久化:内存数据库,内存数据变化快,容易丢失,需要持久化。
两种持久化方案:
1.RDB(Redis DataBase)默认的持久化方案;指定时间间隔内,执行指定次数的写操作,将内存数据写入到磁盘。dump.rdb文件。 redis重启时会加载dump.rdb文件来恢复数据。

是一种数据集快照的方式,半持久化记录redis的所有键值对,某个时间点的数据写入临时文件,持久化结束,把临时文件替换上次持久化的文件。
rdb优点:只有一个rdb文件,方便持久化;安全的保存在磁盘中。容灾性好;性能好,fork子进程来执行写操作,主进程只处理IO;重启加载效率高。
缺点:持久化过程中 redis故障,会发生数据丢失。适合对数据要求不高的场景。

2.AOF(Append Only File)(为了弥补rdb的不足,弥补数据不一致性)
所有命令行记录以redis命令请求协议的格式来完成持久化存储, 用日志形式来记录每个写操作,并追加到文件中,redis重启时根据日志文件的内容将写指令从头到尾执行一遍,来恢复数据。

优点:数据安全,append形式,记录都能保留。(记录可以合并重写并删除)
缺点:aof文件比rdb文件大,恢复速度慢。启动效率低。

redis缓存和数据库一致性的问题:
1.缓存设置过期时间,数据以数据库为准,
主要是数据更新操作,(主要不一致是 缓存里的旧数据,mysql主从机制不一致)
方案1:延时双删(数据库写操作之前删,写操作完成也删)
方案2:主动加载。

内存中的数据结构存储系统,可以用作数据库、缓存、消息中间件。
k-v字典存储系统,跨平台的非关系型数据库。
支持网络、基于内存、分布式、可选持久化。

LRU驱动事件,事务,不同级别的磁盘持久化。
常见的缓存算法。
(1)(LRU,Least Recently Used,最近最少使用,看的!!时间戳!!)算法。缓存中也常使用。。(!!!应用最广的缓存淘汰策略,实现简单,很实用,运行性能高,命中率高!!!)
最近经常被访问的数据,在以后也会经常被访问,经常被访问的数据,需要快速被命中,不常访问的数据,超出容量时要将其淘汰。
实现细节:(1)最近访问的数据插入或置换到缓存队列靠前的位置,(2)优先淘汰队列最末尾的字段。
实现数据结构和算法:链表 + map,map的key,value来保存数据内容;链表用来维护缓存队列。

(2) LFU,Least Frequently Used,最不经常使用,看的是频率),最近一段时间内的访问次数,
(3) FIFO(先进先出),最先进入缓存中,最先被淘汰。

缓存穿透:缓存和数据库中都没有的数据,用户不断的发起请求(我们搜索服务应该不存在这种情况)解决方法:对请求接口做校验,不合法的直接拦截。

缓存击穿:缓存没有命中但是数据库中有数据(一般指缓存到期)解决方法:热点数据永不过期(搜索频率很高的设置为不会过期)(并发查一条数据)

缓存雪崩:缓存中数据大量都到了过期时间,查询量大 都查询不到。(很多数据都查不到)
解决方法:热点数据永不过期,过期时间设置随机。

缓存管理策略:
缓存淘汰策略:过期的,最少使用的删除掉。(LRU)

缓存更新策略。保证缓存内容和db数据内容一致。(低峰时期,对缓存内容批量更新)另外,db数据更新,也有一致性策略、保证缓存和db的一致性。(缓存索引非耦合策略,缓存逐步过期,减少不一致的项)

读和写操作都是并发的,没法保证顺序,就会出现缓存和数据库不一致的问题。

redis哨兵(sentinel), 自动分区。

哨兵模式(sentinel):哨兵系统可以监控一个或多个redis master服务,以及从服务,某个master下线后,自动将该master从服务升级为master来代替。


redis发布(publish)-订阅(subscribe), 一种消息通信模式,发送者(pub)发布消息,订阅者(sub)接收消息.
新消息通过PUBLISH命令发送到频道channel中时,这个消息就会被发送给订阅它的所有客户端。
redis stream: 用于消息队列(MQ, Message Queue), 提供消息持久化,主备复制功能,

—————-
MQ(Message Queue),常叫做消息中间件、分布式消息队列
存放消息的容器,需要使用消息的时候取出来供自己使用。
分布式项目中,MQ基本都是必备消息中间件。 常用的消息中间件有:Kafka、
目的:(1)异步处理,高峰时刻提高系统性能和削峰,(2)降低系统耦合(异步处理:减小高并发的压力。
1.解耦:消息发送端和消息接收端是模块独立的。互不影响。消息队列某个机器宕机,也可以继续用集群中的其它机器做消息队列服务。
2.异步处理:业务逻辑以同步方式运行,很耗费时间;MQ中,用户请求发送到消息队列中就立刻返回;消息接收端拿到数据也是异步消费执行。消息队列的处理速度也很快。
3.削峰:主要是通过异步处理达到削峰目的。短时间高并发产生的事务消息放到消息队列中,削平高峰期的并发事务。

MQ消息队列的缺点:
1.系统可用性降低:引入了一个新模块,消息丢失 mq挂掉,
2.系统复杂性提高:重复消费、消息丢失、消息顺序。。
3.一致性问题:是异步的。。生产的消息没有被正确消费。。


kafka架构: 底层基于zookeeper,部署2N+1个节点,形成zookeeper集群,保证高可用。
kafka prodcuer: 从zookeeper拉取topic的leader分区,写入消息。
kafka broker: 每个topic的partition,会有副本,保证消息存储的可靠性。副本选择leader的partition(给producer和consumer使用),只读写leader分区。
kafka consumer:从topic的leader分区读取消息。

所有MQ中间件,都会有消息重复消费的问题存在。
如何解决重复消费的问题:
(1) kafka层面的解决:offset的概念,写入的每一个消息都有一个offset,消费时,提交offset,证明该消息已经被消费。下次继续从当前位置开始继续消费。。
(2)业务层面的解决:自己做是否重复的校验,比如写入数据,判断是否已经在数据库里了。。等等, 唯一的id。。消息id加锁。。

数据丢失问题:(常用的解决方案 以kafka为例)

  1. 生产者和broker弄丢数据。
    (1) ack机制(确认机制),生产者发送消息,broker中leader分区和所有follower都要进行确认没问题,才回复ok;否则,生产者会一直重试发送。
    (或者,其它MQ中间件用的方法:保存到本地磁盘。。。)
    2.broker挂了。
    保证leader的follower多于2个,都数据同步成功。写入失败,就一直重试。
    3.消费端丢失数据。
    原因是:消费了提交了offset,机器挂了。。
    解决方案:关闭offset提交(就会认为数据还没消费),等自己处理完手动提交offset即可。。(会有重复消费情况,自己业务上保证数据一致,幂等性)

消息中的顺序性保证:
原因:多个消费端在消费,执行速度可能不太一样。。
内存中N个队列queue,指定key,相关的数据都是相同的key,写到同一个队列中,消费的时候同一个队列用单线程消费。(内部有序)

常用Kafka优点
核心功能强大,吞吐量高,ms级延迟,高可用可靠性,分布式任意拓展, 存在消息重复消费。。

———-
缓存服务

pika:
360开发的一个类redis存储系统,完全支持redis协议,
pika针对redis的一些问题而进行的优化
(redis内存限制、主从高可用问题、启动恢复时间长、缓冲区容易写满)

pika优势在于多线程, redis单线程性能厉害。

etcd 和 redis都是键值存储库
etcd:核心在于分布式存储,强调各个节点之间通信、同步,确保各个节点上数据和事务的一致性。 服务发现工作更稳定,单节点的读写能力可能并不强。

redis:内存型缓存,节点一致性主要是数据,读写能力很强。qps达10w+

redis:缓存能力很强,mysql缓存、多级缓存,
etcd:主要做一些事务管理,基础架构服务、容器类服务部署。

———————-
mysql:

MvCC(多版本 并发控制)。Multi Version
https://cnblogs.com/chinesern/p/7592537.html

为啥用b+树:
1.肯定是为了提高查询效率。
b+树磁盘读写代价更低:数据都在叶子节点,其它节点存储更多的键,树的高度很小。(1-3次)
b+树查询效率更稳定:任何查询都必须从根节点走到叶子节点,路径长度相同。
叶子节点数据之间用指针链表 连起来,可以查到所有数据,可以进行范围查询range
innodb:是mysql的数据库内部引擎,用了这个才能支持事务。 内存存储引擎, 页是管理数据的最小磁盘单位,b-tree节点就是实际存放表数据的节点,
1.支持ACID,支持事务完整性和一致性。
2.支持行锁,一致性读,多用户并发。
3.聚集索引 主键设计方式, 大幅提升并发读写性能。

mysql数据都在磁盘中,为了提高速度,用了缓冲池
undo页:实现事务原子性,用来实现多版本并发控制(MVCC),任何操作之前数据备份的地方,方便回滚
InnoDB体系架构:
1.后台线程(主要负责刷新内存池中的数据,将已修改的数据刷新到磁盘)
(1.master thread,主线程,将缓冲池数据异步刷新到磁盘,保证数据一致性,脏页刷新、合并插入缓冲、UnDo页回收;2.IO thread:大量属于异步IO来处理写IO请求;3.purge thread(清理线程):回收已经使用并分配的undo页。

2.内存池(多个内存块,组成一个很大的内存池)
一个innodb页有7个部分组成:
fil header/fil trailer

page header/page dictionary:页的状态信息
dictionary:存储稀疏索引,

user records:页面里 真正存放行记录的部分,
free space:空余空间。 链表结构(从左到右寻找空白节点插入)
b+树查找, 内存中进行。

慢查询:日志记录运行比较慢的sql语句,(记录下来之后可以方便定位优化查询效率)非常有用的日志。
sql优化: 1.修改sql写法, 2.新增索引。
将字段分解成多个表;增加中间表;分解关联查询。 覆盖索引。。。

各种索引:
全文索引:参考es里的term倒排索引
主键索引:主键是一种约束,主键创建后相当于一种唯一索引,(不允许为空,可以被其它表引用为外键;适合 自动递增列,身份证号,
唯一索引:不一定是主键索引。(允许为空)

索引:mysql索引大大提高检索速度
索引优化,是提高查询性能最重要的手段。(查询时每次只能用1个索引)

索引的作用:大大减小服务需要扫描的数据量,大大加快数据检索速度,随机IO变成顺序IO。

——-
mysql日志有哪些:
1.redo log(重做日志), 2.undo log(回滚日志), 3.bin log(二进制日志), 4.slow query log(慢查询日志), 5.relay log(中继日志)
redo log:记录事务执行后的状态,
https://cnblogs.com/myseries/p/10728533.html
(mysql日志)
mysql锁的级别: 表级锁, 页级锁, 行级锁。
https://blog.csdn.net/zcl_love_wx/article/details/81983267

mysql的老版本, myISAM是默认引擎(但是不支持事务及行级锁,
innodb存储引擎:使用b+树建立索引,关系数据库中最常用的
(b+树并不能找到给定键对应的具体值,只能找到数据行对应的页,整个页读入内存,在内存找到具体数据行)
b+树是平衡树,查找任意节点耗费时间都是完全相同的,比较次数就是b+树的高度。
数据库中b+树索引分为聚集索引(clustered index)和辅助索引(secondary index),

聚集索引 存放一条行记录的全部信息。(物理地址连续存放的索引,取区间时,查找速度非常快,使用链表)

辅助索引:只包含索引列和一个用于查找对应行记录的书签。(存的是主键索引,提高某个字段值查询的效率,辅助索引通过牺牲空间来提高查询效率,会浪费空间,合理创建辅助索引)
主键 看作是 聚集索引,如果没有创建,系统自动创建一个隐含列为表的聚集索引。

———
主从同步:
减轻服务器处理海量并发访问,产生的性能问题。
1.master主机器,将对数据的操作记录写到二进制日志中(binary log),mysql将事务串行的写入;
2.slave(备份机器)将二进制日志(binary log) 拷贝到中继日志(relay log)。 slave机器开启一个工作线程 io线程。
然后slave和 master保持一致。

需要中继:bin log不能一口气存到io线程,relay log缓存bin log事件。

———-
读写分离:
master 主机器 只用来进行写操作(主机器创建一个用户,只进行写,给予对应权限)
slave 备份机器 只用来进行读操作。
(通过路由,进行读写分离,

———
分布式事务:
mysql本身支持分布式事务,有限支持。
主要解决:分布式数据库场景下 所有节点间数据一致性问题。(通常采用2PC协议),分布式中会存在部分节点提交失败的情况。(所有节点都能提交时,整个分布式事务才允许被提交)

分布式事务通过2PC协议 将提交分为2个阶段:
1.prepare
2.commit/rollback

mysql 并发控制:

乐观并发控制(默认不出问题。遇到了问题了就重试,写的时候看是否被其他修改了, 整个过程中就没有枷锁。)乐观锁不会死锁, 但是冲突和重试过多时,增加负担,最好用悲观锁。

响应速度要求很高,并发量很大时,推荐乐观锁。(这时悲观锁会有性能问题。)

悲观并发控制(最常见的方法,就是锁)
共享锁,排他锁,两种实现方式。实现了标准的行级锁。

多版本并发控制

并发控制要考虑:冲突频率、重试成本、响应速度和并发量。

——————
事务相关
一件事情有n个组成单元,一起成功 或者一起失败,n个组成单元放在一起,就是一个事务。。

mysql:一条sql语句就是一个事务。。 默认开启事务并提交事务。。

开启事务,事务提交, 事务回滚。。

事务特性:ACID,
原子性(事务是一个不可分割的单位,全部发生、全部不发生)
、一致性,(事务前后 数据完整性必须保持一致)
隔离性,)多个用户并发访问,一个用户的事务不能被其他用户的事务干扰,互相隔离)
持久性,(事务被提交,对数据的改变是永久性的,即使故障也不能有影响)

事务的四种隔离级别
1.read uncommited,读取尚未提交的数据(哪个问题都解决不了)
2.read commited,读取已经提交的数据(可以解决脏读)
3.重复读取,Repeatable Read(解决脏读和不可重复读)mysql默认。(这个隔离级别可以解决了幻读问题)读的都是快照读。
(不可重复读,指一个事务中多次读同一数据 结果出现不一致)
4.串行化,可以解决脏读,不可重复读,虚读,相当于锁表。

(幻读,一个事务中使用相同的sql,两次读取,第二次读取到了其他事务新插入的行)
——
zab(zookeeper内部的分布式协调功能)
https://blog.csdn.net/a724888/article/details/80757503
zab协议, zookeeper根据zab协议实现分布式系统数据一致性。
写入一条数据,到遵循zab一致性,的整个流程:
1.客户端发起写操作请求,
2.


Flink:
火热的大数据处理框架,天然的流式计算,强大的处理性能。
优势:数据分布、容错处理、资源管理。。
工作流程: 创建job, -> 工作环境(environment) -> 数据源(source) ->数据处理transform -> 保存数据。
1.Flink统一批数据(有边界的数据)和流数据(无边界的数据)(流数据应用更广泛)
Flink是标准的实时处理引擎,基于事件驱动。
Spark:是微-批处理引擎。


Flink 和 Spark的区别:
1.架构层面: (1)Flink: job管理, task管理,slot ; (2)Spark: master, worker, driver, executer.

容错机制:(1)spark设置checkpoint,故障重启从checkpoint恢复,保证数据不丢失,danshi可能会重复处理。(2)Flink使用两个阶段提交来保证容错。

https://zhuanlan.zhihu.com/p/142439942

 类似资料: