拓展:
为什么java wait/notify 必须与synchronized(同步块)一起使用
[为了避免「lost wake up 问题」,即「无法唤醒问题」]
synchronized如何实现锁
HashMap 的原理?当谈到线程不安全时自然引申出 ConcurrentHashMap ,它的实现原理?
volatile 是什么?可以保证有序性吗?
一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他
线程来说是立即可见的,volatile关键字会强制将修改的值立即写入主存。
2)禁止进行指令重排序。
使用 Volatile 一般用于 状态标记量 和 单例模式的双检锁
装箱就是自动将基本数据类型转换为包装器类型(int–>Integer);调用方法:Integer的valueOf(int) 方法
拆箱就是自动将包装器类型转换为基本数据类型(Integer–>int)。调用方法:Integer的intValue方 法
拓展:
java八大基本类型(char、boolean、byte、short、int、long、float、double)
为什么需要包装类?Java是一种面向对象语言,无法将int 、double等类型放进去的。因为集合的容器要求元素是Object类型。
Integer i1 = 100; Integer i2 = 100; Integer i3 = 200; Integer i4 = 200;
System.out.println(i1==i2); true(自动拆装箱与缓存。只适用于整数值区间-128 至 +127。)
System.out.println(i3==i4); false
double g = 1 / 3;
System.out.printf("%.2f", g); // 结果为什么为0
属性、方法、内部类、构造方法、代码块。
使用Bigdecimal类进行浮点型数据的运算
拓展:
math类有那些常用方法?
Pow():幂运算 Sqrt():平方根 Round():四舍五入
Abs():求绝对值 Random():生成一个0-1的随机数,包括0不包括1
可以重载,但不能重写。
charAt:返回指定索引处的字符
indexOf():返回指定字符的索引
replace():字符串替换
trim():去除字符串两端空白
split():分割字符串,返回一个分割后的字符串数组
getBytes():返回字符串的byte类型数组
length():返回字符串长度
toLowerCase():将字符串转成小写字母
toUpperCase():将字符串转成大写字符
substring():截取字符串
format():格式化字符串
equals():字符串比较
List—是一个有序的集合,可以包含重复的元素,提供了按索引访问的方式,它继承Collection。
List有两个重要的实现类:ArrayList和LinkedList
ArrayList: 可以看作是能够自动增长容量的数组
ArrayList的toArray方法返回一个数组
ArrayList的asList方法返回一个列表
ArrayList底层的实现是Array, 数组扩容实现
LinkList是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于
ArrayList.当然,这些对比都是指数据量很大或者操作很频繁
Error和Exception都是java错误处理机制的一部分,都继承了Throwable类。
Exception表示的异常,异常可以通过程序来捕捉,或者优化程序来避免。
Error表示的是系统错误,不能通过程序来进行错误处理。
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况 exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况
NIO即New IO,这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO 主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
拓展:
NIO 主要有三大核心部分: Channel(通道), Buffer(缓冲区), Selector。传统 IO 基于字节流和字符流进行操作, 而 NIO 基于 Channel 和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。 Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。 NIO 和传统 IO 之间第一个最大的区别是, IO 是面向流的, NIO 是面向缓冲区的。
除了使用new创建对象之外,还可以用什么方法创建对象?使用Java反射可以创建对象!
1、使用 Class 对象的 newInstance()方法来创建该 Class 对象对应类的实例,但是这种方法要求该 Class 对象对应的类有默认的空构造器。
2、先使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance()方法来创建 Class 对象对应类的实例,通过这种方法可以选定构造方法创建实例
什么是java序列化,如何实现java序列化?
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
序列化 ID
虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 privatestatic final long serialVersionUID
Transient 关键字阻止该变量被序列化到文件中
@Target 修饰的对象范围
@Retention 定义 被保留的时间长短
@Documented 描述-javadoc
@Inherited 阐述了某个被标注的类型是被继承的
拓展:什么叫注解
Annotation(注解)是 Java 提供的一种对元程序中元素关联信息和元数据(metadata)的途径和方法。 Annatation(注解)是一个接口,程序可以通过反射来获取指定程序中元素的 Annotation对象,然后通过该 Annotation 对象来获取注解中的元数据信息。
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系
统的稳定性,使用线程池可以进行统一的分配,调优和监控
拓展:
线程生命周期(状态)?
当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5 种状态。尤其是当线程启动以后,它不可能一直"霸占"着 CPU 独自运行,所以 CPU 需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换
线程池的组成
//线程池的几个核心参数的意义?
// 提问:若corePoolSize满了之后,新来的请求是新建线程吗?
//答:若corePoolSize满了之后,则新添加的任务会被添加到BlockingQueue这个队列中等待处理,如果队列满了,才创建非核心线程执行任务。
// keepAliveTime:非核心线程闲置超时时间(当线程池的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池的线程数不大于corePoolSize。)
// RejectedExecutionHandler:拒绝策略(当线程无法执行新任务(一般是由于线程池的线程数量已经达到最大数(maximumPoolSize)或者线程池关闭导致的)默认情况下当线程池无法处理新线程,会抛出RejectedExecutionException。)
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
Java8使用并行流(ParallelStream)注意事项
乐观锁[如:共享锁ReadWriteLock]
乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。java 中的乐观锁基本都是通过 CAS 操作实现的
悲观锁[如:独占锁ReentrantLock]
悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会 block 直到拿到锁。java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如 RetreenLock。
自旋锁
自旋锁原理非常简单, 如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。线程自旋是需要消耗 cpu的,说白了就是让 cpu 在做无用功,如果一直获取不到锁,那线程也不能一直占用 cpu自旋做无用功,所以需要设定一个自旋等待的最大时间。
如果持有锁的线程执行的时间超过自旋等待的最大时间扔没有释放锁,就会导致其它争用锁的线程在最大等待时间内还是获取不到锁,这时争用线程会停止自旋进入阻塞状态。
阻塞队列,关键字是阻塞,先理解阻塞的含义,在阻塞队列中,线程阻塞有这样的两种情况:
线程独占:栈,本地方法栈,程序计数器
线程共享:堆,方法区
线程私有数据区域生命周期与线程相同, 依赖用户线程的启动/结束 而 创建/销毁(在 Hotspot VM 内, 每个线程都与操作系统的本地线程直接映射, 因此这部分内存区域的存/否跟随本地线程的生/死对应)。线程共享区域随虚拟机的启动/关闭而创建/销毁。直接内存并不是 JVM 运行时数据区的一部分, 但也会被频繁的使用: 在 JDK 1.4 引入的 NIO 提供了基于 Channel 与 Buffer 的 IO 方式, 它可以使用 Native 函数库直接分配堆外内存, 然后使用DirectByteBuffer 对象作为这块内存的引用进行操作(详见: Java I/O 扩展), 这样就避免了在 Java堆和 Native 堆中来回复制数据, 因此在一些场景中可以显著提高性能。
Java 中堆和栈有什么区别?web传输的数据存放在哪?
JVM 中堆和栈属于不同的内存区域,使用目的也不同。栈常用于保存方法帧和局部变量,而对象总是在堆上分配。栈通常都比堆小,也不会在多个线程之间共享,而堆被整个 JVM 的所有线程共享。
功能不同\共享性不足\异常错误不同\空间大小
堆(Heap-线程共享) -运行时数据区 也叫JVM 运行时内存
是被线程共享的一块内存区域, 创建的对象和数组都保存在 Java 堆内存中,也是垃圾收集器进行垃圾收集的最重要的内存区域。 由于现代VM 采用分代收集算法, 因此 Java 堆从 GC 的角度还可以细分为: 新生代(Eden 区、 From Survivor 区和 To Survivor 区)和老年代。
JAVA8 与元数据
在 Java8 中, 永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。元空间的本质和永久代类似,元空间与永久代之间最大的区别在于: 元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。 类的元数据放入nativememory, 字符串池和类的静态变量放入 java 堆中, 这样可以加载多少类的元数据就不再由MaxPermSize 控制, 而由系统的实际可用空间来控制。
可达性分析?标记清除算法?复制算法?
Minor GC与Full GC分别在什么时候发生?
新生代内存不够用时候发生MGC也叫YGC,JVM内存不够的时候发生FGC
当你将你的应用从 32 位的 JVM 迁移到 64 位的 JVM 时,由于对象的指针从32 位增加到了 64 位,因此堆内存会突然增加,差不多要翻倍。这也会对 CPU缓存(容量比内存小很多)的数据产生不利的影响。因为,迁移到 64 位的 JVM主要动机在于可以指定最大堆大小,通过压缩OOP 可以节省一定的内存。通过-XX:+UseCompressedOops 选项,JVM 会使用 32 位的 OOP,而不是 64 位的 OOP。
理论上说上 32 位的 JVM 堆内存可以到达 2^32,即 4GB,但实际上会比这个小很多。不同操作系统之间不同,如 Windows 系统大约 1.5GB,Solaris 大约3GB。
64 位 JVM 允许指定最大的堆内存,理论上可以达到 2^64,这是一个非常大的数字,实际上你可以指定堆内存大小到 100GB。甚至有的 JVM,如 Azul,堆内存到 1000G 都是可能的。
Sun JDK监控和故障处理命令有jps jstat jmap jhat jstack jinfo
@Component 是单例吗?
@Autowired 和 @Resource 区别?
分别为 singleton(单例)、prototype(原型)、request、session 和 global session
singleton:单例模式(多线程下不安全)
prototype:原型模式每次使用时创建
Request:一次 request 一个实例
AOP(Aspect Orient Programming)是软件设计领域中的面向切面编程。AOP 两种代理方式?JDKProxy 和 Cglib
1、切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象
2、横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。
3、连接点(joinpoint):被拦截到的点,因为 Spring 只支持方法类型的连接点,所以在 Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器。
4、切入点(pointcut):对连接点进行拦截的定义
5、通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。
6、目标对象:代理的目标对象
7、织入(weave):将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。
1.默认使用 JDK 动态代理,这样便可以代理所有的接口类型(interface)
2.Spring AOP也支持CGLIB的代理方式。如果我们被代理对象没有实现任何接口,则默认是CGLIB
3.我们可以强制使用CGLIB,指定proxy-target-class = “true” 或者 基于注解@EnableAspectJAutoProxy(proxyTargetClass = true)
// 询问,以下代码有问题吗?
@Component
public class Test {
@DataSource
public boolean product() {
api();
}
@SentinelResource(value = "test")
public boolean api() {
.....
return true;
}
}
Java 事务编程接口(JTA:Java Transaction API)和 Java 事务服务 (JTS;Java TransactionService) 为 J2EE 平台提供了分布式事务服务。分布式事务(Distributed Transaction)包括事务管理器(Transaction Manager)和一个或多个支持 XA 协议的资源管理器 ( ResourceManager )。我们可以将资源管理器看做任意类型的持久化数据存储;事务管理器承担着所有事务参与单元的协调与控制。
public void transferAccount() {
UserTransaction userTx = null;
Connection connA = null; Statement stmtA = null;
Connection connB = null; Statement stmtB = null;
try {
// 获得 Transaction 管理对象
userTx = (UserTransaction)getContext().lookup("java:comp/UserTransaction");
connA = getDataSourceA().getConnection();// 从数据库 A 中取得数据库连接
connB = getDataSourceB().getConnection();// 从数据库 B 中取得数据库连接
userTx.begin(); // 启动事务
stmtA = connA.createStatement();// 将 A 账户中的金额减少 500
stmtA.execute("update t_account set amount = amount - 500 where account_id = 'A'");
// 将 B 账户中的金额增加 500
stmtB = connB.createStatement(); stmtB.execute("update t_account set amount = amount + 500 where account_id = 'B'");
userTx.commit();// 提交事务
// 事务提交:转账的两步操作同时成功(数据库 A 和数据库 B 中的数据被同时更新)
} catch(SQLException sqle){
// 发生异常,回滚在本事务中的操纵
userTx.rollback();// 事务回滚:数据库 A 和数据库 B 中的数据更新被同时撤销
} catch(Exception ne){ }
}
XA和2PC
XA 与 AT
Seata实现2PC要点 :
1、全局事务开始使用GlobalTransactional标识。
2、每个本地事务方案仍然使用@Transactional标识。
3、每个数据都需要创建undo_log表,此表是Seata保证本地事务一致性的关键。
Mybatis 中有一级缓存和二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的。一级缓存是指 SqlSession 级别的缓存,当在同一个 SqlSession 中进行相同的 SQL 语句查询时,第二次以后的查询不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存 1024 条 SQL。二级缓存是指可以跨 SqlSession 的缓存。是 mapper 级别的缓存,对于 mapper 级别的缓存不同的
sqlsession 是可以共享的。
第一次发出一个查询 sql,sql 查询结果写入 sqlsession 的一级缓存中,缓存使用的数据结构是一
个 map。
key:MapperID+offset+limit+Sql+所有的入参
value:用户信息
同一个 sqlsession 再次发出相同的 sql,就从缓存中取出数据。如果两次中间出现 commit 操作(修改、添加、删除),本 sqlsession 中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存。
二级缓存的范围是 mapper 级别(mapper 同一个命名空间),mapper 以命名空间为单位创建缓存数据结构,结构是 map。mybatis 的二级缓存是通过 CacheExecutor 实现的。CacheExecutor其实是 Executor 的代理对象。所有的查询操作,在CacheExecutor 中都会先匹配缓存中是否存在,不存在则查询数据库。
key:MapperID+offset+limit+Sql+所有的入参
具体使用需要配置:
Netty 是一个高性能、异步事件驱动的 NIO 框架,基于 JAVA NIO 提供的 API 实现。它提供了对TCP、UDP 和文件传输的支持,作为一个异步 NIO 框架,Netty 的所有 IO 操作都是异步非阻塞的,通过 Future-Listener 机制,用户可以方便的主动获取或者通过通知机制获得 IO 操作结果。
异步通讯 NIO
零拷贝(DIRECT BUFFERS 使用堆外直接内存)
内存池(基于内存池的缓冲区重用机制)
Reactor 单线程模型, Reactor 多线程模型, 主从 Reactor 多线程模型。
无锁设计、线程绑定
高性能的序列化框架
JAVA 一般使用动态代理方式实现远程调用。
客户端的请求消息结构一般需要包括以下内容:(接口名称+方法名+参数类型和参数值+超时时间+ requestID)
HTTP 是一个无状态的协议。无状态是指客户机(Web 浏览器)和服务器之间不需要建立持久的连接,这意味着当一个客户端向服务器端发出请求,然后服务器返回响应(response),连接就被关闭了,在服务器端不保留连接的有关信息.HTTP 遵循请求(Request)/应答(Response)模型。客户机(浏览器)向服务器发送请求,服务器处理请求并返回适当的应答。所有 HTTP 连接都被构造成一套请求和应答。
1.地址解析,如用客户端浏览器请求这个页面:http://localhost.com:8080/index.htm 从中分解出协议名、主机名、端口、对象路径等部分,对于我们的这个地址,解析得到的结果如下:
协议名:http
主机名:localhost.com
端口:8080
对象路径:/index.htm
在这一步,需要域名系统 DNS 解析域名 localhost.com,得主机的 IP 地址。
2.封装 HTTP 请求数据包
3.封装成 TCP 包并建立连接,TCP 的三次握手
4.客户机发送请求命令。客户机发送请求命令:建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资
源标识符(URL)、协议版本号,后边是 MIME 信息包括请求修饰符、客户机信息和可内容。
5.服务器响应
服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是 MIME 信息包括服务器信息、实体信息和可能的内容。
6.服务器关闭 TCP 连接
服务器关闭 TCP 连接:一般情况下,一旦 Web 服务器向浏览器发送了请求数据,它就要关闭 TCP 连接,然后如果浏览器或者服务器在其头信息加入了这行代码 Connection:keep-alive,TCP 连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。
拓展:
HTTP 状态码列举和含义
1)为什么用了 HTTPS 就是安全的?
2)HTTPS 的底层原理如何实现?HTTPS 在内容传输的加密上使用的是对称加密,非对称加密只作用在证书验证阶段。
3)用了 HTTPS 就一定安全吗?
考一下思路,saas系统,有个接口耗时又比较久,一个接口请求耗时好几秒,一个企业又有多个店铺,一个店铺可以发起多次分页请求。如何设计?qps动态限流,最高不能超过5。如何设计一个100万个店铺的请求。
角色与 Follower 类似,但是无投票权。Zookeeper 需保证高可用和强一致性,为了支持更多的客户端,需要增加更多 Server;Server 增多,投票阶段延迟增大,影响性能;引入 Observer,Observer 不参与投票; Observers 接受客户端的连接,并将写请求转发给 leader 节点; 加入更多 Observer 节点,提高伸缩性,同时不影响吞吐率。
拓展:
服务注册发现改为阿里巴巴的Nacos而不用 ZooKeeper? nacos 底层不是用zookeeper ,服务发现要满足高可用
zookeeper是CP,如果低于三台,挂了一台(无论是leader还是follower节点),集群都不能正常工作。
nacos 可以AP, 三台挂一台没问题。
Kafka
该内容暂无法显示 - 知乎
https://mp.wexin.qq.com/s/MMNV78WfLCW4jhWT6F05HQ
Apache Kafka 是一个分布式数据流处理平台,可以实时发布、订阅、存储和处理数据流。它设计为处理多种来源的数据流,并将它们交付到多个消费者
熟知一个规律:在大数据分布式文件系统里面,95% 的都是主从式的架构,个别是对等式的架构,比如 ElasticSearch。
Kafka 也是主从式的架构,主节点就叫 Controller,其余的为从节点,Controller 是需要和 Zookeeper 进行配合管理整个 Kafka 集群。
Kafka 严重依赖于 Zookeeper 集群,所有的 Broker 在启动的时候都会往 Zookeeper 进行注册,目的就是选举出一个 Controller。
这个选举过程非常简单粗暴,就是一个谁先谁当的过程,不涉及什么算法问题。
那成为 Controller 之后要做啥呢,它会监听 Zookeeper 里面的多个目录,例如有一个目录 /brokers/,其他从节点往这个目录上**注册(就是往这个目录上创建属于自己的子目录而已)**自己。
这时命名规则一般是它们的 id 编号,比如 /brokers/0,1,2。注册时各个节点必定会暴露自己的主机名,端口号等等的信息。
此时 Controller 就要去读取注册上来的从节点的数据(通过监听机制),生成集群的元数据信息,之后把这些信息都分发给其他的服务器,让其他服务器能感知到集群中其它成员的存在。
此时模拟一个场景,我们创建一个主题(其实就是在 Zookeeper 上 /topics/topicA 这样创建一个目录而已),Kafka 会把分区方案生成在这个目录中。
此时 Controller 就监听到了这一改变,它会去同步这个目录的元信息,然后同样下放给它的从节点,通过这个方法让整个集群都得知这个分区方案,此时从节点就各自创建好目录等待创建分区副本即可。这也是整个集群的管理机制。
1、顺序写
操作系统每次从磁盘读写数据的时候,需要先寻址,也就是先要找到数据在磁盘上的物理位置,然后再进行数据读写,如果是机械硬盘,寻址就需要较长的时间。
Kafka 的设计中,数据其实是存储在磁盘上面,一般来说,会把数据存储在内存上面性能才会好。
但是 Kafka 用的是顺序写,追加数据是追加到末尾,磁盘顺序写的性能极高,在磁盘个数一定,转数达到一定的情况下,基本和内存速度一致。
2、零拷贝
Kafka 利用了 Linux 的 sendFile 技术(NIO),省去了进程切换和一次数据拷贝,让性能变得更好
非零拷贝
答:由于领导者的主要角色是执行分区的所有读写请求的任务,而追随者被动地复制领导者。因此,在领导者失败时,其中一个追随者接管了领导者的角色。基本上,整个过程可确保服务器的负载平衡。
因为在具体开发中某些环节考虑使用kafka却担心有消息丢失的风险,本周结合项目对kafka的消息可靠性做了一下调研和总结:
首先明确一下丢消息的定义。kafka集群中的部分或全部broker挂了,导致consumer没有及时收到消息,这不属于丢消息。broker挂了,只要消息全部持久化到了硬盘上,重启broker集群之后,使消费者继续拉取消息,消息就没有丢失,仍然全量消费了。
以我的理解,所谓丢消息,意味着:开发人员未感知到哪些消息没有被消费。
我把消息的丢失归纳了以下几种情况:
1)、 producer把消息发送给broker,因为网络抖动,消息没有到达broker,且开发人员无感知。
解决方案:producer设置acks参数,消息同步到master之后返回ack信号,否则抛异常使应用程序感知到并在业务中进行重试发送。这种方式一定程度保证了消息的可靠性,producer等待broker确认信号的时延也不高。
2)、 producer把消息发送给broker-master,master接收到消息,在未将消息同步给follower之前,挂掉了,且开发人员无感知。
解决方案:producer设置acks参数,消息同步到master且同步到所有follower之后返回ack信号,否则抛异常使应用程序感知到并在业务中进行重试发送。这样设置,在更大程度上保证了消息的可靠性,缺点是producer等待broker确认信号的时延比较高。
3)、 producer把消息发送给broker-master,master接收到消息,master未成功将消息同步给每个follower,有消息丢失风险。
解决方案:同上。
4)、 某个broker消息尚未从内存缓冲区持久化到磁盘,就挂掉了,这种情况无法通过ack机制感知。
解决方案:设置参数,加快消息持久化的频率,能在一定程度上减少这种情况发生的概率。但提高频率自然也会影响性能。
5)、consumer成功拉取到了消息,consumer挂了。
解决方案:设置手动sync,消费成功才提交。
综上所述,集群/项目运转正常的情况下,kafka不会丢消息。一旦集群出现问题,消息的可靠性无法完全保证。要想尽可能保证消息可靠,基本只能在发现消息有可能没有被消费时,重发消息来解决。所以在业务逻辑中,要考虑消息的重复消费问题,对于关键环节,要有幂等机制
优点:
可扩展:Kafka集群可以透明的扩展,增加新的服务器进集群。
高性能:Kafka性能远超过传统的ActiveMQ、RabbitMQ等,Kafka支持Batch操作。
容错性:Kafka每个Partition数据会复制到几台服务器,当某个Broker失效时,Zookeeper将通知生产者和消费者从而使用其他的Broker。
架构解耦
流量控制
异步处理
缺点:
重复消息。Kafka保证每条消息至少送达一次,虽然几率很小,但一条消息可能被送达多次。
消息乱序。Kafka某一个固定的Partition内部的消息是保证有序的,如果一个Topic有多个Partition,partition之间的消息送达不保证有序。
复杂性。Kafka需要Zookeeper的支持,Topic一般需要人工创建,部署和维护比一般MQ成本更高。
消息丢失
消息堆积:提升消费者、水平扩容、采用临时暂存之后再慢慢消费(针对突发性)
传统的消息传递方法包括两种:
排队:在队列中,一组用户可以从服务器中读取消息,每条消息都发送给其中一个人。
发布-订阅:在这个模型中,消息被广播给所有的用户。
事务的保证,内部重试问题。交给Procedure幂等处理;多分区原子写入
Kafka 的分区多副本架构是 Kafka 可靠性保证的核心,把消息写入多个副本可以使 Kafka 在发生崩溃时仍能保证消息的持久性。
为了保证数据的可靠性,我们最少需要配置一下几个参数
producer 级别:acks=all(或者 request.required.acks=-1),同时发生模式为同步 producer.type=sync
topic 级别:设置 replication.factor>=3,并且 min.insync.replicas>=2;
broker 级别:关闭不完全的 Leader 选举,即 unclean.leader.election.enable
保留期限保留了Kafka群集中的所有已发布记录。它不会检查它们是否已被消耗。此外,可以通过使用保留期的配置设置来丢弃记录。而且,它可以释放一些空间。
-事务和外键区别。Innodb具备4个事务隔离级别。Myisam不支持事务,不过针对大量select操作。Myisam性能更好
-锁 innodb是行锁支持,myisam只支持表锁,索引innodb对并发支持比较好
-索引,innodb使用的聚簇索引、索引就是数据,顺序存储,因此能缓存索引,也能缓存数据。Myisam使用非聚簇索引、索引和文件分开,随机存储。只能缓存索引
-分表,能够解决单表数据量过大带来的查询效率下降的问题
-分库,面对高并发的读写访问,当数据库master服务器无法承载写操作压力时,不管如何扩展slave服务器,此时都没有意义。此时,则需要通过数据分库策略,提高数据库并发访问能力。
跨库Join的几种解决思路
字段冗余(只适合少量字段)、表复制和同步、链接表。
分布式事务
提供回滚接口或者失败重试幂等 或者 采用MQ非事务消息。
拓展:
分布式ID有哪些生成方式
分布式特性:全局唯一、数字类型趋势递增、长度短、信息安全、高可用低延时ID生成快
方式:
基于UUID【缺点:无序,不是全数字、无法保证递增。。。】
数据主键自增【缺点:强依赖DB、适合小规模】
数据库多实例主键自增【缺点:无法满足高并发】
Snowflake【强依赖机器时钟】
基于redis、
美团的Leaf(ID段、双Buffer、动态调整Step)
mysql的常见锁 - 简书
如何防止脏读、不可重复读、幻读
a. 设计良好的数据库结构,允许部分数据冗余,尽量避免join查询,提高效率。
b. 选择合适的表字段数据类型和存储引擎,适当的添加索引。
c. mysql库主从读写分离。
d. 找规律分表,减少单表中的数据量提高查询速度。
e.添加缓存机制,比如memcached,apc等。
f. 不经常改动的页面,生成静态页面。
g. 书写高效率的SQL。比如 SELECT * FROM TABEL 改为 SELECT field_1, field_2, field_3 FROM TABLE.
拓展:
如何定位一个线上问题?
CPU 高负载?OOM 排查等?
手写:
SELECT DISTINCT
FROM
ON
WHERE
GROUP BY
HAVING
ORDER BY
LIMIT
机读:
1)FROM
2)ON
3)
4)WHERE
5)GROUP BY
6)HAVING
7)SELECT DISTINCT
8)ORDER BY
9)LIMIT
from:需要从哪个数据表检索数据
where:过滤表中数据的条件
group by:如何将上面过滤出的数据分组
having:对上面已经分组的数据进行过滤的条件
select:查看结果集中的哪个列,或列的计算结果
order by :按照什么样的顺序来查看返回的数据
update T set c=c+1 where ID=2;
1、执行器先通过引擎使用树搜索找到ID=2这一行,如果该记录所在的数据页本身就在内存中,则直接返回执行器,否则先从磁盘读入内存,然后返回
2、执行器拿到数据后将c的值加一,然后通过引擎的写入接口将修改后的数据写入
3、引擎j将新数据更新到内存中,然后在redo log中记录此次修改,这时redo log中该记录的状态置为prepare,并告知执行器已经更新完成,随时可以提交事务
4、执行器生成此次操作的bin log,将bin log写入磁盘中
5、执行器调用引擎的提交事务接口,引擎将刚刚写入的redo log置为commit状态,更新结束
mysql的binlog日志主要用于数据库的主从复制与数据恢复。binlog中记录了数据的增删改查操作,主从复制过程中,主库向从库同步binlog日志,从库对binlog日志中的事件进行重放,从而实现主从同步。
mysql binlog日志有三种模式,分别为:
ROW: 记录每一行数据被修改的情况,但是日志量太大
STATEMENT: 记录每一条修改数据的SQL语句,减少了日志量,但是SQL语句使用函数或触发器时容易出现主从不一致
MIXED: 结合了ROW和STATEMENT的优点,根据具体执行数据操作的SQL语句选择使用ROW或者STATEMENT记录日志
行格式
1、首先我会用top命令和iostat命令,定位是什么进程在占用cpu和磁盘io;
2、如果是mysql的问题,我会登录到数据库,通过show full processlist命令,看现在数据库在执行什么sql语句,是否有语句长时间执行使数据库卡住;
3、执行show engine innodb status命令,查看数据库是否有锁资源争用;
4、查看mysql慢查询日志,看是否有慢sql;
5、找到引起数据库占用资源高的语句,进行优化,该建索引的建索引,索引不合适的删索引,或者根据情况kill掉耗费资源的sql语句等
MySQL高可用集群方案
MySQL死锁问题定位和处理
SHOW STATUS LIKE ‘innodb_row_lock%’; – 查看是否有锁等待
SELECT * FROM information_schema.INNODB_TRX WHERE trx_state=‘LOCK WAIT’\G; – 查看哪个事务在等待(下被阻塞了) show full processlist
SELECT * FROM sys.innodb_lock_waits\G; # 被锁的和锁定它的之间关系
SELECT * FROM performance_schema.threads WHERE processlist_id=2\G #找到锁源的 thread_id
SELECT * FROM performance_schema.events_statements_current
WHERE thread_id=27\G;找到锁源的SQL语句
– 执行语句的历史
SELECT * FROM performance_schema.events_statements_history
WHERE thread_id=27\G;
写入:redo log(prepare)
写入:binlog
写入:redo log(commit)
Redis常用命令
Redis的主从复制原理_全量
添加链接描述
添加链接描述
https://blog.csdn.net/Design407/article/details/103704559
https://blog.csdn.net/Design407/article/details/103716880
https://www.cnblogs.com/chenhuabin/p/13983303.html
https://www.elastic.co/guide/en/elasticsearch/reference/6.5/getting-started.html 文档
其实这个问题没啥,如果你确实干过 es,那你肯定了解你们生产 es 集群的实际情况,部署了几台机器?有多少个索引?每个索引有多大数据量?每个索引给了多少个分片?你肯定知道!
但是如果你确实没干过,也别虚,我给你说一个基本的版本,你到时候就简单说一下就好了。
es 生产集群我们部署了 5 台机器,每台机器是 6 核 64G 的,集群总内存是 320G。
我们 es 集群的日增量数据大概是 2000 万条,每天日增量数据大概是 500MB,每月增量数据大概是 6 亿,15G。目前系统已经运行了几个月,现在 es 集群里数据总量大概是 100G 左右。
目前线上有 5 个索引(这个结合你们自己业务来,看看自己有哪些数据可以放 es 的),每个索引的数据量大概是 20G,所以这个数据量之内,我们每个索引分配的是 8 个 shard,比默认的 5 个 shard 多了 3 个 shard。
大概就这么说一下就行了。
当搜索字段是text类型时:由于它会分词,在执行wildcard、regexp、prefix时和es会检查字段中的每个词条,而不是整个字段。
当搜索字段是keyword类型时:在执行wildcard、regexp、prefix时和es会检查字段中整个文本。
所以能keyword类型的进行keyword类型;禁用 wildcard;设置合理的路由机制;数据量大时候,可以先基于时间敲定索引再检索;
添加链接描述
1 集群层面的设置
2 集群内的节点维护
3 集群内的索引、映射(mapping)、分词器的维护
4 集群内的分片维护
elasticsearch的master将不会成为整个集群环境的流量入口
添加链接描述
映射:所有文档在写入索引前都将被分析,用户可以设置一些参数,决定如何将输入文本分割为词条,哪些词条应该被过滤掉,或哪些附加处理有必要被调用(比如移除HTML标签)。这就是映射扮演的角色:存储分析链所需的所有信息。
索引:是映射类型的容器。一个Elasticsearch索引是独立的大量的文档集合。 每个索引存储在磁盘上的同组文件中,索引存储了所有映射类型的字段,还有一些设置。索引只是一个用来指向一个或多个分片(shards)的“逻辑命名空间(logical namespace)”. 一个分片(shard)是一个最小级别“工作单元(worker unit)”,它只是保存了索引中所有数据的一 部分。
类型:是文档的逻辑容器,类似于表格是行的容器。在不同的类型中,最好放入不同结构的文档:Elasticsearch是面向文档的,这意味着索引和搜索数据的最小单位是文档
在Elasticsearch中文档有几个重要的属性。
它是自我包含的。一篇文档同时包含字段和它们的取值。
它可以是层次的。文档中还包含新的文档,字段还可以包含其他字段和取值。例如,“location”字段可以同时包含“city”和“street“两个字段。
它拥有灵活的结构。文档不依赖于预先定义的模式。并非所有的文档都需要拥有相同的字段,它们不受限于同一个模式。
分片:集群允许系统存储的数据总量超过单机容量。为了满足这个需求,Elasticsearch将数据散布到多个物理的Lucene索引上去。这些Lucene索引被称为分片,而散布这些分片的过程叫作分片处理(sharding)。Elasticsearch会自动完成分片处理,并且让用户看来这些分片更像是一个大的索引。
除了Elasticsearch本身自动进行分片处理外,用户为具体的应用进行参数调优也是至关重要的,因为分片的数量在创建索引的时就被配置好了,之后无法改变,除非创建一个新索引并重新索引全部数据。
倒排索引就是关键词到文档 ID 的映射,每个关键词都对应着一系列的文件,这些文件中都出现了关键词。
在搜索引擎中,每个文档都有一个对应的文档 ID,文档内容被表示为一系列关键词的集合。例如,文档 1 经过分词,提取了 20 个关键词,每个关键词都会记录它在文档中出现的次数和出现位置。
1、Elasticsearch 的选主是 ZenDiscovery 模块负责的,主要包含 Ping(节点之
间通过这个 RPC 来发现彼此)和 Unicast(单播模块包含一个主机列表以控制哪
些节点需要 ping 通)这两部分;
2、对所有可以成为 master 的节点(node.master: true)根据 nodeId 字典排
序,每次选举每个节点都把自己所知道节点排一次序,然后选出第一个(第 0 位)
节点,暂且认为它是 master 节点。
3、如果对某个节点的投票数达到一定的值(可以成为 master 节点数 n/2+1)并
且该节点自己也选举自己,那这个节点就是 master。否则重新选举一直到满足上
述条件。
4、补充:master 节点的职责主要包括集群、节点和索引的管理,不负责文档级
别的管理;data 节点可以关闭 http 功能*。
添加链接描述
解答:
这里的索引文档应该理解为文档写入 ES,创建索引的过程。
文档写入包含:单文档写入和批量 bulk 写入,这里只解释一下:单文档写入流程。
记住官方文档中的这个图。
第一步:客户写集群某节点写入数据,发送请求。(如果没有指定路由/协调节点,
请求的节点扮演路由节点的角色。)第二步:节点 1 接受到请求后,使用文档_id 来确定文档属于分片 0。请求会被转
到另外的节点,假定节点 3。因此分片 0 的主分片分配到节点 3 上。
第三步:节点 3 在主分片上执行写操作,如果成功,则将请求并行转发到节点 1
和节点 2 的副本分片上,等待结果返回。所有的副本分片都报告成功,节点 3 将
向协调节点(节点 1)报告成功,节点 1 向请求客户端报告写入成功。
如果面试官再问:第二步中的文档获取分片的过程?
回答:借助路由算法获取,路由算法就是根据路由和文档 id 计算目标的分片 id 的
过程。
1shard = hash(_routing) % (num_of_primary_shards)
1、搜索被执行成一个两阶段过程,我们称之为 Query Then Fetch;
2、在初始查询阶段时,查询会广播到索引中每一个分片拷贝(主分片或者副本分
片)。 每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的
优先队列。
PS:在搜索的时候是会查询 Filesystem Cache 的,但是有部分数据还在 Memory
Buffer,所以搜索是近实时的。
3、每个分片返回各自优先队列中 所有文档的 ID 和排序值 给协调节点,它合并
这些值到自己的优先队列中来产生一个全局排序后的结果列表。
4、接下来就是 取回阶段,协调节点辨别出哪些文档需要被取回并向相关的分片
提交多个 GET 请求。每个分片加载并 丰富 文档,如果有需要的话,接着返回
文档给协调节点。一旦所有的文档都被取回了,协调节点返回结果给客户端。
5、补充:Query Then Fetch 的搜索类型在文档相关性打分的时候参考的是本分
片的数据,这样在文档数量较少的时候可能不够准确,DFS Query Then Fetch 增
加了一个预查询的处理,询问 Term 和 Document frequency,这个评分更准确,
但是性能会变差。*
1、倒排词典的索引需要常驻内存,无法 GC,需要监控 data node 上 segmentmemory 增长趋势。
2、各类缓存,field cache, filter cache, indexing cache, bulk queue 等等,要设置合理的大小,并且要应该根据最坏的情况来看 heap 是否够用,也就是各类缓存全部占满的时候,还有 heap 空间可以分配给其他任务吗?避免采用 clear cache等“自欺欺人”的方式来释放内存。
3、避免返回大量结果集的搜索与聚合。确实需要大量拉取数据的场景,可以采用scan & scroll api 来实现。
4、cluster stats 驻留内存并无法水平扩展,超大规模集群可以考虑分拆成多个集群通过 tribe node 连接。
5、想知道 heap 够不够,必须结合实际应用场景,并对集群的 heap 使用情况做持续的监控。
添加链接描述
通过Nginx统计网站的PV、UV、IP
61.141.xxx.xxx - [2019-05-16T15:18:34+08:00] “GET /ttt.html HTTP/1.1” - 304 “User_Cookie:032284f362a63e3d375f8176aad4e0d7”
61.141.xxx.xxx - [2019-05-16T15:18:35+08:00] “GET /ttt.html HTTP/1.1” - 304 “User_Cookie:032284f362a63e3d375f8176aad4e0d7”
61.141.xxx.xxx - [2019-05-16T15:18:35+08:00] “GET /ttt.html HTTP/1.1” - 304 “User_Cookie:032284f362a63e3d375f8176aad4e0d7”
61.141.xxx.xxx - [2019-05-16T15:18:35+08:00] “GET /ttt.html HTTP/1.1” - 304 “User_Cookie:032284f362a63e3d375f8176aad4e0d7”
61.141.xxx.xxx - [2019-05-16T15:18:35+08:00] “GET /ttt.html HTTP/1.1” - 304 “User_Cookie:032284f362a63e3d375f8176aad4e0d7”
61.141.xxx.xxx - [2019-05-16T15:18:35+08:00] “GET /ttt.html HTTP/1.1” - 304 “User_Cookie:032284f362a63e3d375f8176aad4e0d7”
//统计IP
awk ‘{print $1}’ xxx/access.log(你的日志文件路径) | sort -r |uniq -c | wc -l
//统计PV
awk ‘{print $6}’ xxx/access.log(你的日志文件路径) | wc -l
//统计UV
awk ‘{print $10}’ xxx/access.log(你的日志文件路径) | sort -r |uniq -c |wc –l
轻量级,同样起web 服务,比apache占用更少的内存及资源
抗并发,nginx 处理请求是异步非阻塞的,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能
高度模块化的设计,编写模块相对简单
社区活跃,各种高性能模块出品迅速啊
apache 相对于nginx 的优点:
rewrite ,比nginx 的rewrite 强大
epoll 和 select
1、IO多路复用(IO Multiplexing) :是一种机制,程序注册一组socket文件描述符给操作系统,表示“我要监视这些fd是否有IO事件发生,有了就告诉程序处理”。
2、IO多路复用是要和NIO一起使用的。NIO和IO多路复用是相对独立的。NIO仅仅是指IO API总是能立刻返回,不会被Blocking;而IO多路复用仅仅是操作系统提供的一种便利的通知机制。操作系统并不会强制这俩必须得一起用,可以只用IO多路复用 + BIO,这时还是当前线程被卡住。IO多路复用和NIO是要配合一起使用才有实际意义
在 select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一 个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait() 时便得到通知。
动态页面
模块超多,基本想到的都可以找到
少bug ,nginx 的bug 相对较多
超稳定
Nginx : 一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理服务器。
cgi协议: 解决不同的语言解释器(如php、Python解释器)与webserver的通信,webserver每收到一个请求,都会去fork一个cgi进程,请求结束再kill掉这个进程。
fast-cgi : 实现单个进程可以一次处理多个请求
php-fpm 即 php-fastcgi process manager, php-fpm是 fast-cgi 的实现,并提供了进程管理的功能。
进程包含 master 进程和 worker 进程两种进程。 master 进程只有一个,负责监听端口,接收来自 Web Server 的请求,而 worker 进程则一般有多个(具体数量根据实际需要配置),每个进程内部都嵌入了一个 PHP 解释器,是 PHP 代码真正执行的地方。
Nginx通过反向代理功能将动态请求转向后端Php-fpm
添加链接描述
Go语言圣经
https://books.studygolang.com/gopl-zh/
go高级编程
https://chai2010.gitbooks.io/advanced-go-programming-book/content/
实战Go内存泄露
https://www.cnblogs.com/shijingxiang/articles/11473774.html
go语言特性
Go语言的这些地方都做的还不错:拥有自动垃圾回收、一个包系统、函数作为一等公民、词法作用域、系统调用接口、只读的UTF8字符串等。但是Go语言本身只有很少的特性,也不太可能添加太多的特性。例如,它没有隐式的数值转换,没有构造函数和析构函数,没有运算符重载,没有默认参数,也没有继承,没有泛型,没有异常,没有宏,没有函数修饰,更没有线程局部存储。
添加链接描述
awk ‘{print $1}’ 测试文件 | sort | uniq -c| sort –nr
在当前目录下,如何查找包含keyword文件.
grep -r “keyword” ./
查询一个日志文件中访问次数最多前10个IP?
第一步:按照IP进行将记录排序。
第二步:按照IP去重,并且显示重复次数
第三步:按照次数升序排列
第四步:显示前10行
cat log.txt|awk -F" " ‘{print &1}’ |sort|uniq -c|sort -nrt " “|awk -F” " ‘print &2’ |head -10
nginx 及 php-fpm和系统ulimit 配置优化&cpu信息查看_斗战圣Q-CSDN博客
1.查看CPU个数
cat /proc/cpuinfo |grep “physical id”|sort|uniq|wc -l
2.查看每个物理CPU含有的核心个数
cat /proc/cpuinfo |grep “cpu cores”|uniq|wc -l
3.查看每个CPU核心含有的线程数
cat /proc/cpuinfo |grep “processor”|wc –l
4、内存大小
cat /proc/meminfo | grep MemTotal
拓展:
Php配置:
https://www.jianshu.com/p/0923b96269ac
https://segmentfault.com/a/1190000014696851?utm_source=tag-newest
添加链接描述
分享70个经典的 Shell 脚本面试题与答案 - 简书
1.HTTP/1.0协议使用非持久连接,即在非持久连接下,一个tcp连接只传输一个Web对象
2.HTTP/1.1默认使用持久连接(然而,HTTP/1.1协议的客户机和服务器可以配置成使用非持久连接)
HTTPS在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息。TLS/SSL协议不仅仅是一套加密传输的协议,TLS/SSL中使用了非对称加密,对称加密以及HASH算法。握手过程的简单描述如下:
1.浏览器将自己支持的一套加密规则发送给网站。
2.网站从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
3.获得网站证书之后浏览器要做以下工作:
a) 验证证书的合法性(颁发证书的机构是否合法,证书中包含的网站地址是否与正在访问的地址一致等),如果证书受信任,则浏览器栏里面会显示一个小锁头,否则会给出证书不受信的提示。
b) 如果证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码,并用证书中提供的公钥加密。
c) 使用约定好的HASH计算握手消息,并使用生成的随机数对消息进行加密,最后将之前生成的所有信息发送给网站。
4.网站接收浏览器发来的数据之后要做以下的操作:
a) 使用自己的私钥将信息解密取出密码,使用密码解密浏览器发来的握手消息,并验证HASH是否与浏览器发来的一致。
b) 使用密码加密一段握手消息,发送给浏览器。
5.浏览器解密并计算握手消息的HASH,如果与服务端发来的HASH一致,此时握手过程结束,之后所有的通信数据将由之前浏览器生成的随机密码并利用对称加密算法进行加密。
这里浏览器与网站互相发送加密的握手消息并验证,目的是为了保证双方都获得了一致的密码,并且可以正常的加密解密数据。其中非对称加密算法用于在握手过程中加密生成的密码,对称加密算法用于对真正传输的数据进行加密,而HASH算法用于验证数据的完整性。由于浏览器生成的密码是整个数据加密的关键,因此在传输的时候使用了非对称加密算法对其加密。非对称加密算法会生成公钥和私钥,公钥只能用于加密数据,因此可以随意传输,而网站的私钥用于对数据进行解密,所以网站都会非常小心的保管自己的私钥,防止泄漏。
TLS握手过程中如果有任何错误,都会使加密连接断开,从而阻止了隐私信息的传输。正是由于HTTPS非常的安全,攻击者无法从中找到下手的地方,于是更多的是采用了假证书的手法来欺骗客户端,从而获取明文的信息。默认HTTP的端口号为80,HTTPS的端口号为443。
http请求与响应,TCP三次握手&四次分手_只是一只程序媛-CSDN博客_http三次握手
HTTP请求与响应步骤
1 建立连接
先解析DNS,把localhost变成ip(127.0.0.1),然后根据127.0.0.1和端口号8080(没有端口号则使用默认的端口)建立socket。也可以理解为通过“三次握手”建立TCP连接,确定通讯正常。
2 发送请求命令
socket建立好之后,客户端开始向web服务器发送请求命令(GET/POST等)。
3 发送请求头(和请求正文如果有)
客户端先发送与自身相关的信息,再发送空行表示请求头发送完毕,如果是post则继续发送请求正文。
4 回传状态行
应答第一步,发送协议版本和状态码(200、503、404等)
5 回传应答头
应答第二步,先发送自身相关信息、Content-Type(必须)及被请求的文档,在发送空行宝石应答头发送完毕。
6 回传应答正文
应答第三步,根据应答头的Content-Type指定的格式发送应答正文。
7 关闭连接
一次‘会话’完成,如果设置了Connection:keep-alive则TCP连接不关闭,否则关闭连接。
TCP的三次握手与四次挥手理解及面试题(很全面)
描述
同步与异步是对应的,它们是线程之间的关系,两个线程之间要么是同步的,要么是异步的。
阻塞与非阻塞是对同一个线程来说的,在某个时刻,线程要么处于阻塞,要么处于非阻塞。
添加链接描述
拆分、降级、冗余、灰度发布、切换》监控应该是贯穿于上述所有手段的
高可用系统常用解决手段浅述 - 又是火星人 - 博客园
区别:
1、数据存放位置不同:
cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、安全程度不同:
cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。
3、性能使用程度不同:
session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
4、数据存储大小不同:
单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie,而session则存储与服务端,浏览器对其没有限制。
5、会话机制不同
session会话机制:session会话机制是一种服务器端机制,它使用类似于哈希表(可能还有哈希表)的结构来保存信息。
cookies会话机制:cookie是服务器存储在本地计算机上的小块文本,并随每个请求发送到同一服务器。 Web服务器使用HTTP标头将cookie发送到客户端。在客户端终端,浏览器解析cookie并将其保存为本地文件,该文件自动将来自同一服务器的任何请求绑定到这些cookie。
1、PHP的生命周期、运行机制及并发模型
PHP学习笔记(一)——PHP的生命周期、运行机制及并发模型_xzf475的博客-CSDN博客
生命周期:
-SAPI启动、初始化模块
-请求处理初始化
-执行php代码
-关闭请求
-SAPI关闭,关闭模块(MSHUTDOWN)
Php运行机制:
-启动zend引擎,加载注册的扩展模块
-词法分析
-语法分析
编译opcode,执行
HashTable是Zend的核心数据结构
FastCGI的工作原理
1、Web Server启动时载入FastCGI进程管理器(IIS ISAPI或Apache Module)
2、FastCGI进程管理器自身初始化,启动多个CGI解释器进程(可见多个php-cgi)并等待来自Web Server的连接。
3、当客户端请求到达Web Server时,FastCGI进程管理器选择并连接到一个CGI解释器。Web server将CGI环境变量和标准输入发送到FastCGI子进程php-cgi。
4、FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web Server。当FastCGI子进程关闭连接时,请求便告处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web Server中)的下一个连接。 在CGI模式中,php-cgi在此便退出了。
在上述情况中,你可以想象CGI通常有多慢。每一个Web请求PHP都必须重新解析php.ini、重新载入全部扩展并重初始化全部数据结构。使用FastCGI,所有这些都只在进程启动时发生一次。一个额外的好处是,持续数据库连接(Persistent database connection)可以工作。
FastCGI的不足
因为是多进程,所以比CGI多线程消耗更多的服务器内存,PHP-CGI解释器每进程消耗7至25兆内存,将这个数字乘以50或100就是很大的内存数。
Nginx 0.8.46+PHP 5.2.14(FastCGI)服务器在3万并发连接下,开启的10个Nginx进程消耗150M内存(15M10=150M),开启的64个php-cgi进程消耗1280M内存(20M64=1280M),加上系统自身消耗的内存,总共消耗不到2GB内存。如果服务器内存较小,完全可以只开启25个php-cgi进程,这样php-cgi消耗的总内存数才500M。
2、PHP安全之道常见漏洞和攻防
-SQL注入,对sql语句进行预编译,杜绝sql注入。可以使用PDO就ok了
-XSS攻击,使用PHP的htmlentities()函数过滤再输出到浏览器
-CSRF,跨站点请求伪造。生成一个一次性的令牌并将其嵌入表单
-代码注入,防止代码注入 过滤用户输入 在php.ini中设置禁用allow_url_fopen和allow_url_include。这将禁用require/include/fopen的远程文件
3、微服务间的负载平衡、服务发现、流量管理、电路中断、遥测、故障注入等功能
Sidecar模式:下一代微服务架构的关键
微服务架构模式之 sidecar 模式(上):原理概述 | RPC 框架 | 微服务从入门到实践
SpringCloud初体验:五、Sidecar 将 PHP 这类非 Java 生态语言的服务接入 Spring Cloud - liugx - 博客园
4、php 高级研发工程师面试题总结
php 高级研发工程师面试题总结 - 王召波 - 博客园
5、时间复杂度按优劣排差不多集中在:
O(1), O(log n), O(n), O(n log n), O(n2), O(nk), O(2n)
二分法:O(log n)
快排:O(n log n)
6、介绍一下PHP的垃圾回收机制
垃圾回收机制可以让程序员不必过分关心程序内存分配,从而将更多的精力投入到业务逻辑。
PHP7 中复杂类型,像字符串、数组、对象等的数据结构中,头部都有一个 gc, 这个 gc 的作用就是用来对垃圾回收的支持。当变量赋值、传递时,会增加 value 的引用数, unset、return 等释放变量时再减掉引用数,减掉后如果发现 refcount 变为 0 则直接释放 value,这是变量的基本回收过程。
不过有一种问题是这个机制无法解决的,就是循环引用的问题。
什么是循环引用呢? 简单说就是变量的内部里存的 value 又引用了变量自身。 这种比较经常发生在数组和对象类型的变量上。
这里先讲一下引用,即 zend_reference 这个类型,这个是 PHP7 新增的变量类型,当对变量使用 “&” 操作时,会创建新的中间结构体 zend_reference,这个结构体会真正的指向对应的 value 结构。
PHP使用了引用计数(reference counting)GC机制,同时使用根缓冲区机制,当php发现有存在循环引用的zval时,就会把其投入到根缓冲区,当根缓冲区达到配置文件中的指定数量后,就会进行垃圾回收,以此解决循环引用导致的内存泄漏问题。
如果引用计数减少到零,所在变量容器将被清除(free),不属于垃圾;
如果一个zval的引用计数减少后还大于0,那么它会进入垃圾周期。其次,在一个垃圾周期中,通过检查引用计数是否减1,并且检查哪些变量容器的引用次数是零,来发现哪部分是垃圾。
每个对象都内含一个引用计数器refcount,每个reference连接到对象,计数器加1。当reference离开生存空间或被设为 NULL,计数器减1。当某个对象的引用计数器为零时,PHP知道你将不再需要使用这个对象,释放其所占的内存空间。
PHP的垃圾回收机制-PHP高级面试题+详解 - 知乎
7、php优缺点
1.语法简单的,上手很快,
2.跨平台,而且还都是免费的
3.PHP已经有很成熟的面向对象体系
4.有很多很好现有的框架,
网站开发语言中php占比还是遥遥领先的
不足的地方
对多线程支持不是很好,只能做一些简单的模拟线程 。
语法不够严谨,如果以前做C++,Java 的就会很有感觉了,比如变量还没有定义,就可能直接使用 。
也许有经验的PHP程序员最感到痛苦的地方是PHP的解释运行机制。这种运行机制使得每个PHP页面被解释执行后,所有的相关资源都会被回收。也就是说,PHP在语言级别上没有办法让某个对象常驻内存。在PHP中,所有的变量都是页面级的,无论是全局变量,还是类的静态成员,都会在页面执行完毕后被清空。以JSP为例,在JSP中,Java Bean的scope有四种有效值:Page、Application、Session、Request,分别对应页面、程序、会话、请求四种生存期。但在PHP中,只有Page一种生存期。
8、OOP的概念
静态方法与普通方法区别
静态的内存空间是固定的,相对来说更省资源。创实例的创一个实例就要开辟一个新内存,耗费资源
静态方法属于类所有,类实例化前即可使用;
非静态方法可以访问类中的任何成员,静态方法只能访问类中的静态成员;
因为静态方法在类实例化前就可以使用,而类中的非静态变量必须在实例化之后才能分配内存;
static内部只能出现static变量和其他static方法!而且static方法中还不能使用this等关键字,因为它是属于整个类;
静态方法效率上要比实例化高,静态方法的缺点是不自动进行销毁,而实例化的则可以做销毁;
静态方法和静态变量创建后始终使用同一块内存,而使用实例的方式会创建多个内存。
主要区别:静态方法在创建对象前就可以使用了,非静态方法必须通过new出来的对象调用。
静态方法可以通过 类名::方法名直接调用。普通方法需要创建一个实例,也就是new一个对象,然后通过 对象名->方法名的方式来调用
静态类只能包含静态成员,否则会抛出编译错误;然而非静态类既可以包含非静态成员也可以包含静态成员
静态类是不能实例化,之所以不能实例化,是因为静态类会导致C#编译器将该类同时标记为abstract和sealed,并且编译器不会在类型中
生成一个实例的构造函数,从而导致静态类不能实例化;非静态类可以,并且静态成员的访问只能通过类来进行访问,因为静态成员是属于类的。
什么是接口?接口有哪些好处,抽象类(abstract)和接口(interface)的区别,什么业务该怎么用。
接口是一bai种用来定义程序的协议,它描述du可属于任何类或zhi结构的一组相关行为
接口是这样定义的:dao 接口,里面包含方法,但是没有方法的具体实现。
然后在继承该接口的类中 去实现接口中的所有方法。包括 属性、方法、事件、索引器,但是不能包括字段;
接口中只能包含 属性、方法、事件、索引器;
接口可以实现C# 中的多继承。(c#不可以多继承,用接口可以实现) 接口可以继承接口,可以继承多个接口;
类可以继承接口,但是继承的类必须去实现接口中的方法代码。
接口不能直接被实例化
接口中的所有成员默认为public,因此接口中不能有private修饰符
接口的好处:
对类的一种约束。
如果一个项目的需求可能在不断变化的情况下,用接口可以很容易进行拓展,并不影响以前写的功能模块的代码,只要新添加类,继承这个接口就可以了。
如果每个类都要用到一些公用的属性字段或者方法,则通过继承接口可以方便的实现,不用再每个类中都写一次公用的属性或方法。
接口中不能包含【常量、字段(域)、构造函数、析构函数、静态成员】
抽象类(abstract)和接口(interface)的区别:
abstract 类 和接口类似,
抽象类中定义方法,只有方法名,但不包含主体,不包含实现,和接口一样,
可以把抽象方法当作没有具体实现的虚方法。
抽象类不能被实例化。这个接口一样,
抽象类中并非一定有抽象方法,但是 有抽象方法的类, 一定是抽象类。
派生类必须覆盖基类的抽象方法,(也就是子类去实现继承类中的方法)抽象类中可以包含:属性、普通方法、可以包含虚方法、抽象方法
IOC和DI,实际项目中的运用?
依赖注入:指的是 类/接口与类/接口的关系是依赖关系,不需要程序员直接new出对象的
这个对象不是在编译前创建的
例:Xxx x = new Xxx();
而是通过我要用的时候/运行的时候 这个IOC容器帮我创建
而我只需要拿来用就可以了
注入指的是:只需要配置xml的对象相关信息
IOC容器帮我注入/实例化对象
控制反转:
控制反转说的是也可以说是架构的那一层之间的关系
MVC设计模式说的是包与包之间的
控制反转说的是类与类、接口之间的这一层
我的要new出来的对象的类是通过IOC容器创建
这个对象类和服务类或者说工厂类之间的关系并不是直接的
而是间接的
它们都依赖这个IOC容器
打个比方
我和你用QQ聊天谈对象
我和你依赖与QQ
我和你并不是直接沟通面对面聊天而是通过QQ
通过QQ来 谈/创建对象
这就是控制反转
控制正转就是我和你(直接、面对面)谈恋爱
反转是相对于正向而言的,那么什么算是正向的呢?考虑一下常规情况下的应用程序,如果要在A里面使用C,你会怎么做呢?当然是直接去创建C的对象,也就是说,是在A类中主动去获取所需要的外部资源C,这种情况被称为正向的。那么什么是反向呢?就是A类不再主动去获取C,而是被动等待,等待IoC/DI的容器获取一个C的实例,然后反向的注入到A类中。
如何消除if else
设计完美的策略模式,消除If-else - 览岳 - 博客园
单例、工厂、注解、反射共同配合,配置读取单例化,实现了更加完善的策略模式,消除了if-else。
策略模式、状态模式、责任链模式都是在解决if-else的问题,但目的不太一样。策略模式主要是对方法的封装,把一系列方法封装到一系列的策略类中,客户端可以根据不同情况选择使用适宜的策略类,不同的策略类可以自由切换。
php如何实例化对象?
对像在PHP里面和整型、浮点型一样,也是一种数据类,都是存储不同类型数据用的,在运行的时候都要加载到内存中去用, 那么对象在内存里面是怎么体现的呢?
内存从罗辑上说大体上是分为4段, 栈空间段, 堆空间段,代码段, 初使化静态段,
①.栈空间段
栈的特点是空间小但被CPU访问的速度快,是用户存放程序中临时创建的变量。由于栈的后进先出特点,所以栈特别方便用来保存和恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个临时数据寄存、交换的内存区。用于存储占用空间长度不变并且占用空间小的数据类型的内存段,例如整型1、100、10000等在内存中占用空间是等长的,占用空间都是32位的4个字节。还有double、boolean等都可以存储在栈空间段中。
②.堆空间段
堆是用于存放进程运行中被动态分配的内存段,它大小并不固定,可动态扩张或缩减。用于存储数据长度可变或占用内存比较大的数据。例如,字符串、数组和对象就存储在这段内存中。
③.数据段
数据段用来存放可执行文件中初始化全局变量,换句话说就是存放程序静态分配的变量。
④.代码段
代码段是用来存放可执行文件的操作指令,也就是说它是可执行程序在内存中的镜像。代码段需要防止在运行时被非法修改,所以只准许读取操作,而不允许写入(修改)操作。例如程序中的函数就存储在这段内存中。
对象类型的数据就是一种占用空间比较大的数据类型,并且是占用的空间不定长的数据类型,所以对象创建完成以后被存放在对内存中,但对象的引用还是存放在栈里面的。程序在运行时,栈内存中的数据是可以直接存取的,而堆内存是不可以直接存取的内存,但可以通过对象的引用名称访问对象中的成员。
PHP面向对象(OOP)编程入门教程————如何实例化对象? - Tinywan - 博客园
9、单点登录的三种实现方式
单点登录的三种实现方式 - 简书
浅谈cookie跨域的解决方案——document.domain_筱葭的博客-CSDN博客_document.cookie跨域
单点登录原理与简单实现 - ywlaker - 博客园
单点登录(多台机只能一个用户登录,把另一用户踢下)思路
单点登录(多台机只能一个用户登录,把另一用户踢下)思路_低调地装B的代码农-CSDN博客
1,用户在电脑A登录,session信息存放在redis当中,并将session_id存到mysql数据库中。
2,同一用户在电脑B登录,验证完用户名和密码后,将该用户信息从数据库读出,取得用户在电脑A登录的session_id,然后在到redis中验证session是否过期。
3,如果过期,不用openfire推送提示信息。如果没有过期,php利用openfire推送消息后,在将redis中用户在电脑A中登录的session删除掉,删除后,在将用户在电脑B登录的个人信息放到session中,并将电脑B登录的session_id更新到数据库中,在这里一定要先发送推送,然后在清空session,不然用户在电脑A收不到xmpp发过来的消息。
注意:
openfire是java cms的一种,自身有数据库,您创建的用户表根openfire自带的用户表之间要建立某种联系(如:手机号,邮箱等),方便信息推送。
同一session_id肯定是在相同媒介上登录的,这个时候,也不用更新数据库和推送消息
10、laravel 架构解析
laravel 架构解析 - 简书
浅谈 Laravel 设计模式 | Laravel | Laravel China 社区
自己回答:
自己开发了一个较为轻便的MVC架构模式。请求到rpc.php入口文件,该文件下引入了框架启动文件boot.php。、在里面实现全局变量的定义,配置文件的载入,composer的自动加载,然后还涉及了多租户的初始化,载入appication程序,也就是new 一个 Application,创造一个容器,在这容器插上管子,这个service container 用来关联 service provider, 用来为应用提供各种服务,像db服务,缓存服务,事件、队列等服务。注册的时候采用了单例、门面、注册树、工厂的设计模式。
工厂模式,依赖转移(比如传入一个参数,工厂方法根据这个参数返回具体类的实例。实例化的过程交给了工厂方法)
抽象工厂模式在简单工厂模式基础上,多了一层抽象工厂接口,它的思想是,假如有多个工厂生产同样的产品,他们有同样的行为,那么把这些产品的创建行为抽象出来,每个工厂实现这个抽象接口。
IOC控制反转为了解决对象之间的耦合度过高的问题,用来实现对象之间的“解耦”,
11、什么叫微服务
微服务,又称微服务 架构,是一种架构风格,它将应用程序构建为以业务领域为模型的小型自治服务集合。
微服务相关面试问题整理 - 简书
百度安全验证
优点:
独立开发、独立部署、故障隔离、业务上解耦、持续交付允许频繁发布软件、敏捷
微服务(Microservices)和服务网格(Service Mesh)架构概念整理
微服务(Microservices)和服务网格(Service Mesh)架构概念整理 - 田园里的蟋蟀 - 博客园
SAAS和PAAS
SaaS,是Software-as-a-Service的缩写名称,意思为软件即服务
PaaS是(Platform as a Service)的缩写,是指平台即服务。 把服务器平台作为一种服务提供的商业模式,通过网络进行程序提供的服务称之为SaaS(Software as a Service),而云计算时代相应的服务器平台或者开发环境作为服务进行提供就成为了PaaS(Platform as a Service)。
所谓PaaS实际上是指将软件研发的平台作为一种服务,以SaaS的模式提交给用户。因此,PaaS也是SaaS模式的一种应用。但是,PaaS的出现可以加快SaaS的发展,尤其是加快SaaS应用的开发速度。在2007年国内外SaaS厂商先后推出自己的PAAS平台。
12、服务治理
首先我们知道服务是能够自闭环的,能够与划分清晰的业务边界,合乎逻辑。他们就像黑盒子。总之,我们并不需要了解业务服务的内部工作细节。对于外部世界,它只是一个能够使用消息交互的黑盒子。例如对于“订单服务”,“支付网关”的服务是一个黑盒子。
服务治理非常重要的一个环节,要在无感知的情况让消费者A调用服务提供者B,C,D,当然实际情况下,这是永远不可能的,根本不在一个内存空间中,我们需要自己模拟出来这种使用方式
https://segmentfault.com/a/1190000013481688
13、技术选型
数据存储架构技术选型
如何做数据存储架构技术选型?(关于存储的一些好文转载–4)_pansaky的博客-CSDN博客_数据存储架构
总结:
1)对ACID有强要求业务一般使用的数据存储采用关系型数据库,如mysql,postgresql、oracle、sql server等。
2)读多写少的场景,使用非关系型数据库Cassandra、hbase、MongoDB等。
3)缓解高并发读对数据库造成的读瓶颈,使用缓存:memcached、redis等。
4)复杂的数据检索,使用外置索引:elasticsearch、solr等。
一、基础知识
二、框架生命周期、框架设计、源码研究
三、设计模式
四、项目结构和优化
3、
五、数据结构
1、数组与链表:单 / 双向链表、跳舞链
2、栈与队列
3、树与图:最近公共祖先
4、哈希表
5、堆:大 / 小根堆、可并堆
6、字符串:字典树、后缀树
六、算法
1、排序算法:快速排序、归并排序、计数算法
2、搜索算法:回溯、递归、剪枝技巧
3、图论:最短路、最小生成树、网络流建模
4、动态规划:背包问题、最长子序列、计数问题
5、基础技巧:分治、倍增、二分、贪心
存储
一、如何优化
二、存储格式
三、性能读写
结合简历的日常习惯
swoole实际上是一个网络通信和异步io的引擎
常驻内存,避免重复加载带来的性能损耗,提升海量性能
协程异步,提高对 I/O 密集型场景并发处理能力(如:微信开发、支付、登录等)
方便地开发 Http、WebSocket、TCP、UDP 等应用,可以与硬件通信
PHP 高性能微服务架构成为现实
未来三年五年 技术领域的提升,能力提升,职业晋升
贵公司的晋升机制?贵公司对于员工的培训方面?公司的发展计划?
40亿个无符号整数存储在一个 40亿/32大小的整型数组中,如何构建这样的数组。答案就是这样:遍历40亿个无符号整数,然后用这个公式 a[n / 32][n % 32] => a[n >> 5] |= 1 << (n & 0x1F)
位图法压缩存储