Redis网络模型全面揭秘
Redis网络模型用户空间和内核态空间服务器大多都采用Linux系统,这里我们以Linux为例来讲解:
ubuntu和Centos 都是Linux的发行版,发行版可以看成对linux包了一层壳,任何Linux发行版,其系统内核都是Linux。我们的应用都需要通过Linux内核与硬件交互
用户的应用,比如redis,mysql等其实是没有办法去执行访问我们操作系统的硬件的,所以我们可以通过发行版的这个壳子去访问内核,再通过内核去访问计算机硬件
 计算机硬件包括,如cpu,内存,网卡等等,内核(通过寻址空间)可以操作硬件的,但是内核需要不同设备的驱动,有了这些驱动之后,内核就可以去对计算机硬件去进行内存管理,文件系统的管理,进程的管理等等
我们想要用户的应用来访问,计算机就必须要通过对外暴露的一些接口,才能访问到,从而简介的实现对内核的操控,但是内核本身上来说也是一个应用,所以他本身也需要一些内存,cpu等设备资源,用户应用本身也在消耗这些资源,如果不加任何限制,用户去操作随意的去操作我们的资源,就有可能导致一些冲突,甚至有可能导致我们的系统出现无法运行的问题,因此我们需要把用户和内 ...
Redis通信协议-RESP协议
Redis通信协议-RESP协议Redis是一个CS架构的软件,通信一般分两步(不包括pipeline和PubSub):
客户端(client)向服务端(server)发送一条命令
服务端解析并执行命令,返回响应结果给客户端
因此客户端发送命令的格式、服务端响应结果的格式必须有一个规范,这个规范就是通信协议。
而在Redis中采用的是RESP(Redis Serialization Protocol)协议:
Redis 1.2版本引入了RESP协议
Redis 2.0版本中成为与Redis服务端通信的标准,称为RESP2
Redis 6.0版本中,从RESP2升级到了RESP3协议,增加了更多数据类型并且支持6.0的新特性–客户端缓存
但目前,默认使用的依然是RESP2协议,也是我们要学习的协议版本(以下简称RESP)。
在RESP中,通过首字节的字符来区分不同数据类型,常用的数据类型包括5种:
单行字符串:首字节是 ‘+’ ,后面跟上单行字符串,以CRLF( “\r\n” )结尾。例如返回”OK”: “+OK\r\n”
错误(Errors):首字节是 ‘-’ ,与单行字符串格 ...
详解Redis底层数据结构
Redis数据结构动态字符串SDS我们都知道Redis中保存的Key是字符串,value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。
不过Redis没有直接使用C语言中的字符串,因为C语言字符串存在很多问题:
获取字符串长度的需要通过运算(因为有一个’\0’)
非二进制安全(也就是说不能包含’\0’,但是可能会有需求在字符串中假如\0这个字符)
不可修改
Redis构建了一种新的字符串结构,称为简单动态字符串(Simple Dynamic String),简称SDS。例如,我们执行命令:
那么Redis将在底层创建两个SDS,其中一个是包含“name”的SDS,另一个是包含“虎哥”的SDS。
Redis是C语言实现的,其中SDS是一个结构体,源码如下:
你可以发现他有两个长度,一个是已保存的字符串字节数,另一个是申请的字节数,这两个是不一样的。
需要注意的是,上面的结构体只是sds的其中一种结构体,是存储8个位的,能存储255个字节,如果字符串超过255了,会转换成其他的sds结构体,比如这些:,这样做的好处就可以节约很多内存,大部分的字符串都不 ...
Redis的两种持久化方式
Redis持久化Redis有两种持久化方案:
RDB持久化
AOF持久化
RDB持久化RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。快照文件称为RDB文件,默认是保存在当前运行目录。
执行时机RDB持久化在四种情况下会执行:
执行save命令
执行bgsave命令
Redis停机时(会默认保存数据)
触发RDB条件时
并且在redis服务器启动时,会自动去读取之前存储的RDB文件加载到redis中
1)save命令
执行下面的命令,可以立即执行一次RDB:
save命令会导致主进程执行RDB,这个过程中其它所有命令都会被阻塞。只有在数据迁移时可能用到。
2)bgsave命令
下面的命令可以异步执行RDB:
这个命令执行后会开启独立进程完成RDB,主进程可以持续处理用户请求,不受影响。
3)停机时
Redis停机时会执行一次save命令,实现RDB持久化。
4)触发RDB条件
Redis内部有触发RDB ...
分布式锁-redission
分布式锁-redission分布式锁-redission功能介绍基于setnx实现的分布式锁存在下面的问题:
重入问题:重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中,可重入锁的意义在于防止死锁,比如HashTable这样的代码中,他的方法都是使用synchronized修饰的,假如他在一个方法内,调用另一个方法,那么此时如果是不可重入的,不就死锁了吗?所以可重入锁的主要意义是防止死锁,我们的synchronized和Lock锁都是可重入的。
不可重试:是指目前的分布式只能尝试一次,我们认为合理的情况是:当线程在获得锁失败后,他应该能再次尝试获得锁。
超时释放:我们在加锁时增加了过期时间,这样的我们可以防止死锁,但是如果卡顿的时间超长,虽然我们采用了lua表达式防止删锁的时候,误删别人的锁,但是毕竟没有锁住,有安全隐患
主从一致性: 如果Redis提供了主从集群,当我们向集群写数据时,主机需要异步的将数据同步给从机,而万一在同步过去之前,主机宕机了,就会出现死锁问题。
那么什么是Redission呢
Redisson是一个在Redis的基础上实现的Java驻内存数据网 ...
盘点Mysql中常见的日志
盘点Mysql中常见的日志错误日志 错误日志是 MySQL 中最重要的日志之一,它记录了当 mysqld 启动和停止时,以及服务器在运行过 程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看此日志。 
该日志是默认开启的,默认存放目录 /var/log/,默认的日志文件名为 mysqld.log 。查看日志位置:  show variables like '%log_error%'; 
二进制日志MySQL主从复制的核心就是二进制日志,因为他记录了所有的DDL和DML语句,有了这些语句我们就可以创建数据库表并且添加数据了 
 二进制日志(BINLOG)记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,但不包括数据查询(SELECT、SHOW)语句。
作用:
灾难时的数据恢复
MySQL的主从复制
在MySQL8版本中,默认二进制日志是开启着的 show variables like '%log_bin%';
参数说明:
log_bin_basename:当 ...
深入理解InnoDB存储引擎
深入理解InnoDB存储引擎逻辑存储结构 InnoDB的逻辑存储结构如下图所示: 
 从大到小依次是:
1)表空间
表空间是InnoDB存储引擎逻辑结构的最高层, 如果用户启用了参数 innodb_file_per_table(在8.0版本中默认开启) ,则每张表都会有一个表空间(xxx.ibd),一个mysql实例可以对应多个表空间,用于 存储记录、索引等数据。
2). 段
段用来管理多个Extent(区)。分为数据段(Leaf node segment)、索引段(Non-leaf node segment)、回滚段(Rollback segment)
数据段就是B+树的叶子节点
索引段即为B+树的非叶子节点。
3). 区(这个没法抽象成我们要看到的)
区,表空间的单元结构,每个区的大小为1M。 默认情况下, InnoDB存储引擎页大小为16K, 即一个区中一共有64个连续的页。
4). 页
页,是InnoDB 存储引擎磁盘管理的最小单元,每个页的大小默认为 16KB。为了保证页的连续性,InnoDB 存储引擎每次从磁盘申请 4-5 个区。
5). 行
行,InnoDB 存储引擎 ...
详解MySQL锁
详解MySQL锁锁是计算机协调多个进程或线程并发访问某一个资源的机制。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。
 MySQL中的锁,按照锁的粒度分,分为以下三类: 
全局锁:锁定数据库中的所有表。 
表级锁:每次操作锁住整张表。 
行级锁:每次操作锁住对应的行数据。
全局锁全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML语句(insert、delete、update),DDL语句(CREATE、ALTER、DROP和TRUNCATE),前面两种语句的所有更新操作的提交语句都将被阻塞。 
其典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,保证数据的完整性。
那为什么全库逻辑备份,就需要加全就锁呢?  
我们一起先来分析一下不加全局锁,可能存在的问题。 
假设在数据库中存在这样三张表: tb_stock 库存表,tb_order 订单表,tb_orderlog 订单日志表。
在进行数据备份时,先备份了tb_stock库存表 ...
SQL优化最干货总结
SQL优化最干货总结插入数据insert如果我们需要一次性往数据库表中插入多条记录,可以从以下三个方面进行优化。  
进行批量插入数据  Insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry'); 
手动控制事务
start transaction;insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');insert into tb_test values(4,'Tom'),(5,'Cat'),(6,'Jerry');insert into tb_test values(7,'Tom'),(8,'Cat'),(9,'Jerry');commit;
主键顺序插入,性能要高于乱序插入
主键乱序插入 : 8 1 9 21 88 2 4 15  ...
索引设计(前缀索引)
索引设计(前缀索引)当字段类型为字符串(varchar,text,longtext等)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘IO, 影响查询效率。
此时可以只将字符串的一部分前缀(因为这一部分前缀就可以进行区分大部分数据了),建立索引,这样可以大大节约索引空间,从而提高索引效率。  
语法:create index idx_xxxx on table_name(column(n)) 
可以这样想,一个表中的一个字段通过前5位就能唯一标识一条数据,那为什么要比较后面的了呢,前缀索引其实就是这个思想。
那我们怎么知道前几位就能区分数据呢,可以根据索引的选择性来决定
索引的选择性
选择性是指不重复的索引值(基数)和数据表的记录总数的比值, 索引选择性越高则查询效率越高, 唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。  
select count(distinct substring(email,1,5)) / count(*) from tb_user ; --得到前5位数字并且进行去重得到的数量/总数,如果这个值很接近1,就说明可以用前5 ...

