自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(128)
  • 收藏
  • 关注

原创 redis 常见数据类型实现原理

redis 常用的数据结构有以下五种:- String- List- Hash- Set- Sorted Set之前简单的介绍了 String 实现原理 SDS,本篇我打算从全局层面一起介绍:无论什么类型的数据结构,在 Redis 中都可以通过 RedisObject 来表示,该类型主要包含以下三个属性:- type:类型,对应上面提到五种数据类型,如:REDIS_STRING、REDIS_LIST 等等- encoding:编码格式- ptr:指针,指向具体的数据类型Red

2021-09-19 17:13:07 704

原创 简单认识 MySQL 分库分表

本篇我打算简单整理一下关于 MySQL 分库分表的基础知识分库:将单个数据库拆分成多个数据库的过程分表:将单张表拆分为多张表的过程总得来说分库分表的原因主要有以下几种:提高性能,增加并发量,增加安全性提高性能是说单张表数据量太大时,数据库查询效率变低,通过拆分数据的方式提高查询性能增加并发量是说单个 MySQL 实例最多支持 2000 左右的并发量,一般超过 1000 数据库就已经很危险了,所以可以通过拆分多几个 MySQL 实例,通过分流的方式减少单个实例上的压力,防止高并发流量直接将数据库

2021-09-14 00:17:58 334

原创 红黑树简单介绍

红黑树是二插平衡树的再优化,二插平衡树强制要求左右子树高度差不能超过1,并且它的左右子树也得是二插平衡树。这就导致每次添加、删除元素时需要大量的操作保持树的平衡,红黑树在其基础上优化,它不强制要求高度差必须小于1,但也尽可能保证树相对平衡,查询效率也高首先红黑树需要满足以下几条规则:1. 节点非黑即红2. 根节点必须黑色3. 每个叶节点(不是叶子节点,页节点值 NIL 或空节点)必须是黑色4. 每个红色节点的两个子节点必须是黑色5. 从任一节点到每个叶节点所经过的黑色节点数目相同也就是说

2021-09-12 09:08:55 274

原创 redis 分布式锁常见问题

上篇博客我简答介绍了 redis 常见加解锁的操作,本篇我计划整理出其中可能导致的问题:一般情况下 redis 分布式锁都是这样使用的:// 加锁操作cacheService.lock(key , timeout);// 业务逻辑xxx// 解锁操作cacheService.unlock();绝大多数情况下都没有问题,但可能存在如下情况:业务逻辑执行时间过长,锁自动失效了。如果锁失效,就有可能导致并发问题一般情况下都是通过设置 timeout 值大于业务逻辑执行时间来解决,但总得来说这不

2021-09-08 23:44:47 652

原创 关于线上常用的几种线程池配置

线程池可以帮助我们省去创建、回收线程所带来的资源消耗,这也是目前使用线程池的主要原因:下面我根据线上业务依次分析常见的几种线程池并给出个人理解:SingleThreadPool:无界队列,核心线程、最大线程都为 1特点:只有一个线程,阻塞队列使用 LinkedBlockingQueue,链表无界。优点在于保证顺序我个人不推荐使用这种线程池,首先它的应用场景很少,单个线程也无法发挥多核的优势。只适合用于一些边缘业务,不重要也不考虑稳定性的场景可以通过这个线程池慢慢跑如果只是为了保证顺序,我更倾向

2021-09-08 22:59:01 378

原创 缓存一致性问题续

在前面的博客中,我有介绍过缓存一致性问题。本篇我打算详细分析各种情况,给出最优的解决方案:其中保证缓存一致性问题常有以下四种方式:1. 先更新缓存,再更新数据库2. 先更新数据库,再更新缓存3. 先删除缓存,再更新数据库4. 先更新数据库,再删除缓存场景一和场景二很少使用,因为都存在脏数据的可能性。导致原因基本类似:先进行的操作成功,但后进行的操作失败。一般线上更多使用场景三或者场景四对于场景三,单线程场景下可以保证缓存一致性,但多线程场景下仍有可能出现脏数据情况:线程a 是写请求

2021-09-08 21:44:34 70

原创 MySQL 索引原理

B 树实际都是从 AVL 树演化而来的,AVL 树由于二叉树的原因,总是不能摆脱每个节点只能保存一条数据的情况,查询效率总是 log2n,整体效率不高,在这种场景下提出了多叉树,减少磁盘 I/O 寻址次数,提高效率B 树实际就是 B- 树,这块是由于翻译问题...

2021-09-04 17:34:42 94

原创 MySQL 主从复制

一般情况下,线上每个 Redis 实例都包含从库,用来做读写分离,减轻主库的压力MySQL 的主从复制默认是异步的,其主要流程如下:1. 从节点的 I/O 线程连接主节点,并请求指定 bin log file 指定 position 之后的日志内容2. 主节点收到请求后,读取并返回。返回信息除了包含日志内容外还包含 bin log file 信息和 position 信息3. 从节点的 I/O 线程收到返回后,将接收到的日志内容更新到 relay log,并将 bin log file 信息和

2021-09-04 15:49:46 63

原创 InnoDB 四大特性

InnoDB 四大特性如下:1. 插入缓存,Insert buffer2. 二次写,double write3. 自适应哈希索引,adaptive hash index4. 预读,read ahead-- --插入缓存索引数据存储在磁盘上,主键索引由于天然自增,无须磁盘的随机 I/O,只需不断追加即可。但普通索引大概率无序,默认情况下需要进行随机磁盘 I/O 操作,效率极差为了解决普通索引插入效率低下的问题,InnoDB 存储引擎引入 Insert Buffer 的概念,对于普通索

2021-09-04 15:30:17 4215 1

原创 MySQL 三大范式

MySQL 三大范式属于一组规则,方便开发人员建立冗余小,结构合理的数据库第一范式:每一列都是不可再分的最小单位举个例子:某网购平台用户信息表通过地址字段记录客户地址,如陕西省西安市雁塔区XXX。系统为了按区域推荐商品需要多次获取用户所在省份,而省份信息实际在地址字段中已经保存过,但该字段还包含所在城市、小区等其它信息。此时也就说该字段不满足第一范式,实际可以将它拆分为三个字段:省、市、详细地址第二范式:每一列都与主键全部内容相关,而不是主键某一部分第二范式在第一范式的基础了做了增强,举个例子:订单

2021-08-24 23:38:38 127

原创 I/O 多路复用技术概述

最开始,传统的 socket 模型效率极差,下面我通过伪代码描述整个过程:// 创建网络套接字s = socket();// 绑定端口及其它配置信息bind(s);// 开启监听listen(s);// 循环建立连接while (true) { // 建立连接 c = s.accept(listenfd); // 读取数据 int data = read(s, buf); // 处理数据 doSomethind(buf); // 断开连接 close(s);}...

2021-08-18 23:09:55 157

原创 从操作系统层面理解同步、异步、阻塞、非阻塞

同步和异步描述调用者会不会主动等待函数的返回值,举个例子:public void method() { int result = otherMethod();}像上面这种形式就叫同步,result 会一直等待 otherMethod() 方法执行完毕并拿到返回值public void method() { new Thread(() -> { int result = otherMethod(); });}像上面这种形式就叫异步,主线程不会等待 otherMethod() 方

2021-08-18 11:00:05 476 1

原创 二叉树类简单介绍

二叉树:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树完全二叉树:一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i 的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树满二叉树:在二叉树的基础上,满二叉树满足:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树二叉查找树(二叉搜索树、二叉排序树)二叉查找树

2021-08-17 10:26:57 263

原创 redis cluster 如何解决批量处理问题

redis cluster 集群模式下执行批量处理命令会报错,具体原因如下:不同的 key 计算出的 slot 槽不一样,不同槽可能对应到不同节点,也就是说批量操作实际很可能被均分到不同的 redis 实例上,对于这种情况,redis cluster 没法处理,直接报错一般情况下有以下三种解决方法:1、别用批量处理命令,老老实实一条一条执行。怎么说呢,这种方式最简单,也最没有人用,因为根本不算解决方案,适合对性能要求不太高的场景2、在客户端计算槽,根据槽判断对应 key 属于那台 redis 实例,直

2021-08-16 22:05:41 1120

原创 redis 管线化 Pipeline

redis Pipeline 常用来解决批量处理问题:redis 只支持部分批量处理逻辑,对于其它绝大多数批量处理需要循环遍历依次执行,使用 Pipeline 就可以将多个命令封装再一起,一起发送给 redis 服务端,一起处理提到 Pipeline 就不得不说 redis 事务,因为它和事务很像:都是将多个命令打包,最后一起执行。这里我简单提一下两者区别:Pipeline 需要客户端、服务端一起参与,命令在客户端处打包,发送到服务端执行。而事务只需服务端参与,redis 通过维护队列保证事务中的指令

2021-08-16 21:07:07 232

原创 redis 事务

所谓事务是指不可分割的最小工作单位,要么全部执行成功,要么全部执行失败redis 事务从开始到结束需要经过三个阶段:事务开始:multi 命令开启一个事务命令入队:watch、multi、discard、exec 会被立即执行、其他命令依次入队并返回客户端 queued事务执行:exec 命令开始执行事务exec:执行事务discard:关闭事务watch:加分布式锁multi:开启事务QUEUED:命令入队成功一般情况下不建议使用 redis 事务,因为它不能保证原子性、不支持

2021-08-16 20:21:55 86

原创 select count(1)、count(*)、count(column)

count(*):先把星号翻译为具体字段名字,多了一步翻译,效率差点count(1):计算有多少符合条件的行,可以理解为每行数据存在某个值固定的字段,计算有多少个固定值从结果来说:count(*) 和 count(1) 没区别,都不会过滤 NULLcount(column) 会过滤 NULL从速度来说:如果只有一列,count(*) 效率最高多列时,count(1) 效率高于 count(*)如果列为主键,count(column) 效率最高如果列不为主键,count(1) 效率比

2021-08-15 20:16:05 706

原创 Object 类常用方法整理

Java Object 类常用方法如下图所示:registerNatives():注册 native 方法getClass():获取 Class 类对象hashCode():计算 hashCode 值equals():比较对象是否相等clone():克隆对象方法toString():转字符串输出notify():随机唤醒一个等待队列中的线程notifyAll():唤醒所有等待队列中的线程wait():放弃锁资源,进入等待队列finalize():gc 收集时用到,唯一有可能复活的机会

2021-08-13 17:24:01 92

原创 MySQL 左连接、右连接、内连接

左连接:select * from table_name t1 left join table_name t2 on t1.id = t2.id以左表每条数据为基础,去右表全表匹配,返回满足条件的数据,右表没找到显示 NULL右连接:select * from table_name t1 right join table_name t2 on t1.id = t2.id以右表每条数据为基础,去左表全表匹配,返回满足条件的数据,左表没找到显示 NULL内连接:select * from ta

2021-08-13 16:47:34 54

原创 操作系统死锁

死锁:多个进程因竞争资源而造成的僵局(互相等待),若无外力作用,这些进程都将无法向前推进死锁产生的直接原因主要有以下两种:系统资源的竞争进程运行推进顺序不合适宏观产生死锁的四个必要条件:互斥条件:一个资源每次只能被一个进程使用,即在一段时间内资源仅为一个进程所占有。此时若有其他进程请求该资源只能等待请求与保持条件:进程请求新资源时不会放弃自己已获得的资源不可剥夺条件:进程已占有的资源只能自己来释放,不能被其它进程强行夺走循环等待条件:若干进程间形成首尾相接循环等待资源的关系死锁避免

2021-08-13 16:25:21 61

原创 TCP 报文头结构

TCP 报文头结构如下所示:源端口、目的端口:指定连接双方的端口序号:本报文段第一个字节的编号,通过序号确认有序性确认号:ack,指明下一个想要收到的字节序号,发送 ACK 说明当前序号之前的所有数据已正常接收首部长度(偏移量):指定 TCP 报文头的长度保留:为将来做准备URG、ACK…FIN:标志位,标志当前数据段的类型接收窗口:用于流量控制,告诉发送方当前缓冲区可用大小,控制流量校验和:用于验证 TCP 报文数据是否中途被修改紧急数据指针:指向紧急数据的位置,URG 标志为 1

2021-08-11 17:13:04 471

原创 TCP 和 UDP 的区别

从宏观层面来说,TCP 和 UDP 有以下区别:TCP 面向连接,UDP 面向无连接TCP 可靠,UDP 不可靠TCP 传播效率慢、UDP 传输效率快TCP 以流格式传输数据、UDP 以数据报格式TCP 所需系统资源多、UDP 所需系统资源少TCP 只支持点对点,UDP 支持一对一,一对多、多对一和多对多TCP、UDP 数据段头部大小不同,TCP 占 20 ~ 60 字节,UDP 占 8 字节所谓面向连接是说,发送数据前需要建立连接,TCP 需要三握,而 UDP 不需要TCP 通过一

2021-08-11 15:13:20 224

原创 TCP 如何保证可靠性

TCP 通过如下几种方式保证消息的可靠性:连接管理序列号和确认号校验和数据分块ARQ 协议超时重传流量控制拥塞控制连接管理三次握手,四次挥手。简单来说通过 TCP 定时器以及挥手、握手保证发送方、接收方都确认自身能正常收发消息关于这块前面博客有详细介绍,这里不再赘述序列号和确认号TCP 对每个字节的数据都进行了编号,这个编号也叫序列号。序列号包含以下功能:保证数据有序去重保证可靠性(接收方总能发现少了哪一段数据)确认号只有在 ACK 报文中才有效,进行确认时,确

2021-08-11 11:32:00 682

原创 TCP 定时器

TCP 内部维护了如下七种定时器:建立连接定时器:主要用于 TCP 三次握手时,发送完 SYN 包后启动定时器,如果 3S 内没有收到 ACK,重发 SYN 包,直到达到最大重传此时重传定时器:主要用于 TCP 超时重传,TCP 发送报文时创建重传计时器,指定时间内返回则撤销定时器,否则超时重发并复位定时器坚持定时器:TCP 通过让接收方指明窗口大小实现流量控制,当接收方窗口已满时告诉发送方暂时不要发送,直到接收方窗口不满时返回 ACK 报文告诉发送方可以发送数据。为了防止该 ACK 报文丢失,双方

2021-08-10 13:41:44 239

原创 Redis Cluster 集群模式

无论是主从复制,还是哨兵模式,都无法摆脱每个节点需要保存所有数据。为了实现水平扩展,Redis 在主从、哨兵保证高可用的基础上提出 Cluster 集群模式,通过 Cluster 集群模式实现水平扩展Cluster 模式提出槽的概念,每个分片负责一部分槽,每组redis 节点(master + slave)组成一个分片。客户端发出指令后,根据 key 计算它应该属于哪个分片、通过分片找到对应的 redis 节点,在对应节点执行相应命令完成客户端请求每个槽并不只保存一对 key-value,如果将单节点

2021-08-09 14:44:46 170

原创 Kafka 原理总结

之前很泛的介绍了消息队列常见的问题,本篇聚焦到 Kafka,记录 Kafka 相关知识:Kafka 是一款分布式发布、订阅消息系统,也就是常说的消息队列。目前市面上绝大多数业务系统使用消息队列的主要原因如下:解耦:当下游系统需要当前系统数据时,无需通过 RPC 或 HTTP 接口的方式传递,直接发送 MQ,下游需要时直接从队列消费即可可扩展:解耦提到的需求实际不属于当前系统业务,通过 MQ 将它“外包”出去,不影响当前系统业务缓冲(削峰):对于突发性的流量,通过消息队列将请求先保存在队列,之后从队

2021-08-09 11:48:44 254

原创 redis、Sentinel 常见配置

redis.conf 常见配置如下:// 是否以守护线程启动,默认不是daemonize no;// 以守护线程启动时,pid 写入 redis.pid 文件,配置文件路径,默认 var/run/redis.pidpidfile var/run/redis.pid// 端口号,默认6379port 6379;// 绑定的主机地址bind 127.0.0.1;// 当客户端闲置300秒后断开连接,为0表示一直不断开timeout 300;// redis 日志级别,从高到低分别为debu

2021-08-05 16:12:42 3353

原创 一致性 Hash 算法

假设现在有 5 台 redis 实例,每台实例负责保存一部分数据。客户端通过如下算法定位具体实例:hash(key) % 5随着业务发展,数据越来越多,5 台实例已经无法满足业务。现在要新增两台,新增两台后客户端算法如下:hash(key) % 7这就导致老算法计算出的值和新算法不一致:之前 hash(a) % 5 == 1,key 为 a 的键值对保存在 1 号实例,而 hash(a) % 7 的值可能等于其它值。这就导致因为扩容(缩容)后所有旧 key 都失效。为了解决该问题,一致性 H

2021-08-04 11:06:08 91

原创 Redis 哨兵模式

哨兵模式是指通过多个 Sentinel 实例监视 Redis 节点的状态:在某个 master 节点下线后,从 slave 节点中选举新的 master 节点,保证服务正常运行Sentinel 判断某个 Redis 节点是否下线的逻辑如下:默认 Sentinel 每秒发送 PING 命令给所有监视的节点(包含 master、slave、sentinel 节点),通过节点返回判断是否下线。如果某个节点在 down-after-miliseconds 毫秒内连续返回无效答复,Sentinel 修改该节点对应

2021-08-03 15:00:07 60

原创 Redis 主从同步

所谓主从同步是指:将 master 节点数据同步到 slave 节点。这样做的好处有以下两点:master 节点异常挂掉,可以从 slave 节点选举新的 master 节点,整个 redis 服务不会挂掉减轻 master 节点的压力,每次读操作在 slave 节点执行,写操作在 master 节点执行可以将排序等耗费资源更大的操作放在 slave 节点去做,减轻 master 节点的压力master 节点可以不用配置持久化 ,减轻压力,持久化配置到某一个 slave 节点就可以当使用主从

2021-08-03 11:03:13 157

原创 堆排序实现

之前笔者在遇到一些需要用到堆的算法题,如 n 个数求最大的 k 个数时经常使用优先队列,Java 通过 PriorityQueue 实现优先队列,本篇我打算通过数组实现堆,并简单说明堆和优先队列的区别堆本质是完全二叉树,通过二叉树也更容易理解,一般通过数组实现,通过数组实现时,具体规则如下图:完全二叉树:数按照从上到下,从左到右的顺序赋值,之间不存在空节点按不同功能,堆可以划分为以下两类:最大堆:节点值大于其左右子树的值,左右子树也是最大堆最小堆:节点值小于其左右子树的值,左右子树也是最小

2021-07-30 20:06:27 80

原创 List 相关实现类整理

Java 代码中常见的 List 实现类有 ArrayList、LinkedList、Vector 等ArrayList 和 Vector 底层都基于数组实现,区别在于 Vector 方法通过 Synchronized 修饰,保证线程安全、并且 ArrayList 扩容后长度为原来 1.5 倍,而 Vector 变为原来两倍LinkedList 底层基于双向链表实现(它还实现 Deque 接口),节点在内存地址上不连续由于实现方式的不同,ArrayList 和 LinkedList 有以下区别:对

2021-07-30 10:17:04 122

原创 二分查找思想及实现

使用二分查找必须满足集合有序,只有集合有序时才能使用二分思想:找出中点元素,此时左侧全是小于它的元素,右侧全是大于它的元素,根据需要选择左半边或右半边,直到找到对应元素实现:// 递归实现public boolean find(int[] num, int start, int end, int val) { if (start > end) { return false; } int mid = start + (end - start) / 2;

2021-07-29 14:17:46 91

原创 ConcurrentHashMap JDK 1.7 源码解析

ConcurrentHashMap 也是一种存储键值对的数据结构,和 HashMap 相比,它可以保证同步HashTable 虽然也能保证同步,但由于它通过 synchronized 直接对方法加锁,并且没有引入红黑树等效率更高的数据结构,导致整体效率较差,一般很少用到在 JDK 1.7 中,ConcurrentHashMap 核心属性如下:其中它的 put() 方法源码如下:public V put(K key, V value) { Segment<K,V> s;

2021-07-28 17:04:57 187

原创 面向对象和面向过程的区别

Java 语言是典型的面向对象程序设计语言,它具有面向对象的三大特征:封装继承多态这里我们简单介绍面向对象和面向过程的区别:知乎上有个回答说的很好:面向过程是编年体,面向对象是传记体。翻译一下就是说面向过程注重解决问题的步骤,将各种步骤通过函数的方式封装起来,然后依次调用,通过这种方式解决问题。而面向对象则更注重对象,将上述所说的步骤分配给不同的对象,每个对象具有相应的行为,通过依次调用对象行文的方式解决问题。举个简单的例子:水杯、饮品面向过程:装可乐 -》 拿出水杯 -> 装可乐、

2021-07-27 23:16:04 242

原创 JDK 和 JRE 的区别

任何 Java 开发者首要的第一件事就是安装 jdk,在安装 jdk 的过程中,jre 会一并弹框安装,安装完毕后配置系统(用户)环境变量,之后就可以愉快的开发了。。。JRE:Java Runtime EnvironmentJava 运行环境,也就是说,即使不安装 JDK,只安装 JRE,也可以成功运行 JAVA 程序,但不能开发。JRE 包含 java 虚拟机、java 基础类库,是使用 Java 语言编写程序所需要的运行环境JDK:Java Development KitJava 开发工具包,是

2021-07-27 16:59:19 174

原创 Unsafe 类简单介绍

UnSafe 类源码如下:// JDK 1.7 版本public final class Unsafe { private static final Unsafe theUnsafe; private static native void registerNatives(); private Unsafe() { } @CallerSensitive public static Unsafe getUnsafe() { Class var

2021-07-27 15:49:23 247

原创 final 关键字

final 是 Java 代码中常用的关键字, 可以用来修饰引用、方法和类,表示最终版,不可变如果 final 修饰引用,分以下两种情况:引用类型为基础类型,表示该引用是常量,值无法修改引用类型为对象类型,对象地址不能改变,但对象的属性可以修改当 final 修饰类的成员变量时,该变量必须包含初始化值,否则编译报错如果 final 修饰方法,表示该方法无法被子类重写,但可以继承。也就是说,子类可以调用父类的 final 方法,但不能重写如果 final 修饰类,表示该类已是最终类,无法被继承

2021-07-27 14:14:30 61

原创 计算机网络基础

本篇我计划简单整理计算机网络中经常出现的抽象概念:

2021-07-21 11:13:02 123 1

原创 DNS 协议

DNS(Domain Name System):全称域名系统,它是 TCP/IP 模型中应用层协议,可以把它看做域名和 IP 地址相互映射的分布式数据库,通过它实现主机名(域名)到具体 IP 地址间的映射,方便用户访问互联网DNS 采用分布式设计方案,其域名空间采用如下图所示树状结构:根域名服务器:最顶层服务器,在因特网上有13个,大部分位于北美洲顶级域名服务器:第二层服务器,这些服务器主要负责记录顶级域名和国家级域名权威域名服务器:第三层服务器,主要记录因特网上公共可访问主机所在组织机构提供的

2021-07-08 11:04:39 315

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除