Mysql中的回表

MYSQL中的回(Back to Table)表说明 一、 基本概念 回表是指当使用非聚簇索引(二级索引)进行查询时,首先在索引中查找到所需数据的主键值,然后再根据这个主键值回到主键索引(聚簇索引)中查找完整数据行的过程。 二、核心原理 聚簇索引 vs 非聚簇索引 -- 创建测试表 CREATE TABLE user_info ( id INT PRIMARY KEY, -- 主键,聚簇索引 name VARCHAR(50), email VARCHAR(100), age INT, created_at DATETIME, INDEX idx_email (email), -- 非聚簇索引(二级索引) INDEX idx_name_age (name, age) -- 复合非聚簇索引 ); 索引结构对比 聚簇索引(主键索引)结构: 索引节点 -> 叶子节点包含完整数据行 [id:1] -> [id:1, name:'张三', email:'zhang@xx.com', age:25, ...] [id:2] -> [id:2, name:'李四', email:'li@xx.com', age:30, ...] 非聚簇索引(二级索引)结构: 索引节点 -> 叶子节点只包含索引列 + 主键值 [email:'li@xx.com'] -> [主键id:2] [email:'zhang@xx....

April 23, 2024 · 4 min · Leanku

Mysql中的锁

MYSQL中的锁 一、 MySQL锁概述 MySQL锁机制是数据库管理系统实现并发控制的核心技术,它通过在共享资源上实施访问限制,确保数据的一致性和完整性。作为PHP高级开发者,深入理解MySQL锁机制对于构建高性能、高并发的Web应用至关重要。 二、 MySQL锁分类体系 1. 按锁的粒度划分 1. 表级锁 特点 开销小,加锁快 锁定整个表 并发度低 使用场景 -- 显式加表锁 LOCK TABLES users READ; -- 共享锁 LOCK TABLES users WRITE; -- 排他锁 -- 操作完成后释放 UNLOCK TABLES; 注意事项: MyISAM引擎默认使用表锁 在InnoDB上应谨慎使用,会严重影响并发 2. 行级锁 特点 开销大,加锁慢 只锁定需要的行 并发度高 使用场景 -- 共享锁(S锁) SELECT * FROM accounts WHERE id = 1 LOCK IN SHARE MODE; -- MySQL 8.0+推荐语法 SELECT * FROM accounts WHERE id = 1 FOR SHARE; -- 排他锁(X锁) SELECT * FROM accounts WHERE id = 1 FOR UPDATE; 注意事项:...

April 23, 2024 · 5 min · Leanku

MySQL分库分表(无中间件)

MySQL分库分表(无中间件) 一、 分库分表方案设计 1. 垂直拆分 (按业务模块) -- 原始单体数据库 CREATE DATABASE ecommerce; USE ecommerce; -- 垂直拆分后的数据库 -- 用户库 CREATE DATABASE user_center; USE user_center; CREATE TABLE users ( user_id BIGINT PRIMARY KEY, username VARCHAR(50) UNIQUE, email VARCHAR(100) UNIQUE, password VARCHAR(100), mobile VARCHAR(20), status TINYINT DEFAULT 1, created_at DATETIME, updated_at DATETIME ); CREATE TABLE user_profiles ( user_id BIGINT PRIMARY KEY, real_name VARCHAR(50), avatar VARCHAR(200), gender TINYINT, birthday DATE, bio TEXT ); CREATE TABLE user_address ( address_id BIGINT PRIMARY KEY, user_id BIGINT, province VARCHAR(50), city VARCHAR(50), district VARCHAR(50), detail VARCHAR(200), is_default TINYINT DEFAULT 0, INDEX idx_user_id (user_id) ); -- 订单库 CREATE DATABASE order_center; USE order_center; CREATE TABLE orders ( order_id BIGINT PRIMARY KEY, user_id BIGINT, total_amount DECIMAL(10,2), status TINYINT, payment_status TINYINT, created_at DATETIME, paid_at DATETIME ); CREATE TABLE order_items ( item_id BIGINT PRIMARY KEY, order_id BIGINT, product_id BIGINT, product_name VARCHAR(100), price DECIMAL(10,2), quantity INT, INDEX idx_order_id (order_id) ); -- 商品库 CREATE DATABASE product_center; USE product_center; CREATE TABLE products ( product_id BIGINT PRIMARY KEY, name VARCHAR(100), category_id INT, price DECIMAL(10,2), stock INT, status TINYINT, created_at DATETIME ); CREATE TABLE categories ( category_id INT PRIMARY KEY, name VARCHAR(50), parent_id INT ); 2....

April 23, 2024 · 11 min · Leanku

MySQL索引类型

MySQL索引类型 索引是帮助MySQL高效获取数据的数据结构,类似于书籍的目录,可以大大加快查询速度。 一、索引类型 1. B-Tree 索引(最常用) 特点 默认的索引类型 适用于全键值、键值范围或键值前缀查找 支持排序和分组 创建语法 -- 单列索引 CREATE INDEX idx_name ON table_name(column_name); -- 多列复合索引 CREATE INDEX idx_name ON table_name(col1, col2, col3); -- 创建表时指定 CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(50), email VARCHAR(100), age INT, INDEX idx_name (name), INDEX idx_email_age (email, age) ); 适用查询类型 -- 全值匹配 SELECT * FROM users WHERE name = 'John'; -- 前缀匹配(最左前缀) SELECT * FROM users WHERE name LIKE 'Joh%'; -- 范围查询 SELECT * FROM users WHERE age BETWEEN 20 AND 30; -- 精确匹配左列 + 范围匹配右列 SELECT * FROM users WHERE email = 'john@example....

April 23, 2024 · 5 min · Leanku

rabbitmq工作原理

rabbitmq工作原理 AMQP协议 AMQP是一个提供统一消息服务的应用层标准协议,基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同开发语言等条件的限制。 AMQP协议是一种二进制协议,提供客户端应用与消息中间件之间异步、安全、高效地交互。 AMQP作为中间层服务,把消息生产和消费分割出来,当消息生产者出现异常,不影响消费者对消息的消费,当消费者异常时,生产者生产的消息可以存放到服务的内存或者磁盘,不以影响到消息的消费,同时,消息也可以基于路由的规则可以投递到指定的消费者消费。 AMQP基于模块化通过Exchange和Message Queue两个组件组合实现消息路由分发 生产者和消费者 生产者是生产消息的主体,消费者是消费消息的主体 数据集成与系统解耦、异步处理与事件驱动、流量削峰、事务消息与分布式事务的最终一致等 生产者生产一条消息丢给消息代理,消息代理根据投递规则将消息传送到消费者手上 交换机 交换机就像是消息代理的路由器,负责拿到一个消息之后,根据确定的规则(路由键)将他路由给一个或零个队列、交换机具备多种路由模式。 基于消息生产者和路由规则可以将消息投递到指定的Message Queue,交换机收到生产者投递的消息,基于路由规则及队列绑定关系匹配到投递对应的交换机或者队列进行分发,交换机不存储消息,只做转发 直连交换机:根据路由键完全匹配的投递到对应的队列。 扇形交换机:无视路由键,将消息进行拷贝,并路由到给绑定到它身上的所有队列,提供了一个广播的效果 主题交换机: 根据路由键按模式匹配的投递到对应的队列 交换机也具备自己的属性,可以定义自己的名字,是否持久化等选项 队列 消息的暂存地,至少有一个消费者订阅了队列的话,消息会立即发送给这些订阅的消费者。但是如果消息到达了无人的订阅队列,消息会在队列中等待,等待有了消费者便进行分发 Exchange和Message Queue之间存在绑定关系,消息到了Exchange后基于路由策略可以将消息投递到已绑定且符合路由策略的Message Queue。 消息队列会将消息存储到内存或者磁盘中,并将这些消息按照一定顺序转发给一个或多个消费者,每个消息队列都是独立隔离的,相互不影响。 消息队列具有不同的属性:私有,共享,持久化,临时,客户端定义或者服务端定义等,可以基于实际需求选择对应的类型 消息 消息是信息的载体,也是MAQP协议的一个实体,消息包含以下两部分 载荷:就是真正的信息,是你想要传输的任何内容,该部分内容对消息代理来说是透明的 元消息:包含路由键、内容类型、编码、是否持久化等等消息属性,会被消息代理所解析,消息代理根据消息的属性对这条消息进行投递,存储等。这部分被消息代理所关心,而消费者对其是不关心的 信道 网络信道,是建立在Connection连接之上的一种轻量级的连接。几乎所有的操作都在Chanel中进行,Channel是进行消息读写的通道,客户端可以建立对各Channel,每个Channel代表一个会话任务 如果把Connection比作一条光纤电缆的话,那么Channel信道就比作成光纤电缆中的其中一束光纤。一个Connection上可以创建任意数量的Channel。 大部分的业务操作是在Channel这个接口中完成的 队列声明 queueDeclare 交换机的声明 ExchangeDeclare 队列的绑定 queueBind 发布消息 basicPublish 消费消息 basicConsume Rabbitmq 工作模式 一、简单模式 生产者发送消息到队列,消费者进行消费,没有交换机 二、工作模式 一个生产者发送消息到队列中,队列分配消息给不同的队列,队列接收到消息进行消费 三、订阅模式 每个队列的消息都是一样的,生产者把消息发送给交换机,交换机把消息发送给消息绑定的队列,让消费者消费 四、路由模式 根据路由键发送到不同的消息队列中 五、主题模式 根据路由键分类,发送到不同的消息队列中

April 23, 2024 · 1 min · Leanku

RabbitMQ详解

RabbitMQ详解 1. 五种工作模式 1.1 简单模式 生产者p发送消息到队列,消费者c消费消息。(无交换机消息直接进入队列) p->queue->c 1.2 工作模式 一个生产者p发送消息到队列,队列将消息分配给多个消费者c1,c2。(实现负载均衡,适合集群异步处理,典型场景:发送邮件、短信等) p->queue|->c1 |->c2 1.3 订阅模式,每个队列的消息都是一样的 使用广播类型的交换机e, 生产者p把消息发送到交换机e,交换机e把消息发送到和交换机绑定的队列c4、c5(每个消费者接收相同的消息。典型应用场景:天气订阅,微博订阅等) |->c4 p->e->| |->c5 1.4 路由模式 使用Direct类型的交换机,生产者p发送消息到交换机e,交换机E根据路由键(如error发送到c1)匹配队列,消息仅发送到匹配的队列(与订阅模式的区别:按条件筛选发送) |->error->c1 p->e| |->info->c2 1.5 主题模式 使用Topic类型的交换机,路由模式的升级版,支持通配符匹配路由,匹配更灵活(#代表匹配一个或多个单词,*代表匹配一个) |log.*->c4 p-> | |log.#->c5 2. 消息持久化 当RabbitMQ重启以后,未消费的消息可以在服务重启后继续消费,不会丢失。 3. 应答机制 ACK 两种方式 自动确认:消费者接收消息后,立即ACK然后再处理业务逻辑,加入业务逻辑出现异常,消息也会被确认 手动确认:消费者接收消息后,消息状态被设置为unack,由业务逻辑指定ACK的位置,假如没有手动ACK,则mq中的消息不会减少,会重复消费 4. 死信队列 DLX全程Dead-Letter-Exchange,也可以称为私信交换机,就是当一个队列中的消息变成死信以后,会被重新发送到另一个交换机,这个交换机就是DLX,而绑定DLX的队列就是死信队列。 变为死信的一般情况: 消息被拒绝 消息过期 队列达到最大长度 使用死信队列只需要定义队列的时候设置x-dead-letter-exchange参数指定交换机就可以了,x-message-ttl参数设置消息存活时间,x-dead-letter-routing-key参数设置路由键 5. 延时队列 延时队列就是当消息发送以后,并不想让消费者立即拿到消费,而是等待特定时间之后才能拿到消息来消费。 延时功能可以通过设置过期时间+死信队列来实现 6. 集群模式 允许消费者和生产者在RabbitMQ节点崩溃的情况下继续运行 允许通过添加更多的节点来扩展消息通信的吞吐量 RabbitMQ会始终记录以下四种类型的内部元数据 队列元数据-队列的名称和他们的属性(是否持久化,是否自动删除) 交换器元数据-交换器的类型、名称和属性 绑定元数据-一张简单的表格展示了如何将消息路由到队列 v-host元数据-为vhost内的队列、交换器和绑定提供命名空间和安全属性 RabbitMQ集群的3个模式 主备模式:从节点相当于主节点的链接,所有从节点收到的请求,真实转向的都是从节点。一般在并发和数据不是特别多的情况下使用,当从节点挂掉后会从备份节点中选择一个节点出来作主节点对外提供服务。 镜像模式:将需要消费的队列变为镜像队列,存在于多个节点,这样就可以实现RabbitMQ的HA高可用。作用就是消息实体会主动在镜像节点之间实现同步,任何一个节点宕机都没关系,保证100%数据不丢失,在实际工作中用的最多的。并且实现集群非常的简单,一般物联网大厂都会构建这种镜像集群模式。 异地多活模式:用来实现异地的数据复制,使用多活模式需要借助federation插件来实现集群间或节点间的消息复制,广泛应用于众多互联网公司 7. 负载均衡 HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡、以及基于TCP和HTTP的应用程序代理 特别适用于那些负载特大的web站点,完全可以支持数以万计的并发连接,同时可以保护web服务器不被暴露到网络上

April 23, 2024 · 1 min · Leanku

Redis分布式锁

Redis分布式锁 一、 Redis锁基础概念 1. 为什么需要Redis锁 Redis锁是一种基于内存数据库Redis实现的分布式锁机制,主要解决分布式系统中的资源竞争问题。相比数据库锁,Redis锁具有以下优势 高性能:基于内存操作,响应速度快 原子性保证:Redis单线程模型天然支持原子操作 分布式支持:可跨多台服务器使用 丰富的数据结构:支持多种锁实现方式 2. 基本实现原理 最简单的Redis锁实现方式: SET resource_name my_random_value NX PX 30000 NX:仅当key不存在时设置 PX:设置过期时间(毫秒) my_random_value:唯一标识,用于安全释放锁 二、Redis锁的实现方式 1. SETNX实现(基本方式) 实现步骤: 尝试获取锁:SETNX lock_key 1 获取成功则设置过期时间:EXPIRE lock_key 30 执行业务逻辑 释放锁:DEL lock_key 问题: 非原子操作,SETNX和EXPIRE之间可能崩溃导致死锁 2. SET扩展参数实现(推荐) Redis 2.6.12+版本支持扩展参数,可原子性完成设置 SET lock_key unique_value NX PX 30000 PHP实现示例: $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $lockKey = 'order_lock_123'; $uniqueId = uniqid(); $expire = 30000; // 30秒 // 尝试获取锁 $acquired = $redis->set($lockKey, $uniqueId, ['NX', 'PX' => $expire]); if ($acquired) { try { // 执行业务逻辑 processOrder(); } finally { // 使用Lua脚本保证原子性释放 $script = " if redis....

April 23, 2024 · 3 min · Leanku

Redis高可用

Redis高可用 1. 事务机制和IO多路复用 1.1 事务 1.1.1 事务特点 事务提交前,先检查命令语法是否正确 提交后的命令一定会执行 有命令报错,也会执行完 不能回滚 1.1.2 命令 multi,告诉Redis服务器开启一个事务。只是开启而不是执行。 exec, 告诉Redis开始执行事务 discard,告诉Redis取消事务 watch,监视某一个键值对,它的作用是在事务执行之前如果监视的键值被修改,事务会被取消 1.2 IO多路复用 redis 是单线程,单线程只能在一个CPU内核上执行,假如是4核的,只会占用一个,其它三个不参与。 worker线程串行 read读->计算->write返回 在Redis6.0加入了io-threads, 主线程worker只进行计算,并行读取 io-threads 4 io-threads-do-reads yes 2. 持久化和过期淘汰策略 2.1 持久化 Redis是存储在内存中的, 服务器重启数据会丢失。持久化方案可以保存数据到磁盘文件,可以恢复到内存中。Redis提供的持久化方案有: rdb:生成某一时刻的快照,保存到二进制文件中 优点: 容灾性好,方便备份 性能最大化,fork出一个子进程来操作,对主进程没有影响 数据较多时,相对于aof启动效率更高 缺点: 会造成数据丢失 aof:实时记录每一条写命令,追加到文件中,打开可以看到具体的操作记录 同步策略:appendfsync everysec(默认),每秒同步一次 always,每次操作后都要同步一次 no,由操作系统调度进行同步 重写策略: 手动触发,执行bgrewiteaof命令 自动触发:auto-rewrite-percentage 100, auto-rewrite-min-size 64mb 优点 数据安全,不会造成数据的丢失 缺点 比rdb重启效率低;运行效率比rdb低 混合模式:上面两种方式的结合 触发方式有两种: 手动触发: save命令,会让Redis处于阻塞的状态,直到rdb持久化完成,线上环境谨慎使用 bgsave命令,它会fork出一个子进程(有短暂阻塞),用来执行持久化,主进程继续响应客户端请求 自动触发: 配置文件修改(save n m),在n秒内,有m个key发生变化就会触发,执行命令最总执行的是bgsave 2.2 过期键删除策略 Redis设置key时,都会设置一个过期时间,Redis同时使用了两种过期删除策略,惰性过期和定时过期...

April 23, 2024 · 1 min · Leanku

分布式session

分布式session 在单体服务器的年代,Session 直接保存在服务器中,是没有问题的,而且实现起来很容易。 但是随着分布式架构的流行,单个服务器已经不能满足系统的需要了,通常都会把系统部署在多台服务器上,通过负载均衡把请求分发到其中的一台服务器上; 那么很有可能第一次请求访问的 A 服务器,创建了 Session ,但是第二次访问到了 B 服务器,这时就会出现取不到 Session 的情况; 于是,分布式架构中,Session 共享就成了一个很大的问题。 解决方案 1. session同步 思路:多个web-server之间相互同步session,这样每个web-server之间都包含全部的session 优点:web-server支持的功能,应用程序不需要修改代码 不足: 1.session的同步需要数据传输,占内网带宽,有时延。 2.所有web-server都包含所有session数据,数据量受内存限制,无法水平扩展。 3.主从架构固有的保证一致性会牺牲可用性的特定,但进行主从同步时,登陆的请求将被阻塞,显然不符合用户实际需求。 2. 客户端存储法 思路:服务端存储所有用户的session,内存占用较大,可以将session存储到浏览器cookie中 优点:服务端不需要存储 缺点: 1.每次http请求都携带session,占外网带宽 2.数据存储在端上,并在网络传输,存在泄漏、篡改、窃取等安全隐患 3.session存储的数据大小受cookie限制 “端存储”的方案虽然不常用,但确实是一种思路。 3. 反向代理hash一致性 思路:使用 Nginx (或其他复杂均衡软硬件)中的 IP 绑定策略,同一个 IP 只能在指定的同一个机器访问,但是这样做失去了负载均衡的意义,当挂掉一台服务器的时候,会影响一批用户的使用,风险很大; 反向代理层做逻辑处理 方案一:ip进行hash 反向代理层使用用户ip来做hash,以保证同一个ip的请求落在同一个web-server上. 方案二:含有业务属性的字段hash 反向代理使用http协议中的某些业务属性来做hash,例如sid,city_id,user_id等,能够更加灵活的实施hash策略,以保证同一个浏览器用户的请求落在同一个web-server(即不同的user_id对应不同的web-server). 总结:让专业的软件做专业的事情,反向代理就负责转发,尽量不要引入应用层业务属性,除非不得不这么做(例如,有时候多机房多活需要按照业务属性路由到不同机房的web-server)。 4. 后端统一集中存储(主流方案) 思路:将session存储在web-server后端的存储层,数据库或者缓存 优点: 1.没有安全隐患 2.可以水平扩展,数据库/缓存水平切分即可,可以存储较多的session。 3.web-server重启或者扩容都不会有session丢失 不足:增加了一次网络调用,并且需要修改应用代码。 对于db存储还是cache,个人推荐后者:session读取的频率会很高,数据库压力会比较大。 如果有session高可用需求,cache可以做高可用,但大部分情况下session可以丢失,一般也不需要考虑高可用。

April 21, 2024 · 1 min · Leanku

NGINX负载均衡

NGINX负载均衡 Nginx是一个强大的开源Web服务器和反向代理服务器,它支持正向代理和反向代理功能。 正向代理 正向代理是客户端访问代理服务器去访问目标服务器,并且对目标服务器隐藏了客户端的真实信息(IP等信息) 正向代理的主要用途包括: 访问被限制的资源:当某些资源受到网络限制或访问限制时,可以使用正向代理绕过这些限制来获取资源。 提高访问速度:代理服务器可以缓存经常请求的资源,从而提高客户端访问资源的速度。 突破防火墙:正向代理可以帮助绕过企业或国家防火墙的限制,访问被封锁的网站或资源。 反向代理 反向代理是指代理服务器接收客户端的请求,然后反向代理将客户端的请求分发给一个或多个目标服务器,最后将响应返回给客户端,对于客户端隐藏了真实的服务端信息 反向代理的主要用途包括: 负载均衡:反向代理可以根据一定的算法将请求均匀地分发给后端的多台服务器,从而实现负载均衡,提高系统的并发处理能力和稳定性。 缓存静态资源:反向代理可以缓存经常请求的静态资源,减少后端服务器的负载,提高网站的访问速度。 安全性和可靠性:反向代理可以作为防火墙和安全设备,提供安全认证、访问控制、DDoS攻击防护等功能。 Nginx配置文件 #user nobody; 是用来指定 Nginx 进程运行的用户和用户组的配置项。 在 Linux 系统中,各个进程需要以某个用户的身份来运行,以限制权限并提高安全性 worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 8080; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } 第一部分 全局块worker_processes:...

April 20, 2024 · 3 min · Leanku