面试知识点
2021-06-08 18:05:42 0 举报
AI智能生成
面试知识点
作者其他创作
大纲/内容
电商超卖
限制前端发来的请求量
限制前端发来的请求量
重新设计秒杀商品页面,不使用网站原来的商品详细页面,页面内容静态化,用户请求不需要经过应用服
秒杀token
没有token的过几秒显示秒杀完成
有token app控制发送请求的频率
CDN服务商临时租借新增的出口带宽
由于最终能够成功秒杀到商品的用户只有一个,因此需要在用户提交订单时,检查是否已经有订单提交。如果已经有订单提交成功,则需要更新 JavaScript文件,更新秒杀开始标志为否,购买按钮变灰
大量请求同时间段查询同一个商品时,可以做页面级别缓存,不管下回是谁来访问,只要是这个页面就直接返回
由网关限制程序过量请求
1 黑名单(ip、用户id等),可以直接放内存里
2 过多的重复请求(可以采用redis集群计数,对同一个ip、id发起的重复请求给予拒绝)限制用户维度访问频率
3.令牌桶,如guava的rateLimer就可以
4.通过账号行为的”数据挖掘“来提前清理掉它们
风控系统
极速下单
1.首选redis。你在订单请求到达后,迅速拼接好order、orderItem对象,将订单下到redis里
2.写入到消费队列MQ中一份, 慢慢生成数据库订单
防止提前下单
防超卖
那么这个分布式锁就会有严重的性能问题
对应这个key的请求就算全部卖光。譬如商品id是10,那么我们就用goodsId-10-1,goodsId-10-2,goodsId-10-3这样,建立count/500个key,当请求来时,按照hash将分布式锁加到不同的key上。这样也能大幅提高分布式锁的性能。
独立域名| 独立部署
将秒杀系统独立部署,甚至使用独立域名,使其与网站完全隔离
验证码防止机器人
主体思路
限流
肖峰
异步处理
内存缓存
核心思想:层层过滤
尽量将请求拦截在上游,降低下游的压力
充分利用缓存与消息队列,提高请求处理速度以及削峰填谷的作用
尽量将请求拦截在上游,降低下游的压力
充分利用缓存与消息队列,提高请求处理速度以及削峰填谷的作用
MQ
定义
virtual host
相当于数据库中一个库
virturl host 要绑定一个用户
队列
交换机
消息模型
子主题
集群
主备模式
主从复制模式
和redis差不多
镜像集群
sentinal模式
如何可靠性投递
confirm 模式
分支主题
微服务架构
设计
独立开发 – 所有微服务都可以根据各自的功能轻松开发
独立部署 – 基于其服务,可以在任何应用程序中单独部署它们
故障隔离 – 即使应用程序的一项服务不起作用,系统仍可继续运行
混合技术堆栈 – 可以使用不同的语言和技术来构建同一应用程序的不同服务
粒度缩放 – 单个组件可根据需要进行缩放,无需将所有组件缩放在一起
微服务的 特点
解耦 – 系统内的服务很大程度上是分离的。因此,整个应用程序可以轻松构建,更改和扩展
组件化 – 微服务被视为可以轻松更换和升级的独立组件
业务能力 – 微服务非常简单,专注于单一功能
自治 – 开发人员和团队可以彼此独立工作,从而提高速度
持续交付 – 通过软件创建,测试和批准的系统自动化,允许频繁发布软件
责任 – 微服务不关注应用程序作为项目。相反,他们将应用程序视为他们负责的产品
分散治理 – 重点是使用正确的工具来做正确的工作。这意味着没有标准化模式或任何技术模式。开发人员可以自由选择最有用的工具来解决他们的问题
敏捷 – 微服务支持敏捷开发。任何新功能都可以快速开发并再次丢弃
组件化 – 微服务被视为可以轻松更换和升级的独立组件
业务能力 – 微服务非常简单,专注于单一功能
自治 – 开发人员和团队可以彼此独立工作,从而提高速度
持续交付 – 通过软件创建,测试和批准的系统自动化,允许频繁发布软件
责任 – 微服务不关注应用程序作为项目。相反,他们将应用程序视为他们负责的产品
分散治理 – 重点是使用正确的工具来做正确的工作。这意味着没有标准化模式或任何技术模式。开发人员可以自由选择最有用的工具来解决他们的问题
敏捷 – 微服务支持敏捷开发。任何新功能都可以快速开发并再次丢弃
面临4个核心问题
服务很多,客户端应该如何访问?
API网关
这么多服务?服务之间如何通信?
HTTP/RPC
.这么多服务?如何治理?
服务注册与发现
服务器挂了怎么办
熔断和降级
缺点
开发人员要处理分布式系统的复杂性
多服务运维难度
系统部署依赖
服务间通信成本
数据一致性
系统集成测试
性能监控
架构
https://www.processon.com/view/5ecdc5dde401fd268dd40dee
具体说明
注册中心
nacos
链路追踪
Zipkin
网关统一鉴权服务
Spring Cloud Gateway
熔断降级
sentinel
架构
几个指标
资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
运行指标,例如 QPS、线程池、系统负载等;
控制的效果,例如直接限流、冷启动、排队等
运行指标,例如 QPS、线程池、系统负载等;
控制的效果,例如直接限流、冷启动、排队等
工作原理
对主流框架提供适配或者显示的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析。
根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel 提供开放的接口,方便您定义及改变规则。
Sentinel 提供实时的监控系统,方便您快速了解目前系统的状态。
根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel 提供开放的接口,方便您定义及改变规则。
Sentinel 提供实时的监控系统,方便您快速了解目前系统的状态。
降级 | 熔断 | 限流
利用了滑动时间窗的方法
分布式事务
seata
有一个事务的协调中心
AT模式
SAGA 模式
TCC模式
两阶段补偿模式
客户端
事务提交告诉协调器
每一个都公司协调器
协调器会生成反向sql
FenginClient
底层使用动态代理
URL 进行拼接
ribbon主键
服务发现和负载均衡
实战项目:
- https://www.processon.com/view/5b3c698ae4b0d97b024ee52d
2https://www.processon.com/view/5d6a3c56e4b08e7d73f08077
数据库一致性
ACID
原子性
需要通过日志:将所有对数据的更新操作都写入日志
一致性
Consistency
隔离性
Isolation
一种是悲观锁,
即当前事务将所有涉及操作的对象加锁
数据库级/表级/行级……
共享锁/排他锁/共享意向锁/排他意向锁/共享排他意向锁…
一种是乐观锁
子主题
持久性
Durability
MVCC
Multi-Version Concurrency Control(多版本并发控制)
MYsql 主从延迟怎么解决
原因:当主库的TPS并发较高时,产生的DDL数量超过slave一个sql线程所能承受的范围,那么延时就产生了,当然还有就是可能与slave的大型query语句产生了锁等待。首要原因:数据库在业务上读写压力太大,CPU计算负荷大,网卡负荷大,硬盘随机IO太高次要原因:读写binlog带来的性能影响,网络传输延迟。
解决方案
单个库读写分离,一主多从,主写从读,分散压力。这样从库压力比主库高,保护主库
服务的基础架构在业务和mysql之间加入memcache或者redis的cache层
不同业务的mysql物理上放在不同机器,分散压力
使用比主库更好的硬件设备作为slave总结,mysql压力小,延迟自然会变小
开源技术了解多少
高并发场景相关题目:同时给10万个人发工资,
按组织部门来分表,一般一个部门最多也就几上千百人吧,用分布式处理,不同的线程处理不同的部门
如何进行JVM调优?有哪些方法?
目标
目标:使用较小的内存占用来获得较高的吞吐量或者较低的延迟。
如果各项参数设置合理,系统没有超时日志出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化
方法
.监控GC的状态
使用各种JVM工具,查看当前日志,分析当前JVM参数设置,并且分析当前堆内存快照和gc日志,根据实际的各区域内存划分和GC执行时间,觉得是否进行优化。
生成堆的dump文件
分析dump文件
JVM调优工具
用 jps(JVM process Status)可以查看虚拟机启动的所有进程、执行主类的全名、JVM启动参数,比如当执行了JPSTest类中的main方法后(main方法持续执行),执行 jps -l可看到下面的JPSTest类的pid为31354,加上-v参数还可以看到JVM启动参数。
用jstat(JVM Statistics Monitoring Tool)监视虚拟机信息
用jmap(Memory Map for Java)查看堆内存信息
利用jconsole、jvisualvm分析内存信息(各个区如Eden、Survivor、Old等内存变化情况),如果查看的是远程服务器的JVM,程序启动需要加上如下参数
子主题
nio的底层实现。
线程池的一些原理,锁的机制升降级
反射机制
常用的类
Java.lang.Class;
Java.lang.reflect.Constructor;
Java.lang.reflect.Field;
Java.lang.reflect.Method;
Java.lang.reflect.Modifier;
创建类3中方法
Object-->getClass
任何数据类型(包括基本的数据类型)都有一个“静态”的class属性
通过class类的静态方法:forName(String className)(最常用)
创建实例:通过反射来生成对象主要有两种方法:
使用Class对象的newInstance()方法来创建Class对象对应类的实例。
先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建对象,这种方法可以用指定的构造器构造类的实例。
通过反射获取构造方法并使用:
反射方法的其他使用--通过反射越过泛型检查
动态代理
重要的接口
接口InvocationHandler(接口)
Proxy(类)
Proxy类就是用来创建一个代理对象的类,它提供了很多方法,但是我们最常用的是newProxyInstance方法。
三个参数:
loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载:handler.getClass().getClassLoader()
interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法 (people.getClass().getInterfaces())。
h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用 (handler 对象)。
loader:一个classloader对象,定义了由哪个classloader对象对生成的代理类进行加载:handler.getClass().getClassLoader()
interfaces:一个interface对象数组,表示我们将要给我们的代理对象提供一组什么样的接口,如果我们提供了这样一个接口对象数组,那么也就是声明了代理类实现了这些接口,代理类就可以调用接口中声明的所有方法 (people.getClass().getInterfaces())。
h:一个InvocationHandler对象,表示的是当动态代理对象调用方法的时候会关联到哪一个InvocationHandler对象上,并最终由其调用 (handler 对象)。
用法
每一个动态代理类的调用处理程序都必须实现InvocationHandler接口
流程
定义一个接口
实现接口类
定义一个handler 继承InvocationHandler
一个Object 对象是实现类
invoke
底层原理
在Proxy类中有一个工厂方法newProxyInstance这基本上就是Java Proxy动态代理的核心了。
newProxyInstance方法主要就是先生成代理的类的Class
获取构造函数把客户端传过来的InvacationHandler注入进去
生成代理类的方法: getProxyClass0(loader, interfaces);
加载成员方法类:检查指定的类加载器loader能否加载指定接口
分布式系统设计你会考虑哪些策略
1. 心跳检测
2. 高可用设计
3. 集群模式
4. 容错性
4. 负载均衡
多机均匀分发数据的问题
一致性hash
范围划分
数据化肥
微信红包怎么实现
订单层南北独立体系,数据不同步
分摊流量,降低系统风险。
cache系统优化
预订单:支付前订单落cache,同时利用cache的原子incr操作顺序生成红包订单号
拆红包入账异步化
Cache住所有查询,两层cache
高并发
请求按红包订单路由,逻辑块垂直sticky,事务隔离
多层级并发量控制
发红包控制
抢红包控制
拆时内存cache控制
柔性降级方案
下单cache故障降级DB
抢时cache故障降级DB
DB不存储用户头像、用户昵称等(上文提到的优化)
拆时资金入账多级柔性
mybatis实现的流程
SqlSessionFactory 通过SqlSessionFactoryBuild 传入配置
Configuration
properties
setting
typeAliases
处理一些复杂类型
ResultSet
hashmap
object
动态根据类型加载类
typehandlers(类型处理器)
处理类型Int | float | string
objectFactory
mapper(映射器)
SqlSession
DefaultSqlSession
两个最重要的参数: configuration 和Executor
BatchExecutor(重用语句并执行批量更新)
ReuseExecutor(重用预处理语句prepared statements)
SimpleExecutor(普通的执行器,默认)
SqlSession openSession()
session 传入configration, executor ,autoCommit
//根据传入的全限定名+方法名从映射的Map中取出MappedStatement对象
MappedStatement ms = configuration.getMappedStatement(statement);
//调用Executor中的方法处理
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
MappedStatement ms = configuration.getMappedStatement(statement);
//调用Executor中的方法处理
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
MappedStatement
mappedStatements 是一个HashMap,存储时key = 全限定类名 + 方法名,value = 对应的MappedStatement对象。
select 标签会在初始化配置文件时被解析封装成一个MappedStatement对象
//MapperProxy类,实现了InvocationHandler接口
mapperMethod.execute(sqlSession, args);
sqlSession 的select方法
MapperRegistry
调用过程
SqlSessionFactoryBean
parseConfiguration
mapperElement
调用过程
:MapperRegistry是Configuration中的一个属性,
当解析mappers标签时,它会判断解析到的是mapper配置文件时,会再将对应配置文件中的增删改查标签一 一封装成MappedStatement对象,存入mappedStatements中
//重点在这行,以接口类的class对象为key,value为其对应的工厂对象,构造方法中指定了接口对象
knownMappers.put(type, new MapperProxyFactory<>(type));
knownMappers.put(type, new MapperProxyFactory<>(type));
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
一些重要类的解析
MapperMethod
处理了RowBounds参数
处理了ResultHandler参数
处理了@Param注解
处理了@MapKey注解
处理了返回结果
处理了ResultHandler参数
处理了@Param注解
处理了@MapKey注解
处理了返回结果
MapperMethod类是整个代理机制的核心类,对SqlSession中的操作进行了封装使用。 该类里有两个内部类SqlCommand和MethodSignature。 SqlCommand用来封装CRUD操作,也就是我们在xml中配置的操作的节点。每个节点都会生成一个MappedStatement类。MethodSignature用来封装方法的参数以及返回类型,在execute的方法中我们发现在这里又回到了SqlSession中的接口调用,和我们自己实现UerDao接口的方式中直接用SqlSession对象调用DefaultSqlSession的实现类的方法是一样的,经过一大圈的代理又回到了原地,这就是整个动态代理的实现过程了。
MapperFactoryBean
解释的非常好的链接
https://www.cnblogs.com/hopeofthevillage/p/11384848.html
数据源配置
datasource
drid datasouce
HikariDataSource
先获取EntityManagerFactoryBuilder
生成EntitiyManagerFactoy
生成EntityManager
生成:JpaTransactionManager
收藏
收藏
0 条评论
下一页