浏览器打开一个网页的过程是什么
HTTPS 秘钥交换过程/四次握手
非对称加密的主要用途就是:密钥交换和数字签名。
数字签名的作用主要是:确保发送的报文没有被篡改。
非对称加密主要应用在秘钥协商阶段 !协商好秘钥之后的通信就用对称加密了 !
TCP 是怎么进行流量控制的
TCP中的流量控制和拥塞控制不同,它只解决端到端之间的问题。
往往是要通过降低发送端发送数据的速率,以便接收端能够处理,而不造成拥塞。
在TCP的首部,有一个标识窗口大小的16位字段,这个字段越大,说明滑动窗口(缓冲区越大),网络的吞吐量也就越大。接收端在收到ACK请求之后,也会把自己的窗口大小填进去,回应发送端,两端取一个最小的窗口尺寸进行数据发送。如果,接收端这边网络拥堵,状况不佳,那么这个窗口就可以动态的减小。如果网络特别通常,也可动态增加。
16位的窗口最大,2^16-1 = 65535字节 约64K。
当然在TCP首部控制位中还有一个CWR,它可以收缩窗口。
总结以下,两个字段,一个是 窗口大小,另一个是CWR(congestion window reduced 拥塞窗口减少)
窗口大小 = min(发送端窗口大小,接收端窗口大小)
高并发的解决方案
一、减少请求数量
高并发的主要原因之一就是请求量过于庞大,以致超出服务器的承受范围,因此想要解决问题就需要在这方面做出处理,一是需要避免重复的请求消耗不必要的资源,二是通过客户端自身的处理能力来响应请求,而不必到达服务端。
二、配置优化
如果请求量无法减少,或者有可能更多的情况下,那么增加资源、优化配置是必须要做的。可以增大带宽或对某些配置进行升级,或直接购买更高配置。如果请求量还是过大,可以提供多个服务器来实现任务分摊。
三、应用优化
在网页上也需要进行一番处理,例如动态页面静态化,减少不必要的图片和视频等需要占据和消耗大量空间的内容,可以考虑使用压缩传输的功能,来减少流量产生并提高速度。
------架构层面----
- 应用和静态资源分离
- 页面缓存
- 集群和分布式
- 反向代理
- CDN
缓存一致性问题
【单节点下两种方案对比】
先淘汰cache,再更新数据库:
采用同步更新缓存的策略,可能会导致数据长时间不一致,如果用延迟双删来优化,还需要考虑究竟需要延时多长时间的问题——读的效率较高,但数据的一致性需要靠其它手段来保证
采用异步更新缓存的策略,不会导致数据不一致,但在数据库更新完成之前,都需要到数据库层面去读取数据,读的效率不太好——保证了数据的一致性,适用于对一致性要求高的业务
先更新数据库,再淘汰cache:
无论是同步/异步更新缓存,都不会导致数据的最终不一致,在更新数据库期间,cache中的旧数据会被读取,可能会有一段时间的数据不一致,但读的效率很好——保证了数据读取的效率,如果业务对一致性要求不是很高,这种方案最合适
系统稳定性保障措施
预警:
所谓预警,前提当然是监控,所以我们此时就需要对系统各个层面做好实时监控,以便在灾难发生前后做好风险规避和应急处理
我们通常监控三个层面:业务监控(链路/qps/异常),系统硬件监控(CPU使用情况),系统软件监控(jvm/redis等使用情况)
业务监控:就是对用户的行为进行追踪记录,收集并统计各个指标,包括qps,pv,uv,请求次数/耗时,异常等等信息,比如我们可以通过SkyWalking进行链路追踪和请求异常告警,以实现快速定位问题。以及可通过kibana对业务数据进行监测与可视化分析等等。
系统硬件监控:就是对系统物理层面的监控,主要针对的是CPU的使用情况,比如,网络带宽,IO负载,内存使用率,CPU使用率,CPU负载等等,比如CPU负载(即当前正在运行与等待运行的任务平均数)业内常用的CPU负载临界值<=CPU核数*0.7 ,大于这个数,就说明当前可能存在大量的任务处于等待的状态,CPU已经在满负荷运转了,如果在五分钟/15分钟内都处于这种状态,此时我们就应该警惕并去寻找原因了。简单来说如果是8核的CPU,其负载要小于5.6才是理想的状态。CPU负载主要考虑是的“计算密集型”的程序,比较依赖于CPU的计算能力。而IO负载则是依赖于磁盘的读写速度,主要考虑的是“IO密集型”的程序。对于硬件监控与预警,若使用的是K8S可通过配置的方式来实现。
系统软件监控:也叫应用监控,因为其主要统计的是JVM中的GC,线程,内存以及缓冲池加载等指标。我们可以通过grafana开源框架去收集与分析系统应用以及redis集群信息。
总结:以上是从代码角度,由点到面去考虑和衡量一个系统的稳定性。如果从整个架构层面去考虑,其实就是三个方面的问题。
可感知——即通过各种数据指标的收集与分析进行异常告警,比如IO异常,CPU使用异常,业务异常等等
可预防——从代码优化,sql优化,jvm调优等多方面去预防可能发生的系统问题
可应急——有应急预案和流程去快速响应
- 严格的代码规范,书写健壮的代码,做好异常处理机制,降低内存溢出和内存泄漏的风险。
- 对代码的强弱依赖做好梳理,比如可有可无的依赖可以去掉,这样可以降低链路的请求层次,对于弱依赖可做熔断降级限流等处理(比如第三方接口调用),对于强依赖可做缓存处理(比如用户登陆信息)。
- Sql层面要注重性能,比如索引的使用,深度分页处理,慢sql优化等等。
- 对核心应用做好拆分,降低相互间的耦合度,做好负载均衡,以提高系统的可用性
- 要具备可预见性,对于可预见的故障点,做好开关,以达到快速切断问题来源的目的
业务功能模块系统拆分原则
- 功能维度
按照系统业务功能进行划分,例如对于电商系统,按功能维度我们可以拆分为商品中心,订单中心,用户中心,购物车,结算等功能模块。
2. 状态维度
对于一个功能模块可以按照不同的业务逻辑状态再进行划分,比如电商的优惠券模块按状态可以划分为创建模块,领券模块,使用模块。这个是从一个业务从开始到结束的不同状态进行的模块拆分。
3. 读写维度
按照读写不同的压力进行拆分,例如对于商品中心而言,读取商品详情的量会特别大,远远大于写入商品详情的量。这个时候就可以拆分为商品的写服务、读服务。读取服务可以考虑使用redis或者memcache缓存来提高性能,也可以做读写分离,而且可以依据访问需求量增加或者减少读写服务的部署数量。当写入的量太大时,可以考虑做分库分表,有些聚合读取的场景,比如商品详情页可以考虑使用数据异构,将分散的数据聚合到一个存储,从而提升系统的可靠性和性能。
4. 纵深维度
按照纵深的维度,最底层的是基础服务,最上层的是业务服务,代码结构一般按照MVC三层架构来进行划分。
秒杀系统的设计
设计思想
- 秒杀时大量用户会在同一时间,同时进行抢购;瞬时高并发
- 访问量远远大于实际库存量,只有少部分用户能够抢购成功
- 业务场景相对简单,就是下单减库存
业务隔离,系统隔离,数据隔离
- 页面静态化
- CDN加速
- 缓存
- mq异步处理
- 限流
- 分布式锁
系统设计思路
4S分析法
Scenario
Service
Storage
Scale
- 设计一个某某系统比如秒杀系统、微博系统、抢红包系统、短网址系统。
- 设计某某系统中的一个功能的点赞功能。
- 设计一个框架比如 RPC 框架、消息队列、缓存框架、分布式文件系统等等。
- 某某系统的技术选型比如缓存用
Redis
还是Memcached
、网关用Spring Cloud Gateway
还是Netflix Zuul2
。
JVM面试题
https://www.nowcoder.com/discuss/818602
Tomcat
- 处理Socket连接, 负责网络字节流与Resquest和Response对象的转换.
- 加载和管理Servlet,以及请求的具体处理.
Tomcat工作原理的具体步骤如下:1、用户点击网页时,客户端会将请求发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得。2、Connector连接器把该请求交给它所在的Service的Engine来处理,并等待Engine的回应的结果。 3、Engine获得请求的资源,如index.jsp,匹配所有的虚拟主机Host。 4、Engine匹配到名为localhost的Host(就算匹配不到也会把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求资源的信息,如/test/index.jsp,匹配它所拥有的所有的Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为“ ”的Context去处理)。 5、path=“/test”的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL PATTERN为*.jsp的Servlet,对应于JspServlet类。 6、构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost()。执行业务逻辑、数据存储等程序。 7、Context把执行完之后的HttpServletResponse对象返回给Host。 8、Host把HttpServletResponse对象返回给Engine。 9、Engine把HttpServletResponse对象返回Connector。 10、Connector把HttpServletResponse对象返回给客户Browser。
Tomcat原理
Tomcat IO模型
1.用户线程等待内核数据从网卡缓冲区拷贝到内核空间
2.内核将数据从内核空间拷贝到用户空间
Tomcat架构
Tomcat顶层架构小结:
(1)Tomcat中只有一个Server,一个Server可以有多个Service,一个Service可以有多个Connector和一个Container;
(2) Server掌管着整个Tomcat的生死大权;
(4)Service 是对外提供服务的;
(5)Connector用于接受请求并将请求封装成Request和Response来具体处理;
(6)Container用于封装和管理Servlet,以及具体处理request请求;
Connector就是使用ProtocolHandler来处理请求的,不同的ProtocolHandler代表不同的连接类型,比如:Http11Protocol使用的是普通Socket来连接的,Http11NioProtocol使用的是NioSocket来连接的。
Connector
其中ProtocolHandler由包含了三个部件:Endpoint、Processor、Adapter。
(1)Endpoint用来处理底层Socket的网络连接,Processor用于将Endpoint接收到的Socket封装成Request,Adapter用于将Request交给Container进行具体的处理。
(2)Endpoint由于是处理底层的Socket网络连接,因此Endpoint是用来实现TCP/IP协议的,而Processor用来实现HTTP协议的,Adapter将请求适配到Servlet容器进行具体的处理。
(3)Endpoint的抽象实现AbstractEndpoint里面定义的Acceptor和AsyncTimeout两个内部类和一个Handler接口。Acceptor用于监听请求,AsyncTimeout用于检查异步Request的超时,Handler用于处理接收到的Socket,在内部调用Processor进行处理。
Container
(1)Connector在接收到请求后会首先调用最顶层容器的Pipeline来处理,这里的最顶层容器的Pipeline就是EnginePipeline(Engine的管道);
(2)在Engine的管道中依次会执行EngineValue1、EngineValue2等等,最后会执行StandardEngineValue,在StandardEngineValue中会调用Host管道,然后再依次执行Host的HostValue1、HostValue2等,最后在执行StandardHostValue,然后再依次调用Context的管道和Wrapper的管道,最后执行到StandardWrapperValue。
(3)当执行到StandardWrapperValue的时候,会在StandardWrapperValue中创建FilterChain,并调用其doFilter方法来处理请求,这个FilterChain包含着我们配置的与请求相匹配的Filter和Servlet,其doFilter方法会依次调用所有的Filter的doFilter方法和Servlet的service方法,这样请求就得到了处理!
(4)当所有的Pipeline-Value都执行完之后,并且处理完了具体的请求,这个时候就可以将返回的结果交给Connector了,Connector在通过Socket的方式将结果返回给客户端。
Tomcat 调优
1、Tomcat的自身调优
采用动静分离节约 Tomcat 的性能
调整 Tomcat 的线程池
调整 Tomcat 的连接器
修改 Tomcat 的运行模式
禁用 AJP 连接器
2、JVM的调优
调优Jvm内存
Tomcat类加载机制
Tomcat类加载机制Tomcat类加载机制
类加载逻辑
tomcat的类加载机制是违反了双亲委托原则的,对于一些未加载的非基础类(Object,String等),各个web应用自己的类加载器(WebAppClassLoader)会优先加载,加载不到时再交给commonClassLoader走双亲委托。具体的加载逻辑位于WebAppClassLoaderBase.loadClass()方法中,代码篇幅长,这里以文字描述加载一个类过程:
先在本地缓存中查找是否已经加载过该类(对于一些已经加载了的类,会被缓存在resourceEntries这个数据结构中),如果已经加载即返回,否则 继续下一步。
让系统类加载器(AppClassLoader)尝试加载该类,主要是为了防止一些基础类会被web中的类覆盖,如果加载到即返回,返回继续。
前两步均没加载到目标类,那么web应用的类加载器将自行加载,如果加载到则返回,否则继续下一步。
最后还是加载不到的话,则委托父类加载器(Common ClassLoader)去加载。
第3第4两个步骤的顺序已经违反了双亲委托机制,除了tomcat之外,JDBC,JNDI,Thread.currentThread().setContextClassLoader();等很多地方都一样是违反了双亲委托。
Tomcat IO模型
Tomcat中的NIO模型是使用的JAVA的NIO类库,其内部的IO实现是同步的(也就是在用户态和内核态之间的数据交换上是同步机制),采用基于selector实现的异步事件驱动机制(这里的异步指的是selector这个实现模型是使用的异步机制)。而对于Java来说,非阻塞I/O的实现完全是基于操作系统内核的非阻塞I/O,它将操作系统的非阻塞I/O的差异屏蔽并提供统一的API,让我们不必关心操作系统。JDK会帮我们选择非阻塞I/O的实现方式。
这里需要提一下同步异步和阻塞非阻塞的概念:
同步和异步关注的是消息通信机制,同步异步指的是应用程序发起的调用请求和获得的返回值是否一起返回,如果一起返回就是同步,否则就是异步,异步可以通过回调函数等方式实现。
阻塞和非阻塞关注的是程序在等待调用结果时的状态,应用程序发起调用请求之后不能干别的事情直到请求处理完成了就是阻塞,否则就是非阻塞。
所以我个人认为,对于阻塞I/O谈同步异步是没有太大意义的,因为此时进程已经阻塞,想要去干别的事情必须得等请求处理完,而请求处理完必然会得到返回值。
上面我们提到得内核基于回调得事件检测方式二就是典型的异步非阻塞I/O模型。
网友评论