链接:Spring Cloud微服务简介
微服务各个服务可以独立部署,各个服务之间是松耦合的,每个微服务只关注完成一个或少数任务。每个微服务都有自己独立处理通讯的机制,可以部署在一个或多个服务器上。
Spring Cloud的注册中心可以由Eureka、Consul、Zookeeper、ETCD等来实现,这里推荐使用Spring Cloud Eureka来实现注册中心,它基于Netfilix的Eureka做了二次封装,完成分布式服务中服务治理的功能,微服务系统中的服务注册与发现都通过这个注册中心来进行管理。通过SpringCloud Ribbon实现负载均衡。Spring Cloud Gateway作为路由网关,实现路由转发。
服务容错保护Spring Cloud Hystrix:
解决雪崩效应:
链接:熔断机制hystrix
资源隔离:
微服务优点:1、解耦;2、分布式;
微服务缺点:通常一个操作可能涉及多个微服务,如果为了完成一个操作而多次从服务端调用不同的微服务,http请求的耗时可能会成为瓶颈。
springcloud是基于RESTful(http+json)架构的。
Dubbo是基于RPC(remote procedure call)实现远程调用。
- SpringCloud Ribbon:所有的服务通过Eureka 进行注册到注册中心,客户端的调用就可以利用 Ribbon 技术来实现。Ribbon 是一个服务调用的组件,并且是一个客户端实现负载均衡处理的组件。服务器端实现负载均衡可以使用 Nginx、 HAProxy、LVS 等。
- 负载均衡集群:作用将大量的并发请求分担到多个处理节点,由于单个处理节点的故障不影响整个服务,负载均衡集群同时也实现了高可用性。一般提到的负载均衡(Load Balance),是指实现负载均衡集群。负载均衡实现了横向扩展(Scale Out),避免纵向的升级(Scale Up)换代。服务器端的负载均衡可以通过Nginx、HAProxy、LVS 等。
- MySQL高可用架构之MHA。
服务器收到第一次请求,开辟一块Session空间,生成一个SessionId,并通过响应头的Set-Cookie:“JSESSIONID=XXXXXXX”命令,向客户端发送设置cookie的响应;客户端收到响应,在本机浏览器设置JSESSIONID的cookie信息,该cookie的生命周期为会话结束。以后每次浏览器每次向服务端请求时都会带上这个cookie信息,服务端通过读取请求头中的cookie信息,获取sessionId。服务端通过sessionId判断是不是同一个会话。
GET请求在URL中传送的参数是有长度限制的,而POST没有。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET参数通过URL传递,POST放在Request body中。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
GET产生的URL地址可以被Bookmark,而POST不可以。
GET在浏览器回退时是无害的,而POST会再次提交请求。
get和post本质上没有区别,底层都是通过TCP传输数据。
get请求只产生一个数据包;post产生两个数据包(跟浏览器有关,我用chrome60试了试,用抓包工具抓包测试,发现只发了一个数据包);
get请求,浏览器会把header和data一起发过去,服务器响应200。
post请求浏览器先发送header,服务器响应100;后发送data,服务器响应200。
axios给后端发送post请求,如果设置带cookie,则是请求两次,第一次发送OPTIONS请求,第二次发送post请求。
链接:TCP与UDP的区别以及TCP的三次握手四次挥手
字段 | 含义 |
---|---|
URG | 紧急指针是否有效,为1,表示某一位需要被优先处理。 |
ACK | 确认号是否有效,一般置为1。 |
PSH | 提示接收端应用程序立即从TCP缓冲区把数据读走。 |
RST | 对方要求重新建立连接,复位。 |
SYN | 请求建立连接,设置为1。 |
FIN | 希望断开连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接。 |
- 事务支持
MyISAM:不支持事务,强调的是性能,是非事务安全的,当select查询比较多,用MyISAM比较合适。
InnoDB:支持事务,支持外键,是事务安全的,默认开启自动提交,宜合并事务,一同提交,减小数据库多次提交导致的开销,大大提高性能。具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。当update和insert比较多时,用InnoDB合适。
- 存储结构
MyISAM:每个数据表在磁盘上存储成三个文件,.FRM文件存储表定义,.MYD数据文件,.MYI索引文件。
InnoDB:所有的表都保存在同一个数据文件中,InnoDB表的大小只受限于操作系统的大小,一般为2GB。
- 存储空间
MyISAM:可被压缩,存储空间较小。
InnoDB:需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。
- 全文索引
MyISAM:支持(FULLTEXT类型的)全文索引
InnoDB:不支持(FULLTEXT类型的)全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好。
- 表的总行数
MyISAM:保存有表的总行数,如果select count() from table;会直接取出出该值。
InnoDB:没有保存表的总行数(只能遍历),如果使用select count() from table;就会遍历整个表,消耗相当大,但是在加了wehre条件后,myisam和innodb处理的方式都一样。
delete from dept where dname in (select t.dname from (select dname from dept group by dname having count(1) > 1)t)
Collection:List、Set、Queue
- List:
- ArrayList:底层是数组,非同步的。
- Vector:跟ArrayList类似,也是数组,是同步的,线程安全的,但是效率低,用的少。
- LinkedList:底层是链表。
- Set:
- HashSet:为快速查找而设计的set,存入HashSet的对象必须定义HashCode和equals。
- TreeSet:基于红黑树的实现,存入的数据会排序。
- LinkedHashSet:类似于HashSet,不过用链表维护元素的顺序(插入顺序)。
- Queue:扩展了Queue接口,增加了很多其它的方法。
- LinkedList:基于链表的实现,是一个普通队列,具有入队出队等操作。
- PriorityQueue:是一个比较标准的队列实现类,之所以说其标准,是因为其保存队列元素不是按其入队顺序,而是按照队列大小对其重新排序,因此出队的元素通常是最小元素。
- Deque:基于Queue的子类。
- ArrayDeque:基于数组的实现,具有入队出队等操作。
- LinkedList:基于链表的实现,具有入队出队等操作。
Map:
- HashMap:基于哈希表的实现,它取代了HashTable。
- TreeMap:基于红黑树的实现,存入的数据是要经过排序的。
- LinkedHashMap:类似于HashMap,区别是它采用链表维护元素顺序(插入顺序)。
- 栈:函数中的局部变量和函数调用过程中的临时变量,还有对象的引用都存在该区域。
- 堆:对象实例存在该区域。
- 方法区:包含常量池,存放了要加载的类的信息(名称、修饰符等)、静态常量、final类型的常量、Field信息、方法信息。方法区是被Java线程锁共享的,不像Java堆中其他部分一样会频繁被GC回收。
- 程序计数器:记录线程执行的字节码的行号。
链接:JVM回收机制
栈:又称方法栈,线程私有的,线程执行方法是都会创建一个栈阵,用来存储局部变量表,操作栈,动态链接,方法出口等信息.调用方法时执行入栈,方法返回式执行出栈。类的成员变量,没有实例化类的时候是存在栈中,实例化后跟随对象存在堆中,栈中存放的是对象的引用。
本地方法栈:与栈类似,也是用来保存执行方法的信息.执行Java方法是使用栈,执行Native方法时使用本地方法栈。
程序计数器:保存着当前线程执行的字节码位置,每个线程工作时都有独立的计数器,只为执行Java方法服务,执行Native方法时,程序计数器为空。
堆:JVM内存管理最大的一块,对被线程共享,目的是存放对象的实例,几乎所欲的对象实例都会放在这里,当堆没有可用空间时,会抛出OOM异常.根据对象的存活周期不同,JVM把对象进行分代管理,由垃圾回收器进行垃圾的回收管理。
方法区:又称非堆区,用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器优化后的代码等数据.1.7的永久代和1.8的元空间都是方法区的一种实现。
TCP:
UDP:应用层实现采用超时重传,实现udp的可靠传输。在规定的时间内,若没有收到sendto的信息,我们就认为数据包丢失,打破recvfrom的阻塞式等待,设置一个闹钟定时器alarm,当收到SIGALRM信号时,程序中断,转去处理中断响应函数,通知客户端进行重传。
HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议。
它是一个安全通信通道,基于HTTP开发,用于在客户计算机和服务器之间交换信息。它使用安全套接字层(SSL)进行信息交换,简单来说它是HTTP的安全版。
它是由Netscape开发并内置于其浏览器中,用于对数据进行压缩和解压操作,并返回网络上传送回的结果。HTTPS实际上应用了Netscape的安全套接字层(SSL)
作为HTTP应用层的子层。(HTTPS使用端口443,而不是象HTTP那样使用端口80来和TCP/IP进行通信。)
HTTPS和HTTP的区别:
https协议需要到ca申请证书,一般免费证书很少,需要交费。
http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
http的连接很简单,是无状态的。
HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。
由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC。
Scavenge GC:
一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden(新new的对象会放在该区域,经过GC回收幸存下来的会存入Survivor Space幸存者区)区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。
Full GC:
对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于Full GC的调节。有如下原因可能导致Full GC:
a) 年老代(Tenured)被写满;
b) 持久代(Perm)被写满;
c) System.gc()被显示调用;
d) 上一次GC之后Heap的各域分配策略动态变化;
Java 流在处理上分为字符流和字节流。字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组。
Java 内用 Unicode 编码存储字符,字符流处理类负责将外部的其他编码的字符流和 java 内 Unicode 字符流之间的转换。而类 InputStreamReader 和 OutputStreamWriter 处理字符流和字节流的转换。字符流(一次可以处理一个缓冲区)一次操作比字节流(一次一个字节)效率高。
- IOC:控制反转,具有依赖注入功能的容器,可以创建对象的容器;传统的程序设计中通常是由调用者创建被调用者的实例;在Spring中,创建被调用者的工作不再由调用者来完成,由IOC控制对象的创建,因此称为控制反转。IOC容器管理bean的生命周期,一旦创建这个对象,就不再帮你管理这个对象了,交给GC管理。
- DI:依赖注入,容器创建对象后,处理对象的依赖关系。组件之间的依赖关系由容器运行期间决定,由容器动态的将某个依赖注入到组件中;依赖注入的目的是为了提升组件重用的频率,为系统搭建一个灵活可扩展的平台。依赖注入是利用反射实现注入的,反射允许程序运行时动态的生成对象,执行对象的方法,改变对象的属性。**控制反转和依赖注入是同一个概念不同角度的描述。**依赖注入的方式:set注入方式,静态工厂注入方式,构造方法注入方式,基于注解的方式。
- AOP:面向切面编程,把那些分散在各处且与对象核心功能无关的代码(横切代码)的存在,使得模块复用难度增加。AOP则将封装好的对象剖开,找出其中对多个对象产生影响的公共行为,并将其封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),切面将那些与业务无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。比如日志记录,拦截器,事务管理。
- 连接点(join point):对应的是具体被拦截的方法,在SpringbootAOP例子中printUser就是一个连接点,AOP通过动态代理的技术把它织入对应流程中。
- 切点(point cut):我们的切面不单单是应用于单个方法,通过正则表达式去适配连接点,让切面应用于多个连接点。
- 通知(advice):前置通知、后置通知、环绕通知、事后返回通知和异常通知。
- 目标对象(target):即被代理对象,连接点所在的对象。
- 引入(introduction):引入新的类和方法,增强现有Bean的功能。就是引入切面,实现Bean的增强。
- 织入(weaving):通过动态代理技术,将约定织入流程的过程。
- 切面(aspect):是一个可以定义切点、各类通知和引入的内容,Spring AOP通过切面增强Bean的功能或者将对应的方法织入流程。
- Spring 是一个“引擎”。
- Spring MVC是Spring的一个模块,是一个web框架。通过Dispatcher Servlet, ModelAndView 和 View Resolver让开发web应用变得很容易。解决的问题领域是网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等。
- Springboot是基于Spring的快速开发整合包,Spring Boot有一套默认配置,我们可以把它看做比较通用的约定,而Spring Boot遵循的也是约定优于配置原则,在Spring Boot中,你会发现你引入的所有包都是*starter(懒人整合包)*形式。
- 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
- 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
- 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
- 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
- Spring事务:事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。 在企业级应用程序开发中,事务管理必不可少的技术,用来确保数据的完整性和一致性。
- 线程暂时放弃CPU操作,例如调用yield()方法。
- 当前线程进入阻塞状态,例如I/O阻塞。
- 当前线程执行结束,即运行完run()方法。
对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。
虽然两者都是用来暂停当前运行的线程,但是 sleep() 实际上只是短暂停顿,因为它不会释放锁,而 wait() 意味着条件等待,这就是为什么该方法要释放锁,因为只有这样,其他等待的线程才能在满足条件时获取到该锁。
链接:Java 中的异常和处理详解
如果要自定义异常类,则扩展Exception类即可,因此这样的自定义异常都属于检查异常(checked exception)。如果要自定义非检查异常,则扩展自RuntimeException。按照国际惯例,自定义的异常应该总是包含如下的构造函数:
try{
//try块中放可能发生异常的代码。
//如果执行完try且不发生异常,则接着去执行finally块和finally后面的代码(如果有的话)。
//如果发生异常,则尝试去匹配catch块。
}catch(SQLException SQLexception){
//每一个catch块用于捕获并处理一个特定的异常,或者这异常类型的子类。Java7中可以将多个异常声明在一个catch中。
//catch后面的括号定义了异常类型和异常参数。如果异常与之匹配且是最先匹配到的,则虚拟机将使用这个catch块来处理异常。
//在catch块中可以使用这个块的异常参数来获取异常的相关信息。异常参数是这个catch块中的局部变量,其它块不能访问。
//如果当前try块中发生的异常在后续的所有catch中都没捕获到,则先去执行finally,然后到这个函数的外部caller中去匹配异常处理器。
//如果try中没有发生异常,则所有的catch块将被忽略。
}catch(Exception exception){
//...
}finally{
//finally块通常是可选的。
//无论异常是否发生,异常是否匹配被处理,finally都会执行。
//一个try至少要有一个catch块,否则, 至少要有1个finally块。但是finally不是用来处理异常的,finally不会捕获异常。
//finally主要做一些清理工作,如流的关闭,数据库连接的关闭等。
//良好的编程习惯是:在try块中打开资源,在finally块中清理释放这些资源。
//首先一个不容易理解的事实:在 try块中即便有return,break,continue等改变执行流的语句,finally也会执行。
//不要在fianlly中使用return。finally中的return会抑制(消灭)前面try或者catch块中的异常。会覆盖前面return的值。
//不要在finally中抛出异常。finally中的异常会覆盖(消灭)前面try或者catch中的异常。
//减轻finally的任务,不要在finally中做一些其它的事情,finally块仅仅用来释放资源是最合适的。
//尽量将所有的return写在函数的最后面,而不是try...catch...finally...中。
}