- CSRF :跨站请求伪造,用户通过跨站请求,以合法用户身份做非法的事情
- 防范:
- token 验证
- Referer 验证: Referer 指的是页面请求来源。意思是,只接受本站的请求,服务器才做响应;如果不是,就拦截
- XSS:跨站脚本攻击,是向网页中注入恶意脚本在用户浏览网页时在用户浏览器中执行恶意脚本的攻击方式
- 防范:
- 校验:对用户输入的数据进行HTML Entity 编码
- 过滤:移除用户输入的和事件相关的属性。
- 校正:避免直接对HTML Entity进行解码。
- 定义:设计模式用于承载复杂的业务逻辑,使写出的代码简洁、易扩展
- 六大原则:
- 单一原则:一个类或者一个方法只负责一个职责,尽量做到类的只有一个行为原因引起变化
- 里氏替换原则:子类可以拓展父类的规则,但不能改变原有父类的功能
- 依赖倒置原则:设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象。抽象不应该依赖于细节;细节应该依赖对象。通过依赖倒置,可以减少类与类之间的耦合性,提高代码的耦合性,提高系统的稳定性,提高代码的可读性,并能够降低修改程序锁造成的风险
- 接口隔离原则:就是将业务设计进行最小的划分创建各自的接口
- 迪米特原则:最少知道原则,尽量降低类于类之间的耦合,一个对象应该对其他对象有最少的了解
- 开闭原则:一个软件实体如类、模块和函数应该对拓展开放,对修改关闭
- 常用的设计模式:
- 单例模式:单例模式可以确保系统中某个类只有一个实例,该类自行实例化并向整个系统提供这个实例的公共访问点,除了该公共访问点,不能通过其他路径访问该实例
- 工厂模式:建立一个工厂类,对实现了同一接口的一些类进行实例的创建,工厂模式的实质就是由一个工厂类根据传入的参数,动态决定应该创建哪儿一个产品类
- 建造者模式:将复杂产品的创建步骤分解到不同的方法里,使的创建过程更加清晰,从而更精准控制浮渣对象的产生过程
- 适配器模式:适配器模式主要是将一个类或者接口转化成客户端希望的格式,使的原本不兼容的的类可以一起工作,将目标类和适配者类解耦;同时也符合“开闭原则”,可以在不修改原代码的基础上增加新的适配器类;将具体的实现封装在是陪着类中,对于客户端来说是透明的,而且提高了适配者的的复用性
- 装饰器模式:可以动态给对象添加一些额为的职责从而实现功能的拓展,在运行时选择不同的装饰器,从而实现不同的行为
- 代理模式:代理模式的设计动机是通过代理对象来访问真实对象,通过建立一个对象代理类,有代理对象控制原对象的引用,从而实现对真实对象的操作。在代理模式中,代理对象主要是起到一个中介的作用,用于协调与连接调用者(即客户端)和与被调用者(即目标对象),在一定程度上降低了系统的耦合度,同时也保护了目标对象。但缺点是在调用者与被调用者之间增加了代理对象,可能会造成请求的处理速度变慢
- 桥接模式:
桥接模式即将抽象部分与它的实现部分分离开来,使他们都可以独立变化。桥接模式将继承关系转化成关联关系,它降低了类与类之间的耦合度,减少了系统中类的数量,也减少了代码量。将抽象部分与他的实现部分分离这句话不是很好理解,其实这并不是将抽象类与他的派生类分离,而是抽象类和它的派生类用来实现自己的对象。
门店模式:通过对客户端提供一个统一的接口,用于访问子系统中的一群接口
策略模式:将类中经常改变或者可能改变的部分提取为作为一个抽象策略类接口类,然后在类中包含这个对象的实例,这样类在运行中就可以随意调用实现这个接口类的行为
迭代器模式(Inerator):提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示
- 什么是微服务:
- 微服务就是很小的服务,小到一个服务只对应一个单一的功能,只做一件事情。这个服务可以单独部署运行,服务之间可以通过RPC来进行交互,每隔微服务都是由独立的小团队开发,测试,部署,上线,负责它的整个生命周期
- RPC:远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的思想。
- 垃圾回收机制是一种动态存储分配的方案,它会自动释放程序不再需要的已分配的内存块。垃圾回收机制可以让程序员不必关心程序内存分配,从而将更多的精力投入到业务逻辑。
- PHP 垃圾回收机制
- PHP5.3 之前使用的垃圾回收机制是单纯的“引用计数”,每个内存对象都会被分配一个计数器,当内存变量被变量引用时,计数器就+1,unset后计数器就会-1,但是如果两个对象和多个对象互相引用行程环状后,内存对象的计数器就不会被消减为0,会不能被回收。
- PHP5.3之后,在引用计数基础上,实现了一种复杂的算法,来检测内存对象中是否存在引用环的存在,以避免内存泄露;每个PHP变量中都存在一个zval的变量容器,里面包括了变量的类型和值,还包括两个字节的额为信息,一个是is_ref 是否是引用变量,通过这个字节可以吧普通变量和引用变量分开来,第二个额外字节是refcount,这个字节表示指向这个zval变量容器的变量个数
- SQL 预编译
- 确认每种数据的类型
- 规定数据长度
- 过滤参数中含有的一些数据库关键词
- 定义:在密码学中,时序攻击是一种侧信道攻击,攻击者试图经过分析加密算法的时间执行来推导密码。若是通过===来进行比较,那么两个字符串是从第一位开始逐一进行比较的,发现不一样当即返回false,那么经过计算返回的速度就知道了大概是哪一位开始不一样的
- 防御:
- PHP : hash_equals ⽐较两个字符串,⽆论它们是否相等,本函数的时间消耗是恒定的。
__construct():构造方法,往往进行与首次调用。
__destruct():析构方法,销毁对象时调用。
__get():在调取不可访问属性值的时候调用
__set():给不可访问的属性赋值时调用
__isset(): 当给一个未定义的属性上调用isset()函数时会调用此方法
__unset():当给一个未定义的属性上调用unset()函数时会调用此方法
__call():在对象中调用一个不可访问方法时调用
__clone():使用clone方法复制一个对象时,会调用此方法
__toString():在将一个对象转化成字符串时自动调用
- 依赖注入原理就是利用类方法反射,取得参数实例,然后利用容器构造好实例。然后在使用回调函数调起
- all()方法,转换为属性形式输出
- avg()方法返回平均值
- count()方法返回集合总数
- countBy()方法返回数值出现的次数或回调函数指定值出现的次数
- diff()方法返回集合数组之间不相同的部分,组合新的集合
- duplicates()返回重复的值;
- first()返回成立后的第一个值;
- flatten()将多维数组转换为一维
- get()通过键名找值
- has()判断集合中是否存在指定键
- pop()移出集合中最后一个值
- slice()返回指定值后续的集合
- sort()返回指定值后续的集合
- where()系列方法,和数据库条件一样
- array_divide:array_divide 函数返回两个数组,一个包含原始数组的键,另一个包含原始数组的值。
- array_dot :函数将多维数组平铺到一维数组中,该数组使用「.」符号表示
- array_except:函数从数组中删除指定的键/值对
array_first: 函数返回数组中第一个通过指定测试的元素
- array_flatten:函数将多维数组平铺为一维数组
- array_forget:函数使用「.」符号从深度嵌套数组中移除给定的键/值对
- array_only: 函数仅返回给定数组中指定的键/值对
- array_plunk:函数从数组中检索给定键的所有值
- array_pull: 函数返回并从数组中删除键/值对
- array_random:函数从数组中返回一个随机值
Str::is:
方法用来判断字符串是否与指定模式匹配。星号*
可用于表示通配符- ...
- 参考:辅助函数 | 综合话题 |《Laravel 8 中文文档 8.x》| Laravel China 社区
- Authenticate 中间件 : 用户身份验证。可修改 redirectTo 方法,返回未经身份验证的用户应该重定向到的路径。
- CheckForMaintenanceMode 中间件:检测项目是否处于 维护模式。可通过 $except 数组属性设置在维护模式下仍能访问的网址。
- EncryptCookies 中间件:对 Cookie 进行加解密处理与验证。可通过 $except 数组属性设置不做加密处理的 cookie。
- RedirectIfAuthenticated 中间件:当请求页是 注册、登录、忘记密码 时,检测用户是否已经登录,如果已经登录,那么就重定向到首页,如果没有就打开相应界面。可以在 handle 方法中定制重定向到的路径。
- TrimStrings 中间件:对请求参数内容进行 前后空白字符清理。可通过 $except 数组属性设置不做处理的参数。
- TrustProxies 中间件:配置可信代理。可通过 $proxies 属性设置可信代理列表,$headers 属性设置用来检测代理的 HTTP 头字段。
- VerifyCsrfToken 中间件:验证请求里的令牌是否与存储在会话中令牌匹配。可通过 $except 数组属性设置不做 CSRF 验证的网址。
- 加载项目依赖,创建laravel实例
- 通过web服务器定向到public/index.php入口文件中,通过autoload.php加载composer生成的自动加载器定义,然后从bootstarp/app.php中检索laravel应用程序的实例
- 创建应用实例
- 传入请求到内核处理
- Http 和 console 内核
- 运行bootstrappers数组,这些引导程序用来配置异常处理、配置日志、检测应用程序环境,并执行实际处理请求之前需要完成的其他任务
- 内核还定义了http中间件列表,所有请求在被应用程序处理之前必须通过这些中间件
- 服务提供者
- 为应用程序加载service providers
- 服务提供者负责引导框架的所有不同组件,如数据库,队列,验证和路由组件
- 路由
- 应用程序中最重要的服务提供者之一是
App\Providers\RouteServiceProvider
。此服务提供程序加载应用程序的routes
目录中包含的路由文件。- 路由器将请求发送到路由或控制器,并运行任何路由特定的中间件。
- 如果请求通过了所有匹配路由分配的中间件,则将 HTTP 请求定向到控制器或通过省略控制器直接返回视图或响应
- 控制器
- 视图
- 最后
- 一旦路由或控制器方法返回一个响应,该响应将通过路由的中间件返回,从而使应用程序有机会修改或检查传出的响应。
- 最后,一旦响应通过中间件传回,HTTP 内核的 handle 方法将返回响应对象,并且
index.php
文件对返回的响应调用 send 方法。send 方法将响应内容发送到用户的 web 浏览器。
- 协程,英文Coroutines,是一种比线程更加轻量级的存在
- 协程不是进程,也不是线程,它就是一个可以在某个地方挂起的特殊函数,并且可以重新在挂起处继续运行。所以说,协程与进程、线程相比,不是一个维度的概念
- 一个进程可以包含多个线程,一个线程也可以包含多个协程,也就是说,一个线程内可以有多个那样特殊函数运行。但是有一点,必须明确,一个线程内的多个协程的运行是串行的。如果有多核CPU的话,多个进程或一个进程内的多个线程是可以并行运行的,但是一个线程内的多个协程却绝对串行的,无论有多少个CPU
- 协程、线程和进程关于上下文切换的比较
- php-fpm
- 早期版本的PHP并没有内置的web服务器,而是提供了SAPI(ServerAPI)给第三方做对接。现在非常流行的php-fpm就是通过fastCGI协议来处理PHP与第三方WEB服务器之间的通信
- 比如Nginx+ php-fpm 的组合,这种方式运行的fpm是Master/Worker模式,启动一个Master进程监听来自Nginx的请求,再fork多个Worker进程处理请求。每个Worker进程只能处理一个请求,单一请求的生命周期如下:
- 初始化模块
- 初始化请求。此处请求是请求PHP执行代码的意思,并非HTTP的请求
- 执行PHP脚本
- 结束请求
- 关闭模块
- Swoole
- Swoole 也是采用的是Master/Worker 模式,不同的是Master进程有多个Reactor进程,Master只是一个事件发生器,负责监听Socker句柄的事件变化。Worker以多进程的方式进行,接收来自Reactor线程的请求,并执行回调函数。启动Master进程的流程如下:
- 初始化模块
- 初始化请求。因为swoole需要通过cli的方式运行,所以初始化请求时,不会初始化PHP的全局变量,如$_SERVER,$_POST等
- 执行PHP脚本。包含词法、语法解析、变量、函数、类的初始化等,Master进入监听状态,并不会结束进程
- Swoole 加速的原理:
- 由Reactor(epo的IO复用方式)负责监听Socket句柄的事件变化,解决高并发问题
- 通过内存常驻的方式节省PHP代码初始化的时间,在使用笨重的框架时,用swoole加速效果是非常明显的
- 对比不同
- php-fpm:
- Master主进程/Worker 多进程模式
- 启动Master,用过FastCGI协议监听来自Nginx传输的请求
- 每隔Worker进程只对应一个连接,用于执行完整的PHP代码
- PHP 代码执行完毕,占用的内存会全部销毁,下一次请求需要重新再进行初始化等各种繁琐的操作
- 只用于HTTP Server
- Swoole
- Master之进程(由多个Reactor线程组成)/Worker多进程(多线程模式)
- 启动Master,初始化PHP代码,由Reactor监听Socker句柄的时间变化
- Reactor主线程负责子多线程的均衡问题,Manager进程管理Worker多进程,包括TaskWorker的进程
- 每隔Worker接收来自Reactor的请求,只需要执行回调函数部分的PHP代码
- 只在Master启动时执行一遍PHP初始化状态,Master进入监听状态,并不会结束进程
- 不仅可以用于HTTP Server,还可以建立TCP连接、WebSocket连接
- InnoDB支持事务,myiSAM不支持
- InnoDB支持外键,myiSAM不支持
- InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构),必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查到主键,然后再通过主键查询到数据。因此,主键不应该太大,因为主键太大,其他索引也都会很大
- InnoDB不保存表的具体行数,执行 count(*)的时候需要全表扫描;而MyiSAM用一个变量保存了整个表的行数,执行count(*)的时候只需要读出该变量
- InnoDB不支持全文索引,而MyiSAM支持全文索引,在设计全文索引领域的查询效率上MyiSAM速度更快更高;PS:5.7以后的InnoDB支持全文索引了
- MyiSAM表格可以被压缩后进行查询操作
- InnoDB支持表、行(默认)级锁,而MyiSAM支持表级锁
- InnoDB表必须有唯一索引(如主键),而MyiSAM可以没有
- InnoDB存储文件有frm、ibd,而MyiSAM是frm、MYD、MYI
Innodb:frm是表定义文件,ibd是数据文件
Myisam:frm是表定义文件,myd是数据文件,myi是索引文件
- B树与B+树的区别
- B+树内节点不存储数据,所有data存储在叶子节点导致查询时间复杂度固定为log n。而B树查询时间复杂度不固定,与key在树中的位置有关,最好为O(1)
- B+树叶节点两两相连可大大 增加区间复杂度,可使用在范围查询时,而B树每个节点Key和data在一起,则无法进行区间查找
- B+树更适合外部存储。由于内节点无data域,每个节点能索引的范围更大更精确
- 使用B+树的好处
- 由于B+树的内部节点只存放键,因此,一次读取,可以在内存页中获取更多的键,有利于更快地缩小查找范围。B+树的叶节点由一条链路相连,因此,当需要进行一次全数据遍历的时候,B+树只需要使用O(log n )时间找到最小的一个节点,然后通过链进行O(N)的顺序遍历即可。而B树则需要对树的每一层进行遍历,这会需要更多的内置换次数,因此也就需要花费更多时间
- Mysql 为什么使用B+树
- 插入缓冲
- 索引数据存储在磁盘上,主键索引由于天然自增,无须磁盘的随机I/O,只需不断追加即可,但普通索引大概率无序,默认情况下需要进行随机磁盘I/O操作,效率极差
- 为了解决普通索引插入效率低下的问题,InnoDB 存储引擎引入 Insert Buffer 的概念,对于普通索引(非聚集索引)不是直接插入到索引页中,而是先判断插入的非聚集索引页是否在缓存池中,如果在直接插入,否则先放入 Insert buffer 对象中,然后以一定频率和辅助索引页子节点进行合并操作,此时通常能将多个插入合并到一个操作中,提高插入性能
- 二次写
InnoDB 索引页一般 16KB 大小,而操作系统写文件以 4KB 为单位,这就导致同一页需要分四块分别写入。此时就存在写完一块系统崩溃或者断电等特殊情况,此时就导致写入数据不完整的问题
二次写就是为了解决该问题,double write 分为两部分,一部分 doublewrite buffer,其大小 2MB,另一部分是磁盘上共享表空间中连续的 128 个页,也是 2KB
每次刷盘时这样处理:先将脏数据写入 doublewrite buffer,doublewrite buffer 每次 1MB 写入共享表空间的磁盘上,完成以上两步后调用 fsync 函数,将数据同步到各个表空间
如果操作系统在将页写入磁盘的过程中崩溃,InnoDB 重启发现页数据损坏后,可以从共享表的 doublewrite 中找到副本,用于数据恢复
- 自适应哈希索引
- InnoDB 虽然主要使用 B+ 树作为索引结构,但在某些特殊场景下用到哈希索引。InnoDB 会监控对表上索引的查找,如果发现某个索引频繁被访问,则建立哈希索引。InnoDB 会自动根据访问的频率和模式来为某些页建立哈希索引
- 预读
当 InnoDB 预计某些页很快就要被访问时,会异步加载对应页数据到缓冲池。该思路就类似空间局部性:如果某块内存被访问,那么它周围的内存大概率也会被访问。
InnoDB 采用两种预读算法提高 I/O 性能:线性预读 和 随机预读
线性预读:以块为单位,一块等于64页。如果某一块中的被顺序读取的页数超过预定值,则 InnoDB 将会异步的将下一块读取到 buffer pool 中
随机预读:以页为单位,当某一个块中的一些页在 buffer pool 中被发现时,InnoDB 会将该块中的剩余页一并读到 buffer pool 中,目前已废弃
- 悲观锁:正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度(悲观),因此,在整个数据处理过程中,将数据处于锁定状态,被关锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)
- 乐观锁:在关系型数据库中,乐观并发控制是一种并发控制的方法。它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在改事务读取数据后,有没有其他事务有修改了该数据。如果有其他事务有更新的话,正在提交的事务会进行回滚
- FROM:SELECT 是先执行FROM这一步的,在这个阶段,如果是多表查询,还会经历以下几个步骤
- 首先通过CROSS JOIN 求笛卡尔积,相当于得到虚拟表vt1
- 通过ON进行筛选,在虚拟vt1的基础上进行筛选,得到虚拟表vt2
- 添加外部行。如果我们使用的是左连接,右连接或者全连接,就会涉及到外部行,也就是在虚拟表vt1的基础上增加外部行,得到虚拟表vt3
- WHERE : 当我们拿到了查询数据表的原始数据,也就是最终的虚拟表vt1,就可以在此基础上再进行WHERE阶段。在这个阶段,会根据vt1表中的结果进行筛选过滤,得到虚拟表vt2
- GROUP,HAVING:然后进入到第三步和第四步,也就是GROUP和HAVING阶段,在这个阶段中,实际上是在虚拟表vt2的基础上进行分组和分组过滤,得到虚拟表vt3,vt4
- SELECT,DISTINCT:首先在SELECT阶段会提取想要的字段,然后再DISTINCT阶段过滤掉重复的行,分别得到虚拟表vt5-1 和 vt5-2
- ORDER BY:当我们提取了想要的字段数据之后,就可以按照指定的字段进行排序,得到虚拟表vt6
- LIMIT:在vt6的基础上,去除指定行的记录,得到最终的结果,得到虚拟表vt7
- 序列化(SERIALIZABLE):SERIALIZABLE 是最高的事务隔离级别,主要通过强制事务排序来解决幻读问题。简单来说,就是在每个读取的数据行上加上共享锁实现,这样就避免了脏读、不可重复读和幻读等问题。但是该事务隔离级别执行效率低下,且性能开销也最大,所以一般情况下不推荐使用。
- 可重复读(REPEATABLE READ):在可重复读隔离级别下,事务B只能在事务A修改过数据并提交后,自己也提交事务后,才能读取到事务B修改的数据。可重复读隔离解决解决了脏读和不可重复读的问题,但可能发生幻读问题
- 读已提交(READ COMMITTED):在读已提交隔离级别下,事务B只能在事务A修改修改过并且已提交后才能渠道到事务B修改的数据。读已提交隔离级别解决了脏读的问题,但可能发生不可重复读和幻读的问题
- 未提交读(READ UNCOMMITTED):在读未提交隔离级别下,事务A可能读取到事务B修改过但未提交的数据,可能发生脏读,不可重复读和幻读的问题
- 拓展:
- 脏读:脏读是指一个事务正在访问数据,并且对数据进行了修改,但是这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
- 不可重复读:在这个事务还没有结束时,另外一个事务也访问了该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
- 幻读:幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
- 先通过普通索引定位到主键值
- 在通过聚集索引定位到行记录
- like查询以“%”开头
- or语句前后没有同时使用索引;
- 组合索引中不是使用第一列索引;
- 在索引列上使用“IS NULL”或“IS NOT NULL”操作;
- 在索引字段上使用“not”,“<>”,“!=”等等。
- 数据的切分(Sharding)根据其切分规则的类型,可以分为两种垂直切分和水平切分模式
- 垂直分库:按照业务模块进行拆分,将不同模块的表拆分到不同的数据库中
- 垂直分表:按照字段将大表拆分成小表
- 水平分表:以字段为依据,按照一定策略(hash、range等),将一个表中的数据拆分到多个表中。
- 读写分离就是让主库处理事务性查询,从库处理select查询。数据库复制被用来把事务性查询导致的数据变更同步到从库,当然,主库也可以select查询。
- 主从复制:
- 对于主从复制,通常的操作是主库用来写入数据,从库用来读取数据,这样的好处是通过将读写压力分散开,避免了所有的请求都打在了主库上,同时通过从库进行水平拓展是系统的伸缩性及负载能力也得到了很大的提升
- 数据同步:在主从同步的过程中,主库会将所有的操作事件记录在binlog中,从库通过开启一个I/O线程保持与主库的通信,并在一定时间间隔内探测binlog日志文件是否发生改变,如果binlog日志发生了变化,主库生成一个binlog dump线程向从库I/O线程传送binlog。从库上的I/O线程将binlog赋值到自己的relay log 中。最终由从库中的SQL线程读取relay log 中的事件重放到从库上
- 主从复制延迟原因:
- 从库中的SQL重放的过程是随机写盘的,并且SQL线程是单线程的,因此数据来不及重放的话就会导致主从延迟。
- 主库并发高会导致写操作 不断写入binlog,对于SQL线程说可能会应接不暇,也会产生主从延迟
- 重放过程中遇到所等待也是产生延迟的原因之一
- 网络传输延迟
- 主从延迟处理
- Mysql5.6 版本以后通过并行复制的方式来解决SQL单线程产生的主从延迟问题。对于低版本来说,可以通过降低主库的并发来解决。如果对数据实时性要求比较严格的话,可以通过读主库来达到目的
- String(字符串,整数,浮点数):做简单的键值对缓冲
- set 往Redis里面插入一条Key-value 数据
- get 获取key的值
- incr 自增一
- decr 自减1
- mget 一次获取多个key的值
- List(列表):储存一些列表类型的数据结构
- lpush 从列表的最左边插入一个元素
- lpop 从列表的左边移除一个元素
- rpush 从列表list 的右边插入一个元素
- rpop 从列表list的右边移出一个元素
- llen 打印当前列表list的元素个数
- Set(无序集合):交集,并集,差集的操作
sadd: 往set中添加数据
srem 从set中删除数据
scard 查看set中存在的元素个数
sismember 查看set中是否存在某个数据
- sinter:两个key交集
- sdiff:两个key的差集
- sunion:两个key的所有value
- Hash(包含键值对的无序散列表):结构化的数据
- hget : 通过key值,从hash里取对应的value
- hst:往hash里添加key-value
- hmget:一次性获取多个key的value
- Zset(有序集合):去重同时也可以排序
- Zadd 添加数据
- Zrem 删除元素
- zcard 查询数据
- zrange 数据排序 从大到小
- zrevrange 数据排序 从小到大
- 过期策略
- 定期删除
- redis会将每个设置了过期时间的key放入到一个独立的字典中,以后会定期遍历这个字典来删除到期的key
- redis默认会每100ms扫描一次,过期扫描不会遍历过期字典中所有的key,而是采用了一种简单的贪心策略
- 从过期字典中随机20个key
- 删除这20个key中已经过期的key
- 如果过期的key比率超过1/4,那就重复步骤一
- 惰性删除
- 所为惰性删除就是在客户端访问这个key的时候,redis对key的过期时间进行检查
- 内存淘汰策略
noeviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键
allkeys-lru:加入键的时候,如果过限,首先通过LRU算法驱逐最久没有使用的键
volatile-lru:加入键的时候如果过限,首先从设置了过期时间的键集合中驱逐最久没有使用的键
allkeys-random:加入键的时候如果过限,从所有key随机删除
volatile-random:加入键的时候如果过限,从过期键的集合中随机驱逐
volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键
volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键
allkeys-lfu:从所有键中驱逐使用频率最少的键
- MULTI、EXEC、DISCARD和WATCH命令是REDIS中事务的基础,它们允许将多个命令组合在一起以事务的方式执行
- DISCARD命令用于清除所有先前在一个事务中放入队列的命令,然后恢复正常的连接状态。而当某个事物需要按条件执行时,就要使用WATCH命令将给定的键设置为受监控的,UNWATCH 清除事务中所有监控的键
- 事务的定义:Redis 的事务本质十一组命令的合集,一个事务中的命令要么全部执行,要么都不执行。事物的原理是先将属于一个事务的命令发送给Redis,存放到一个对列中,再让Redis执行这些命令。如果发送EXEC命令前客户端断线了,则Redis会清空事务队列,事务中的所有命令都不会执行,而一旦客户端发送了EXEC命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为Redis中已经记录了所有要执行的命令
- 特性:
- 原子性:Redis的原子性只能保证批量操作的一次性执行,和传统mysql事务不同的是,Redis不支持回滚,在执行EXEC命令时,如果Redis事务中某条命令执行失败,其后的命令仍然会被执行,没有回滚
- 隔离性:事务是⼀个单独的隔离操作,没有隔离级别的概念,事务队列中的命令在没有提交之前都不会实际的被执⾏。在事务中,所
有命令都会被序列化,按顺序地执⾏。事务在执⾏的过程中,其他客户端发送来的命令请求不会插⼊到事务执⾏命令序列中- 持久性:如果Redis运⾏在某种特定的持久化模式下时,事务也具有持久性。
- 错误处理:有语法错误时,都不会执行;运行错的时候,其他命令依然会执行
- 缓冲穿透:是指缓冲中没有但数据库中有的数据,这时由于并发用户特别多,同时读缓冲没读到数据,又同时去数据去取数据,引起数据库压力瞬间增大,造成过大压力
- 缓冲击穿:缓冲击穿是指缓冲中没有但是数据库中有的数据(一般是缓冲时间过期),这是由于并发用户特别多,同时读缓冲没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
- 缓冲雪崩:缓冲雪崩是指缓冲中数据批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓冲击穿不同的是, 缓冲击穿是只并发查同一条数据,缓冲雪崩是不同数据都过期了,很多数据都查不到从而查数据库
- 三种方式
- 主从复制
- 哨兵模式
- Redis-Cluster集群
- 工作方式:在redis的每一个节点上,都有这么两个东西,一个是插槽(slot),它的的取值范围是:0-16383。还有一个就是cluster,可以理解为是一个集群管理的插件。当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
为了保证高可用,
redis-cluster
集群引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。如果主节点A和它的从节点A1都宕机了,那么该集群就无法再提供服务了。
- 概述:在Redis主从同步中,一般只有一个Master进行数据的写操作,二会有多个salve进行读操作,定期的数据备份也是通过一个单独的slave进行实现,使得redis 的性能能够最大成都发挥出来,为了支持数据的弱一致性和最终一致性,我们并不需要保证Master与Slave之间的数据是实时同步,但是在一段时间后它们保存的数据是趋于同步的,从而满足最终一致性
- 主从同步的机制
- 第一次同步的时候,主节点会执行一次BGSAVE操作,并将之后的修改操作记录到内存的缓冲中,待完成后,会将全亮的RDB镜像文件同步到节点中,从节点接收到该镜像文件之后加载到内存中,加载完成后会发送消息通知主节点,将期间修改的操作,记录及增量数据同步到从节点,进行保存。也就是将某个时间点的全量数据同步完之后,再将该时间点之后的增量数据进行存储,进而实现整个同步过程
- 全同步:
- salve节点请求增量同步
- master 检查 replid不一致,拒绝增量同步,开始全量同步
- master将完整的内存数据生成RDB文件,发送给slave
- slave清空本地缓冲,加载RDB文件
- master将RDB期间接收到的命令记录在repl_baklog,并持续将log中的命令发送给slave
- slave执行接收到的命令,与master保持同步
- 增量同步:
- salve 请求增量同步
- master检查 replid 是否一致
- 不一致:全量同步
- 一致:去repl_baklog获取offset后的数据
- 发送offset后的命令
- 执行命令、
- 概念:
- Elasticsearch(简称ES)是一个基于Apache Lucene™的开源搜索引擎,无论在开源还是专有领域,Lucene 可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。注意,Lucene 只是一个库。想要发挥其强大的作用,你需使用 Java 并要将其集成到你的应用中。
- 特性:
- 分布式的实时文件存储,每个字段都被索引并可被搜索
- 实时分析的分布式搜索引擎
- 可以拓展到上百台服务器,处理PB级结构化或非机构化数据
- 基本概念:
- 倒排索引
- 倒排索引也叫反向索引,有反向索引必有正向索引。正向索引是通过key找value,反向索引则是通过value找key
- 分词
- 搜索引擎三大过程:
- 爬取内容
- 进行分词
- 建立反向索引
- 介绍:
- meiliSearch 是一个功能强大,快速,开源,易于使用和部署的搜索引擎。所所和索引都是高度定制的。允许输入、过滤器和同义词等特性都是开箱即用的。是近两年开源的项目,同样也支持中文分词,在小数据规模下可以实现比Es更加快速和易用的搜索引用。
- 消息队列
- 点对点模式
- 一个具体的消息只能由一个消费者消费。多个生产者可以向同一个消息队列发送消息;但是,一个消息在被一个消息者处理的时候,这个消息在队列上会被锁住或者被移除并且其他消费者无法处理该消息。需要额外注意的是,如果消费者处理一个消息失败了,消息系统一般会把这个消息放回队列,这样其他消费者可以继续处理
- 发布/订阅模式
- 单个消息可以被多个订阅者并发的获取和处理,一般来说,订阅有两种类型
- 临时订阅,这种订阅只有在消费者启动并运行的时候才存在。一旦消费者退出,相应的订阅以及尚未处理的消息就会丢死
- 持久订阅么这种订阅会一直存在,除非主动去删除。消费者退出后,消息系统会继续维护该订阅,并且后续消息可以被基础处理
- 原理
- RabbitMQ是一个纯java、分布式、队列模型的开源消息中间件,前身是MetaQ,是阿里参考Kafka特点研发的一个队列模式的消息中间件,后开源给apache基金会成为了apache的顶级开源项目,具有高性能、高可靠、高实时、分布式的特点
- AMQP协议
- Server :接收客户端的连接,实现AMQP实体服务
- Connection:连接,应用程序与Server的网络连接,TCP连接
- Channel:信道,消息读写等操作在信道中执行。客户端可以建立多个信道,每隔信道代表一个会话任务
- Message:消息,应用程序和服务器之间传送的数据,消息可以非常简单,也可以很很复杂。由Properties和Body组成。Properties为外包装,可以对消息进行修饰,比如消息的优先级、延迟等高级特性;Body就是消息体内容
- Virtual Host:虚拟主机,用于逻辑隔离。一个虚拟主机里面可以有若干个Exchange和Queue,同一个虚拟主机里不能有相同名称的Exchange和Queue
- Exchange:交换器,接收消息,按照路由规则将消息路由到一个或者多个队列。如果路由找不到,或者返回给生产者,或者直接丢弃。RabbitMQ常用的交换器类型有direct、topic、fanout、headers四种
- Binding:绑定,交换器和消息队列之间的虚拟连接,绑定中可以包含一盒或者多核RoutingKey
- RoutingKey:路由键,生产者将消息发送给交换器的时候,会发送一个RoutingKey,用来指定路由规则,这样交换器就知道把消息发送到哪儿个队列。路由键通常 为一个“.”分割的字符串
- Queue:消息队列,用来保存消息,供消费者消费
- Rabbit常用的交换器类型
- Direct Exchange:直连交换机,意思是次交换机需要绑定一个队列,要求该消息与一个特定的路由键完全匹配。简单点说就是一对一的,点对点的发送
- Fanout Exchange:这种类型的交换机需要将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。交单点说就是发布订阅
- Topic Exchange:直接翻译的话叫做主体交换机,如果从用法上面翻译可能叫通配符交换机会更加贴切。这种交换机是使用通配符去匹配,路由到对应的队列,通配符有两种:“*”、“#”。需要注意的是通配符前面必须要加上“.”符号
- * 符号, 只匹配一个词。比如a.*可以匹配到“a.b”、"a.c",但是匹配不了"a.b.c"
- # 符号:匹配一个或多个词。比如"rabit.#"可以匹配到"rabbit.a.b"、"rabbit.a"
- Headers Exchange:这种交换机用的相对没这么多。它跟上面三种有点区别,它的路由不适用routingKey进行路由分配,而是在匹配请求头中键值进行路由。创建队列需要设置绑定的头部信息,有两种模式:全部匹配和部分匹配。如上图所示:交换机会根据生产者发送过来的头部信息修改的键值去匹配队列绑定的键值,路由到对应的队列
- 消费原理
- 基本概念
- broker:每个节点运行的服务程序,功能为维护该节点的队列的增删以及转发队列操作请求
- master queue:每个队列都分为一个主队列和若干个镜像队列
- mirror queue:镜像队列,作为master queue的备份。在master queue所有节点挂掉之后,系统把mirror queue 提升为master queue。负责处理客户端队列操作请求
- 高级特性
- 过期时间:
- Time To Live,也就是生存时间,是一条消息在队列中的最大存活时间,单位是毫秒,下面看看RabbitMQ过期时间特性:
RabbitMQ可以对消息和队列设置TTL。
RabbitMQ支持设置消息的过期时间,在消息发送的时候可以进行指定,每条消息的过期时间可以不同。
RabbitMQ支持设置队列的过期时间,从消息入队列开始计算,直到超过了队列的超时时间配置,那么消息会变成死信,自动清除。
如果两种方式一起使用,则过期时间以两者中较小的那个数值为准。
当然也可以不设置TTL,不设置表示消息不会过期;如果设置为0,则表示除非此时可以直接将消息投递到消费者,否则该消息将被立即丢弃。
消息确认:
为了保证消息从队列可靠地到达消费者,RabbitMQ提供了消息确认机制。消费者订阅队列的时候,可以指定autoAck参数,当autoAck为true的时候,RabbitMQ采用自动确认模式,RabbitMQ自动把发送出去的消息设置为确认,然后从内存或者硬盘中删除,而不管消费者是否真正消费到了这些消息。当autoAck为false的时候,RabbitMQ会等待消费者回复的确认信号,收到确认信号之后才从内存或者磁盘中删除消息。
消息确认机制是RabbitMQ消息可靠性投递的基础,只要设置autoAck参数为false,消费者就有足够的时间处理消息,不用担心处理消息的过程中消费者进程挂掉后消息丢失的问题。
持久化
消息的可靠性是RabbitMQ的一大特色,那么RabbitMQ是如何保证消息可靠性的呢?答案就是消息持久化。持久化可以防止在异常情况下丢失数据。RabbitMQ的持久化分为三个部分:交换器持久化、队列持久化和消息的持久化。
消息的可靠性是RabbitMQ的一大特色,那么RabbitMQ是如何保证消息可靠性的呢?答案就是消息持久化。持久化可以防止在异常情况下丢失数据。RabbitMQ的持久化分为三个部分:交换器持久化、队列持久化和消息的持久化。
队列的持久化能保证其本身的元数据不会因异常情况而丢失,但是不能保证内部所存储的消息不会丢失。要确保消息不会丢失,需要将其设置为持久化。队列的持久化可以通过在声明队列时将durable参数设置为true。
设置了队列和消息的持久化,当RabbitMQ服务重启之后,消息依然存在。如果只设置队列持久化或者消息持久化,重启之后消息都会消失。
设置了队列和消息的持久化,当RabbitMQ服务重启之后,消息依然存在。如果只设置队列持久化或者消息持久化,重启之后消息都会消失。
死信队列
当消息在一个队列中变成死信之后,他能被重新发送到另一个交换器中,这个交换器成为死信交换器,与该交换器绑定的队列称为死信队列。消息变成死信有下面几种情况:
消息被拒绝。
消息过期
队列达到最大长度
DLX也是一个正常的交换器,和一般的交换器没有区别,他能在任何的队列上面被指定,实际上就是设置某个队列的属性。当这个队列中有死信的时候,RabbitMQ会自动将这个消息重新发送到设置的交换器上,进而被路由到另一个队列,我们可以监听这个队列中消息做相应的处理。
死信队列有什么用?当发生异常的时候,消息不能够被消费者正常消费,被加入到了死信队列中。后续的程序可以根据死信队列中的内容分析当时发生的异常,进而改善和优化系统。
延迟队列
一般的队列,消息一旦进入队列就会被消费者立即消费。延迟队列就是进入该队列的消息会被消费者延迟消费,延迟队列中存储的对象是的延迟消息,“延迟消息”是指当消息被发送以后,等待特定的时间后,消费者才能拿到这个消息进行消费
延迟队列用于需要延迟工作的场景。最常见的使用场景:淘宝或者天猫我们都使用过,用户在下单之后通常有30分钟的时间进行支付,如果这30分钟之内没有支付成功,那么订单就会自动取消。除了延迟消费,延迟队列的典型应用场景还有延迟重试。比如消费者从队列里面消费消息失败了,可以延迟一段时间以后进行重试。
- 什么是mongonDB
- 非关系型数据库(nosql ),属于文档型数据库。先解释一下文档的数据库,即可以存放xml、json、bson类型系那个的数据。这些数据具备自述性,呈现分层的树状数据结构。数据结构由键值(key=>value)对组成。
- 存储方式
- 虚拟内存+持久化
- 适合场景
- 游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、更新
- 物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。
- 社交场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能
- 物联网场景,使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析
- 视频直播,使用 MongoDB 存储用户信息、礼物信息等
- 架构特点
- 分片存储,分片是将数据水平切分到不同的物理节点。当应用数据越来越大的时候,数据量也会越来越大。当数据量增长是,单台机器有可能无法存储数据或可接受的读取谢日吞吐量。利用分片技术可以添加更多的机器来应对数据量增加以及读写操作的要求
- 数据处理
- 数据是存储在硬盘上的,只不过需要经常读的数据会被加载到内存中,将数据存储在物理内存中,从而达到告诉读写
- redis memcache
- 概念
- Kafka是有Apache软件基金会发布的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式分布订阅消息系统,他可以处理消费者在网站上的所有动作流数据。它是一个分布式的,支持多分区、多副本,计入Zookeeper的分布式消息流平台,它同时也是一款开源的基于发布订阅模式的消息引擎系统
- 基本术语
- 消息
- kafka 中的数据单元被称为消息,也被称为记录,可以把它看做数据库表中的某一行的记录
- 批次
- 为了提高效率,消息会分批次写入kafka,批次就代表的是一组消息
- 主题
- 消息的种类称为主题,可以说一个主题代表了一类消息,相当于是对消息进行分类。主题就像是数据库中的表
- 分区
- 主题可以被分为若干个分区,同一个主体中的分区可以不在一个机器上,有可能会被部署在多个机器上,由此来实现kafka的伸缩性,单一主题中的分区有序
- 生产者
- 向主体发布消息的客户端应用程序被称为生产者,生产者将源源不断的向某个主题发送消息
- 消费者
- 订阅主题消息的客户端程序成为消费者,消费者用户处理生产者产生的消息
- 消费者群组
- 一个生产者对应多个消费者,消费者群组就是指由一个或多个消费者组成的群体
- 偏移量
- 偏移量是一种元数据,他是一个不断递增的整数值,用于记录消费者发生重平衡时候的位置,以便用来恢复数据
- broker
- 一个独立的kafka服务器就被称为broker,borker接受来自生产者的消息,为消息设置偏移量,并提交消息到磁盘
- broker集群
- broker 是几群的组成部分,broker集群由一个或多个broker组成,每个集群都有一个broker同时充当了集群控制器的角色
- 副本
- kafka中消息的备份有叫做副本,副本的数量是可以配置的,kafka定义了两类副本;领导者副本和追随者副本,前者对外提供服务,后者只是被动跟随
- 重平衡
- 消费者组内某个消费者实例挂掉之后,其他消费者实例自动重新分配,订阅主题分区的过程。
- 特性
- 高吞吐、低延迟::kafka最大的特点就是收发消息非常快,kafka每秒可以处理几十万条消息,它的最低延迟只有几毫秒。
- 高伸缩性:每个主题(topic)包含多个分区(partition),主题中的分区可以费能不在不同的主机(broker)中。
- 持久性、可靠性:kafka能够允许数据的持久化存储,消息被持久化到磁盘,并支持数据备份防止数据丢失,kafka底层的数据存储是基于Zookeeper存储的,Zookeper我们知道它的数据能够持久存储。
- 容错性:允许集群中的节点失败,某个节点宕机,kafka集群能够正常工作。
- 高并发:支持竖数千个客户端的同时读写
- 适用场景
- 活动追踪:可以用来追踪用户的行为。
- 传递消息:应用程序向用户发送通知就是通过传递消息来实现的,这些应用组件可以生成消息,而不需要关心消息的格式,更不需要关心消息是怎么发送的。
- 度量指标:用来记录运营的监控数据。包括收集各种分布式应用的数据,生产各种操作的几种反馈,比如警报和报告
- 日志记录:kafka的基本盖面来源于提交日志,比如我们可以把数据库的更新发送到kafka上,用来记录数据库的更新时间,通过kafka以统一接口服务的方式开放给各种consumer、例如Hadoop、HBASE、Solr等
- 流式处理:流式处理有一个能够提供多种应用程序的领域
- 限制削峰:kafka多用于互联网领域某一时刻请求特别多的情况下,可以把请求写入kafka中,避免直接请求后端程序导致服务崩溃。
- 为什么快
Kafka实现了零拷贝原理来快速移动数据,避免了内核之间的切换。Kafka可以将数据记录分批发送,从生产者到文件系统到消费者,可以端到端的查看这些批次的数据
批处理能够进行更有效的数据压缩并减少I/O延迟,Kafka采取顺序写入磁盘的方式,避免了随机磁盘寻址的浪费。
- 顺序读写
- 零拷贝
- 消息压缩
- 分批发送