vps 网站异常,wordpress memcache,做网站帮外国人淘宝,濂溪区建设局网站先讲项目背景#xff0c;再讲技术栈模块划分#xff0c;
讲业务的时候可以先讲一般再特殊
为什么用这个#xff0c;好处是什么#xff0c;应用场景
Debug发现问题/日志发现问题.
QPS
TPS
项目单元测试#xff0c;代码的变更覆盖率达到80%#xff0c;项目的复用性高…先讲项目背景再讲技术栈模块划分
讲业务的时候可以先讲一般再特殊
为什么用这个好处是什么应用场景
Debug发现问题/日志发现问题.
QPS
TPS
项目单元测试代码的变更覆盖率达到80%项目的复用性高。
测试用例考虑清楚自动测试框架
Qps\TpS压测修复前后对比提升了多少倍
项目难点
FGC内存泄漏定位bug
CPU飙升
并发问题死锁代码并发集合原理源码
制造问题-发现问题-解决问题-看了源码
实习内容
http框架使用nestjs数据库使用mongodb3.x-4.xredis消息队列使用kafkanosql服务承载使用k8s容器化架构日志使用的kibana
nestjs的依赖循环REQUEST注解链路追踪id(cls-rtracer)等造成的内存泄露和性能问题
在做了优化之后就开始使用jmeter进行测试使用两种测试方案
提供最简单的http服务和一个数据库查询最高qps达到1000
提供普通业务的http服务内部有简单的数据库增删改查或请求其他服务qps普遍在200-300技术方向
灰度发布目的一个是降低线上系统问题影响的客户群体一个是降低线上系统问题的故障时
0. Spring Boot/DDD JDK21 MyBatis Redis Elasticsearch 8 LogStash Kibana K8S Docker Dubbo Eureka 、Nacos 熟悉微服务架构技术掌握开源MQ、RPC框架、注册中心、配置中心、分布式跟踪、微服务网关和分布式事务操作一致性要么全部成功、失败、网关高并发、监控与限流、路由转发gateway等中间件技术 服务熔断熔断器Sentinel A – B 其中B不可调用A为保证自身不受影响从而不调用B减轻A和B的压力直至服务B恢复。 服务降级减轻系统压力A (50) — B (30) — C (20) 50条数据A扛住B扛不住解决服务雪崩 服务限流高并发滑动窗口计数器、令牌桶 分布式 , 缓存 , 消息队列 集合、I/O、多线程/线程池的使用 后端Velocity、XML、JSON、ZooKeeperwatch机制和临时节点特性、Tomcat 前端JQuery/Bootstrap、Vue3 XML、HTML、JSP、javascript、JDBC、Servlet Oracle、mysql、NoSQL、MongoDB等数据库 Kafka、ZooKeeper Istio K8S Spring Security / Shiro 具备自动化测试脚本编写经验熟悉业界常用自动化测试工具如Jenkins、selenium、SoapUI、jMeter、cucumber等 JVM工作原理 Minio图床将文件上传到图床数据库保存url地址为了方便之后下载。 es底层原理、redis应用场景和缓存管理热点数据维护、缓存雪崩、缓存穿透 文件下载提高效率 - FastDFS 链路分析 Sleuth 、Zipkin 集群管理:Spring cloud cluster 事件驱动Spring cloud stream 方便通过发送消息数据来进行通信 || RocketMQ || KAFka 消息推送实时性建立长连接-vertx框架基于netty的异步网络轻量级框架、websocket 用户越来越多一台服务器不够用需要用到多台服务器 - 负载均衡 Nginx 、集群TPS、QPS 多台服务器下他们会有通信问题 - RPC远程调用 支付、认证会产生对方接口调用过慢网络等影响 - 异步 同时使用的人数过多避免服务器爆炸 - 消息队列 MQ/KafKa 消息处理 数据库的数据量过大 - 建立索引分库分表 常用信息访问过多占用资源 - Nosql 缓存 重复提交【接口幂等性】分布式事务分布式锁。 资源争抢问题和秒杀场景如何设计 Spring源码以及相关的场景 RPC AOP动态代理自定义注解-前置通知登录前校验、环绕通知操作日志、参数、执行结果生命周期声明的原理 IOC 、DI – 生命周期 – 循环依赖 AOP -- 动态代理 -- 声明式事务 Spring
1. Autowired 和 Resource区别 来源不同Autowired 来自 Spring 框架而 Resource 来自于Java 依赖查找的顺序不同Autowired 先根据类型再根据名称查询而 Resource 先根据名称再根据类型查询 支持的参数不同Autowired 只支持设置 1 个参数而 Resource 支持设置 7 个参数 依赖注入的用法支持不同Autowired 既支持构造方法注入又支持属性注入和 Setter 注入而 Resource 只支持属性注入和 Setter 注入 2. IOC
控制反转创建和获取对象的技术思想依赖注入DI是实现这种技术的一种方式分为两个注解Bean初始化注解和依赖注入注解Resource / Autowired 和 Service/Configuration/ Component/Bean
省去了new 创建对象这个过程由IOC容器接管
通过封装对象的创建和生命周期的管理使用依赖注入解耦对象之间的依赖关系利用反射和配置元数据来动态创建和管理对象同时提供作用域管理的功能这些机制共同构建了Spring IOC的原理。
3. AOP
AOP一种面向切面编程的思想主要就是在不修改现有业务逻辑代码的情况下动态的添加或修改程序的执行逻辑。什么是切面简单来说切面编写公共逻辑代码的那个类通过Aspect注解的类实现
应用1. 权限校验拦截器token校验首先把所有Controller标记为一个切入点在切入点之前创建一个切面切面中实现token校验逻辑。
动态切换数据源可以将DS注解表示的方法定义为“切入点”另外再定义一个切面类定义一个切面类 定一个切换数据源的方changDateSource拿到注解里面那个制定的数据源ID如果我们的数据库不支持制定的数据源就使用默认数据源否则如何支持就设置为手动设置的那个数据源定义一个切点使用Pointcut注解指明对添加了所有DS注解的接口在这里拓展我们切换数据源的功能。Before \ After
AOP原理
相对原有的代码进行添加或者修改最直接的办法就是直接在原有代码的基础上进行添加或者修改但是如果在面对很多方法都要新增逻辑这样就需要同样的方法复制到多个方法里面造成程序的冗余aspectJ是一个独立的AOP框架同时Spring提供了对AspectJ注解的驱动支持通常EnableAspectJAutoProxy注解启用对ASpectJ框架 的支持使Spring能够识别织入里Aspect声明的切面。
AOP主要通过动态代理实现在运行的时候创建代理对象这些代理对象可以拦截目标对象的方法调用并在方法执行前后执行切面中定义的逻辑主要分为两种JDK动态代理和CGLIB代理。
JDK动态代理Spring使用Proxy类和InvocationHandler接口在运行时动态创建代理类由代理类实现目标对象的所有接口并重写接口中方法然后将切面逻辑执行到方法的执行中。
举个例子银行存钱取钱首先有一个Account账户接口存钱的话账户余额就增加取钱的话就减少首先使用JDK自带的Proxy类来实例化一个Proxy对象然后拿到代理对象重写InnovocationHandler里面的invoke方法。在被代理对象方法的前面后者后面执行我们需要拓展的业务逻辑即可。
CGLIB代理是一个强大的高性能代码生成库它在运行时动态生成目标类的子类来创建代理对象并重写方法实现前面逻辑的织入它是一种基于类的代理方式不要求目标对象实现接口操作实例化一个代理工厂ProxyFactory()设置代理对象重写MethodInterceotor 的invoke方法然后在拓展原有的业务逻辑之前或者之后进行拓展。
总的来说呢Springboot主要解决两点“业务功能拓展” 和 ”性能消耗管理“AOP负责业务功能的拓展他保证在拓展业务功能时不用修改原有的业务逻辑动态添加或修改程序的执行逻辑IOC负责统一管理对象创建和依赖关系解决了内存消耗问题。 bean的生命周期 BeanFactory 和 FactoryBean 的区别
微服务
微服务就是一种软件架构风格专注于单一职责的小型项目为基础组合成复杂的大型项目。
分布式架构 - 解耦合降低服务集群影响范围
Eureka - 实现服务治理服务注册与发现可以对所有的微服务进行集中管理包括他们的运行状态、信息等。Ribbon - 提供客户端的软件负载均衡算法现在被SpringCloudLoadBalancer取代。 Hystrix - 断路器保护系统控制故障范围。Zuul - 具有api网关路由负载均衡等多种作用。Config - 配置管理可以实现配置文件集中管理。
分布式架构要考虑的问题
服务拆分粒度如何服务集群地址如何维护服务之间如何远程调用服务健康状态如何感知
RPC
Remote Procedure Call 远程过程调用IPC单机中运行的进程之间的相互通信应用场景A服务器想调用B服务器的接口
我们怎么告诉远程服务器我们调用的是方法1而不是方法2Call ID进行函数映射 在本地调用中函数题是直接通过函数指针来确定的我们通过调用函数 1编译器就会自动帮我们调用它对应的函数指针但是在远程调用中调用函数指针的方法是行不通的因为两个机器的两个进程的空间地址是完全不一样的 所以在RPC调用中所有的函数必须有一个自己的ID这个ID在所有进程中是唯一确定的客户端在做远程过程调用时必须附上这个ID 同时我们还需要在客户端和服务分别维护一个“函数与Call ID的对应表”客户端和服务端上的对应表不一定需要完全相同到哪相同的函数对应的Call ID必须相同 当客户端进行远程调用的时候就查一下这个表找出想要调用函数对应的Call ID然后把 Call ID传给服务端服务端也通过查表来确定客户端调用的函数然后执行对应的函数代码。 客户端怎么把参数传给远程的函数序列化和反序列化Serizlize 在本地调用中我们只需要把参数压到栈里然后让函数自己去栈里读就行。 但是在远程过程调用时客户端跟服务端是不同的机器的进程不能通过内存来传递参数 甚至有时候客户端和服务端使用的都不是同一种语言比如服务端用C客户端用Java或者Python 这时候就需要客户端把参数先转成一个字节流传给服务端后服务端再把这个字节流转成自己能读取的格式 这个过程叫序列化和反序列化。同理从服务端返回的值也需要序列化反序列化的过程。 网络传输问题将Call ID和序列化后的参数字节流传送给服务端在把序列话后的函数调用结果返回给客户端 远程过程调用往往用在网络上客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输因此就需要有一个网络传输层。网络传输层需要把“Call ID”和“序列化后的参数字节流”传给服务端然后再把“序列化后的调用结果”传回客户端只要能完成这两个功能的都可以作为传输层使用。因此RPC所使用的协议其实是不限的只要能完成传输就行。尽管大部分RPC框架都使用TCP协议但其实UDP也可以而gRPC干脆就用了HTTP2 综上所述要实现一个RPC框架其实只需要把以上三点实现了就基本完成了。Call ID映射可以直接使用函数字符串也可以使用整数ID映射表一般就是一个哈希表序列化反序列化可以自己写也可以使用Protobuf或者FlatBuffers之类的网络传输库可以自己写Socket或者用AsioZeroMQNetty之类。 RPC调用基本流程建立通信连接 - IP端口方法名称 - Client进行参数序列化 -反序列化 - 调用函数返回序列化函数结果 - 反序列化
1. 要解决通信的问题。主要是通过在客户端和服务器之间建立连接如TCP连接远程过程调用的所有数据都在这个连接中传输。此连接可以是按需连接调用结束后就断掉即短连接也可以是长连接多个远程过程共享同一个连接。
2. 要解决寻址问题。也就是说服务器上的应用怎么告诉底层的RPC框架如何连接到B服务器如主机或IP地址以及特定的端口、方法名称IP端口方法名这样才能完成调用。
3. client上的应用发起远程过程调用时方法的参数需要通过底层的网络协议如TCP传递到server上。由于网络协议是基于二进制的内存中的参数也要序列化成二进制的形式这就是序列化过程Serizlize通过连接寻址将序列化的二进制发送给server。
4. server收到请求后需要对参数进行反序列化恢复为内存中的表达形式然后找到对应的方法根据CALL ID与函数的对应表进行本地调用然后得到函数的返回值。
5. server需要将函数返回值发送给client上的应用。该返回值也需要经过序列化后发送client接到server发送的消息后再对该消息进行反序列化恢复为内存中的表达形式交给client上的应用。DubboRPC框架
服务消费者在调用服务提供者的时候发生了阻塞、等待的情形这个时候服务消费者会一直等待下去。 在某个峰值时刻大量的请求都在同时请求服务消费者会造成线程的大量堆积势必会造成雪崩。
解决办法
1设置超时和重试机制
dubbo 利用超时机制来解决这个问题设置一个超时时间在这个时间段内无法完成服务访问则自动断开连接。
使用timeout属性配置超时时间默认值1000单位毫秒。
设置了超时时间在这个时间段内无法完成服务访问则自动断开连接。
如果出现网络抖动则这一次请求就会失败。
Dubbo 提供重试机制来避免类似问题的发生。
通过 retries 属性来设置重试次数。默认为 2 次。2超时和重试代码
其实就是在service上加配置属性
Service(timeout3000) Reference(timeout3000)
Service(retries2) Reference(retries2)负载均衡策略4种
Random 按权重随机默认值。按权重设置随机概率。
RoundRobin 按权重轮询。
LeastActive最少活跃调用数相同活跃数的随机。
ConsistentHash一致性 Hash相同参数的请求总是发到同一提供者。// 代码
Service(loadbalancerandom)
Reference(loadbalancerandom)集群容错模式
Failover Cluster失败重试。默认值。当出现失败重试其它服务器 默认重试2次使用 retries 配置。一般用于读操作
Failfast Cluster 快速失败只发起一次调用失败立即报错。通常用于写操作。
Failsafe Cluster 失败安全出现异常时直接忽略。返回一个空结果。
Failback Cluster 失败自动恢复后台记录失败请求定时重发。通常用于消息通知操作。
Forking Cluster 并行调用多个服务器只要一个成功即返回。
Broadcast Cluster 广播调用所有提供者逐个调用任意一台报错则报错。// 代码
Service(clusterfailfast)
Reference(clusterfailfast)ELK
IK分词器源码
热启动
ELK连接Mysql热点词
Elasticsearch Logstash Kibana Filebeat
Elasticsearch Logstash Kafka Kibana
收集磁盘中的日志文件然后导入到Elasticsearch。
ELK中Logstash底层原理
解决问题
日志记录的格式复杂正则表达式非常磨人。服务日志有多种格式如何匹配。错误日志打印了堆栈信息包含很多行如何合并。日志记录行数过多100 多行被拆分到了其他的日志记录中。输出到 ES 的日志包含很多无意义字段。输出到 ES 的日志时间和本来的日志时间相差 8 小时。如何优化 Logstash 的性能Logstash 单点故障如何处理。
Logstash收集、解析、转换日志解决生产环境出现问题都需要远程到服务器查看日志文件定义统一的日志搜索入口从几十万条日志中搜索关键信息
正则解析
分片 sharding分布式存储和副本replicas备份注意不可与分片内容放在同一台服务器防止内容丢失
ES不可root用户启动必须普通用户启动
ES.port : 9200
kabana.port : 5601
post /es_db/_doc/_search
{query : {// term 整体匹配match 拆分匹配term / match : {name : admin}}
}ES工作原理 与Mysql 模糊查询的区别
ES是是一种分布式数据引擎处理大规模数据并采用倒排索引存储数据预处理的分词机制全文扫描
MySql更适合事务性擦欧总和关系数据的查询全表扫描 数据越大效率越低
关系型 database table row column
ES Index type document field
type : keyword 不会拆开: text 分词/拆开NoSQL
MongoDB
try {db.student.insertMany([{_id:1, articleid:100001, content:哈哈哈, createTime:new Date(2024-01-11)}])
}catch (e) {print(e);
}// 修改语句格式
db.collection.update(query, update, options)
// 默认修改一条数据
db.studnet.update({_id:1001,{$set{name:123}})
// 批量修改db.student.uptate({_id:1221,{$set{name:123}}, {multi:true})
// 对列值增长的修改
// 对其数值每次递增1
db.collection.update({_id:2},{$inc:NumberInt(1)}})
// 查找
db.collection.find()
// 删除
db.collection.remove(“条件”)
// 统计查询限制查询条数默认是20skip是跳过多少条数据
db.collection.find().limit(NUMBER).skip(NUMBER)
// 排序查询
db.collection.find().sort({userId:-1,likemnum:1}) // -1降序1升序
db.collection.find ({field:{$gt value}}) # 大于 fielde value
# $lt 小于 $gte 大于等于 $lte小于等于 $ne 不等于
# 包含
db.collection.find({userId{$in:[1101,1104]}})
db.collection.find({userId{$nin:[1101,1104]}}) # 不包含
# 条件连接查询
# $and:[{},{}]
# $or:[{},{}]
db.collection.find($and:[{num:{$gte:NumberInt(700)}}, {num:{$lt:NumberInt(800)}])# 索引
db.student.createIndex({userId:1})
# 执行计划查看查询性能
db.student.find({userId:1121}).explainMongnDB使用B树Mysql使用B树
应用场景
对数据库高并发读写的需求对海量数据的高效存储和访问的需求对数据库的高可拓展性和高可用性等应用不需要事物以及复杂join支持读写QPS在2000以上应用需要TB/PB级别的数据存储应用需要大量的地理位置查询、文本查询
缺点数据量大、读写很频繁、数据价值较低对事务性要求不高
具体应用场景
视频直播存储用户信息物联网场景使用MongoDB存储订单信息订单状态在运送过程中会不断更行以内嵌数组的形式来存储一次查询就能将订单错有的变更读取出来。用户发表朋友圈信息
数据插入
Redis
推荐极客时间的《redis核心技术与实战》
问题
使用redis实现分布式锁如果持有锁的主线程挂了那么其他锁一直等待锁未释放如何解决
设置锁的过期时间利用消费订阅机制 与 数据超时特性
缓存关键数据的数据副本
适用数据1.实时性、数据一致性要求不高、2.访问量大且更新频率不高的数据读多 写少
本地缓存 分布式缓存
缓存中存入的数据是JSON字符串
本地缓存缺点单体架构影响小、分布式存在数据不一致问题
将数据存入缓存 — 序列化 反序列化
1. 从缓存中查询数据 .get()
2. if(StringUtils.isEmpty(Obj)) 1. 从数据库中查询 2. 将查到的data save -- redis 将对象转化为JSON格式
3. return JSON字符串转化为Obj JOSN.parseObject()在使用缓存之前使用布隆过滤器检查一个元素是否在一个集合如果布隆过滤器不存在那么就直接返回不在查询数据库解决缓存穿透问题查询一个数据库中不存在的数据由于缓存不命中因为数据根本就不存在请求便会穿过缓存直接请求数据库。如果有大量此类请求数据库压力会突然增大严重时可能会拖垮数据库。 2.加锁或队列当热点key过期时不是所有请求都去数据库查询而是让某一个请求去数据库查询并更新缓存其他请求等待缓存更新后再访问缓存解决缓存击穿一个热点key在缓存中有效期过期的瞬间大量请求同时涌入数据库去查询这个数据因为缓存过期这些请求不能被缓存拦截直接请求到数据库导致数据库瞬间压力过大使用高可用的缓存架构即使缓存服务出现问题也能通过备份机制快速恢复解决缓存雪崩在某一个时间段内大量的缓存键集中过期失效导致所有的请求都落到数据库上造成数据库瞬间压力过大可能到达崩溃的状态 计算机网络:
计算机操作系统、计算机网络
推荐小林codinghttps://xiaolincoding.com/
Cookie、Session会话、Token
Cookie把Session放到Cookie中保存到浏览器
Session 诞生并保存在服务器
Token诞生在服务器保存在浏览器持有令牌可以访问服务器数据
Mysql
Neo4j 如何选择合适的分布式主键方案 数据库自增长序列或字段。 UUID。 Redis 生成 ID 雪花算法或者雪花加盐算法 利用 zookeeper 生成唯一 ID MongoDB 的 ObjectId 解决在Mysql表很大进行分页查询加载很慢limit加载很慢的问题
好的面试官这个问题在生产环境也是比较常见的。
limit mn ;其实去扫描mn条数据然后过滤掉前面的m条数据当m越大那么需要扫描的数据也就越多性能也会越来越慢。
针对这种情况有以下几种方案可以进行一定的优化。
1.如果id是趋势递增的那么每次查询都可以返回这次查询最大的ID然后下次查询加上大于上次最大id的条件这样会通过主键索引去扫描并且扫描数量会少很多很多。因为只需要扫描where
条件的数据
2.先limit出来主键ID然后用主表跟查询出来的ID进行inner join 内连接这样也能一定上提速因为减少了回表查询ID只需要走聚集索引就行。
3.当然如果mysql级别优化不了了。我们也可以对分页数据进行缓存比如Redis缓存数据进行变动的时候做好缓存依赖即可。
4.在业务允许的条件下限制页数因为越往后一般用户行为触及不到比如你去看淘宝不会去翻后面几百页的数据所以业务
层面也可以做一些让步比如不做后面几百页的数据。
Mysql双主 keepalived
两个数据库分别部署在两台服务器上相互同步数据但是只有一个提供给外部访问当一个宕机后另外一个可以继续提供服务在没有 keepalived 的帮助下只能手动切换。
检测和重启两台服务器上都部署 keepalived 软件定时检测 MySQL 服务是否正常如果一个数据库服务崩了keepalived 会用脚本尝试重启 mysql 服务。备份两个 keepalived 服务都提供了虚拟 IP 供客户端使用但是流量只会转到一台 MySQL 服务上。虚拟 IPkeepalived 配置好了后会有一个 虚拟 IP对于客户端来说不关心连接的是哪台 MySQL访问虚拟 IP 就可以了。流量切换如果客户端正在访问的 MySQL 服务崩了后keepalived 会用我们写的脚本自动重启 MySQL如果重启失败脚本主动停掉 keepalived客户端的流量就不会访问到这台服务器上的 MySQL 服务后续访问的流量都会切到另外一台 MySQL 服务。
主主集群、主从集群
熟悉mysql事务的ACID特性和事务隔离级别
MySQL*
推荐尚硅谷视频MySQL数据库高级mysql优化数据库优化
推荐极客时间的《MySQL实战45讲》
优化SQL
Mysql 是一个IO访问量非常频繁的关系型数据库
1.搭建Mysql主从集群单个Mysql服务容易当个节点故障一旦服务器宕机将会导致数据应用无响应主从或主主集群可提高服务的可用性。
2.读写分离设计在读多写少的场景中通过读写分离的方案避免读写冲突导致的性能影响。
3.引入分库分表机制分库可以降低单个服务器节点的IO压力分表可以降低单表的数据量提高SQL查询效率。
4.针对热点数据引入更高效的分布式数据库利用Redis、MongoDB。
SQL优化三部曲 慢SQL的定位和排查 通过慢查询日志和慢查询日志分析工具得到有问题的SQL列表 执行计划分析 针对慢SQL使用关键字explain来查看当前SQL的执行计划重点关注type key rows filterd等字段定位SQL慢的根本原因再有放矢地进行优化。 使用 show profile工具 此工具分析当前会话中SQL资源消耗情况的工具用于SQL调优的测量。分析IO开销、CPU开销、内存开销等
-- 注意
-- SQL查询一定要通过索引来进行数据扫描
-- 避免索引列上使用函数或者运算这样回导致索引失效
-- where字句中like % 尽量防止在右边
-- 查询中少用 * 分库和分表设计
按照业务归属拆分为不同的库中
按照字段数据的活跃性将字段拆分为主表和副表
按照字段拆分到多个库或多个表
分库分表的中间件sharding-jdbc当当、Mycat、TDDL淘宝、Oceanus 58同城、Atlas360
-- 注意
-- 事务问题需要用分布式事务
-- 跨节点 Join问题解决这个问题可以分两次查询实现
-- 夸节点的count、order、group by 以及聚合函数问题分别在各个节点上得到结果后在应用程序端进行合并。
-- 数据迁移、容量规划、扩容等问题
-- ID问题无法依赖数据库自身饿的主键生成机制解决用UUID
-- 跨分片的排序分页问题后台加大Pagesize处理应用场景
分库不分表数据库的读写访问量过高数据库连接不够用
分表不分库单表数据量非常大数据写入和查询的性能出现瓶颈并发量不高数据库连接够用
分裤分表数据库连接不够用、单表数据量大
Docker K8S
docker -help 查看所有帮助文档
docker run -help 查看帮助文档
docker run --name 容器名称 -p 80:80 -d naginx
docker load -i mysql.tar 加载一个tar文件导入为镜像
容器运行命令左侧是宿主端口 : 右侧是容器端口
-d 后台运行
docker start 容器名称
docker stop 容器名称
docker rm -f 容器名称
强制删除容器
docker ps -a
查看所有 容器docker exec -it mn bash
进入容器执行命令
docker exec - 进入容器内部执行一个命令
-it - 给当前进入的容器创建一个标准的输入、输出终端
mn -进入容器的名称
bash -进入容器后执行的命令docker run --name mr -p 6379:6379 -d redis redis-server --appendonly yes
# 运行redis数据卷(volume) 虚拟目录
docker volume -help
docker volume [COMMAND]
create -创建一个volume
inspect -显示一个或者多个volume的信息
ls -列出所有的volume
prune -删除未使用的volume
rm -删除一个或多个指定的volume数据挂载
docker run \ 创建并运行容器
--name mn \ 给容器起个名字
--v html:/root/html\ 把html数据卷挂载到容器内的/root/html目录下
-p 8080:80 把宿主机的8080端口映射到容器内的80端口
nginx \ 镜像名称docker run --name mn -p 80:80 -v html:/usr/share/nginx/html -d nginx
docker inspect html 查看数据卷挂载位置信息
cd /var/lib/docker/volumes/html/_data自定义镜像结构
# 指定基础镜像
FROM java:8-alpine
COPY ./docker-demo.jar /tmp/app.jar
# 暴露接口
EXPOSE 8090
# 入口java项目启动命令
ENTRYPOINT java -jar /tmp/app.jardocker build -t javaweb:2.0 空格.dockerCompose
基于Compose文件快速部署分布式应用无需一个个微服务去构建镜像和部署
touch docker -compose.yml
# 创建一个文件私有镜像仓库 重新tag本地镜像名称前缀为私有仓库的地址192.168.150.101:8080/ docker tag nginx:lastest 192.168.150.101:8080/nginx:1.0推送镜像 docker push 192.168.150.101:8080/nginx:1.0拉取镜像 docker pull 192.168.150.101:8080/nginx:1.0Docker将环境和程序一起打包
Docker.file:操作系统到运行程序的一个完成的命令清单文件要做的哪些事情
镜像仓库
Docker容器 和 虚拟机的区别
传统虚拟机自带一个完整的操作系统Docker容器自身不带完整的操作系统容器内部只包含操作系统的核心依赖库、配置文件等利用NameSpace让容器看起来像一个独立操作系统一样再利用Cgroup限制容器使用的计算资源总的来说就是容器本质上是一个自带独立运行环境的特殊进程底层用的还是宿主机的操作系统内核。docker compose
应用场景顺序化部署。数据库 -- 身份验证 -- WEB服务
yaml文件写清楚部署顺序以及容器占用CPU和内存等信息通过docker-compose up 解析yaml文件进行整套程序的顺序化部署。docker swarm
解决问题多台服务器集群部署问题服务器A停运应用迁移应用扩缩容。K8S(Kubernetes)
以API变成的方式管理安排各个容器的引擎。
解决问题简化服务的部署运维流程。
将服务器内部分为控制平面 Node运行各个应用服务控制平面控制各个Node
将程序和系统环打包为Container Image
程序 日志收集器、监控采集器 Container共同组成一个PodPod运行在Node上
k8s可以将pod从某个Node调度到另一个Node上还能进行Pod的重启和动态扩缩容
外部用户通过Ingress控制器入口访问Prod cluster 、 Test cluster 集群
部署流程
1. 编写yaml文件写清楚部署顺序以及容器占用CPU和内存等信息
2. Kubectl 执行 kubetcl apply -f xx.ymal
3. Kubectl将API发送给控制平面
4. Schedule(调度器)查看服务资源比如CPU和内存是否充部署应用
5. Controller Mgr 控制Node - kubelet接受命令Container runtime对镜拉取完成pod创建持续集成CI 代码合并、构建、部署、测试频繁的将代码上传到主干 持续交付CD部署到测试环境、预生产环境 持续部署CD部署到生产环境 私有仓库Nexus3 Maven 部署流程 代码push到gitlab库Jenkins构建git pull 使用maven打包打包成声的代码生成一个新版本镜像push到本地docker仓库harbor发布测试机器pull新版本镜像并删除原来的容器重新运行新版本镜像。执行docker.file文件 消息队列
SpringAMQP
spring:rabbitmq:host: # 主机名virtual-host: # 虚拟主机名username: # 用户名password: # 密码listener:simple:prefetch: 1 # 每次只能获取一条消息处理完才能获取下一个消息交换机作用
接收publisher发送的消息将消息按照规则路由到与之绑定的队列不能缓存消息路由失败消息丢失FanoutExchange会将消息路由到每一个绑定的队列群发
声明队列、交换机、绑定关系Bean
Queue、FanoutExchange、Binding
Direct交换机和Fanout交换机的差异发给特定对象
Fanout交换机将消息路由给每一个与之绑定的队列Direct交换机根据RoutingKey判断路由给哪个队列如果多个队列具有相同的RoutingKey则与Fanout功能相似
发布订阅 - TopicExchange
RabitListener(bindings QueueBinding (value Queue(name topic.queue2),exchange Exchange(name itcast.topic, type ExchangeTypes.TOPIC),key #.newskey china.#
))Direct 交换机 和 Topic 交换机的差异
Topic交换机支持通配符routingKey多个单词以.分割#代表0个或者多个* 代表恰好一个
消息转换器
SpringbootAMQP中消息的序列化和反序列化是怎么实现的
利用MessageConverter实现的默认是JDK的序列化缺点内容较长存储不好
改进采用JSON形式采用自定义方法覆盖JDK的方法同时接收方和发送方使用相同MessageConverter
Bean
public MessageConverter messageConverter( ) {return new Jackson2JsonMessageConverter();
}RabbitMQRocketMQKafka数据量万级10w10w基于erlang语言开发并发能力强延迟低微秒分布式架构基于Java开发基于大数据开发结合Spark flink hadoop消息基本不丢失经过参数优化配置可以做到0丢失经过参数优化配置可以做到0丢失应用场景即时通讯系统实时数据分析、电商秒杀、分布式事务消息实时计算、日志收集三者topicmmap零拷贝技术sendFile零拷贝技术比RocketMQ优秀
性能提升
TPS系统每秒处理交易数
QPS系统每秒处理查询次数
指标CPU占用率、内存占用率
JUC推荐寒食君up主评论有总结的PDF、有时间可以读读《Java并发编程之美》
jemter发送请求测试接口在usr/local
visualvm对Java进程监视
开源网站、性能压力测试
内存泄漏fgc
并发问题
没问题虚拟制造问题
源码
同步和异步
全局锁分布式锁、互斥使用共享资源
问题
OOM
基础配置参数从XXX 调到 XXX 为什么这么调如何进行JVM参数调优
1. 图形界面压力测试服务器- 集群化环境对某一台机器进行熔断大家的环境都一样 - 定位分析
2. arthas工具 查看业务线程(mian)死循环 系统线程(system)垃圾回收机制是否忙不过来heapdump jvisualvm - 分析文件 - 定位对象不可在生产环境导出文件
jinfo pid
jstack
jstack
jmap并发编程
程序出现死锁是因为在多线程环境里面两个或两个以上的线程同时满足
互斥条件、请求和保持条件、不可抢占条件、循环等待条件。 互斥条件共享资源x和y只能被一个线程占用
请求和保持条件线程t1已经获取共享资源x在等待共享资源y的时候不释放共享资源x
不可抢占条件其他线程不能强行抢占线程t1占有的资源
循环等待条件线程t1等到线程t2占有的资源线程t2等待线程t1占有的资源形成循环等待 在这四个条件里面互斥条件是锁本身的特性无法被破坏其他三个条件都可以被破坏。
对于请求和保持条件我们可以在第一次执行的时候一次性申请所有的共享资源
对于不可抢占条件占用部分资源的线程在进一步申请其他资源的时候如果申请不到就主动释放
它占有的资源。
对于循环等待条件可以按照顺序来申请资源相当于给资源编号按照编号顺序申请就可以避免循
环等待
出现死锁以后可以通过jstack命令去导出线程的dump日志
然后从dump日志里面定位到具体死锁的程序代码。
通过修改程序代码去破坏这四个条件里面的任意一个就可以解决死锁问题。
*当然因为互斥条件因为是锁本身的特性所以不能被破坏。
游戏开发
unity使用左手坐标系
ECS架构Entity-Component-System实体-组件-系统
entity - id多个组件组成一个entity组件可选择性使用 - compont1HP血量- compont2vel可移动- compont3组件只存状态而不具有行为实体中挂载组件无method只有成员变量System遍历所有无data只有method完成data的逻辑处理
核心逻辑与数据分离
规则组件没有函数系统没有数据
继承为对象强行建立父子关系耦合高。解决问题
人工智能
数据分析数据可视化基础,mayavi-三唯数据可视化nltk自然语言处理库,jiebaPython-docx基于python写一wordscikit-learn-机器学习方法工具集tensorflow-机器学习框架pytorch工业机器学习框架pytorch-高校、研究机构的机器学习框架
scrapypyspiderweb网页爬取系统djangoweb框架pyramid-web中型框架flask-小型框架aip-百度ai开放数据接口myqr-二维码功能pygame-游戏开发panda3d-游戏渲染
计算机视觉、R语言、scalaspark框架linuxscala然后spark
TensorFlow工业届机器学习pytouch学术界机器学习
支持向量机就是把维度升高用低维度看高维度的东西例如区分红绿豆
面试
1.你做的项目中有哪些难点以及你是如何克服的。
京东一面
1. 自我介绍
2. java集合有哪些实现list/map/set区别ArrayList和LinkedList区别扩容方式查找速度。
ArrayList自动扩容机制ArrayList底层实现是数组在无参构造条件下数组默认长度为0add添加一个元素之后长度为10添加内容超过数组长度之后就会发生数组自动扩容每次扩容的大小为原来数组大小的1.5倍创建新数组然后把旧数组的元素copeOf到新数组之中然后把新添加的元素添加到新数组中的位置旧数组不引用就被垃圾回收机制回收3. 静态方法和实例方法的区别。
4. public private protect的区别private可修饰静态方法吗
5. springMVC知道吗MVC的原理分别指什么
6. spring的装配原理没讲出来
7. Mybatis使用方式
8. mybatis返回一个list如何封装成一个object对象没讲出来
9. java反射机制讲得不好
10. Mysql的B树优势
11. MySQL如何优化explain
12. 外键为什么不用外键。如何保证数据库表之间的关联关系。
13. 数据库的三范式
14. 分库分表
15. 查询数据量大如何导出
16. redis的LRU和LFU持久化AOF和RDB
17. 分布式锁
18. 穿透击穿雪崩以及解决方法
19. 对象存储大对象存储怎么优化
20. 权限系统那五个表新增接口改哪些表
21. 限流令牌桶水滴桶了解其他限流框架吗
22. 排序方法对象对某个属性进行排序。第二个人23. 项目介绍任务分配项目流程时间...
24. 消息队列用过吗
25. python会用吗
26. 对大模型方面了解吗
27. 从哪些指标评价一个平台的稳定性
28. 时序数据库了解吗
29. 未来规划
30. 上班城市有偏向吗31.反问。
代码
用二叉树排序方法对一个数组进行排序。卧槽当时没想出来就没做。想叉了其实就是递归构建树腾讯金融科技
1.自我介绍
2.coding
\- 最大和连续子数组
\- 一个文件里一行有一个8位的电话号很多文件数据大到内存无法容纳如何统计不同电话号出现的次数
先说思路文件分块读单纯统计哪些出现→用set因为电话号范围是00000000-99999999共10^9个数int型可以容纳根据os不同int所占大小不同这里取32位即4B一共可能有10^8大小因此set最大4*10^8B≈400MB。如果考虑统计次数用map为了简化我们的统计key是号码仍然用int多的就是val的大小事先如果已知出现次数的范围用int或者long计数int则在set基础上多一倍800MBlomg这里假设是int两倍则1.2GB。
面试官提到像一些单片机和一些简单的设备内存还是太多了用一些基础的结构想到了bitmap号码是多少就把第几位变成1。大小就只需要10^8bit≈125*10^5B≈12.5MB。那如果考虑需要统计多少次呢那就用连续的几位来进行二进制加法计数比如次数不超过255就连续8位表示次数空间需要12.5*8100MB以此类推。
那就实现一下最初说的Map方法吧进行了coding
3.刚刚的hashmap如果在累加过程中val的Integer溢出map会有什么处理吗(我记得没有会抛出异常所以我catch了)
4.java注解的原理和用途
5.假设我是一个不懂java的人怎么给我介绍java aop
6.反射了解吗是java的特性的话c有反射吗反射和黑客所说的hook钩子有关系吗
7.redis为什么快(传统八股)
8.redis怎么保证数据安全的会发生丢失吗
9.如果数据过大redis性能会不会受限接近mysql
10.关系型数据库和非关系型数据库的区别联系
11.mysql你是怎么学的
12.mysql主从复制分类和原理
13.mysql除了binlog还有其他的吗什么作用
14.执行sql语句过程是什么binlogredolog这些什么时候写
15.binlog具体作用是什么
16.如果现在有一台主一台备采用半同步复制必须要binlog吗如果没有备呢
17.秒杀系统redis作用如果并发几十万库存10如何设计怎么扛得住并发而且不超卖(这里确实有点问题回答偏了答到先放部分库存容错后续再开一次秒杀了)
18.本科学过密码学吗有哪些加解密算法RSA的用途是什么为什么要存密码用AES可以看看目前业界的方式主要是不存储密码了。对称加密算法ARS算法用于大量数据的加密
19.这边是做财付通的有问题没base地以及是倾向于AI还是纯后台开发都可以选
20.实习内容目前手里的offer实习转正吗整体感觉非常舒服很尊重人一直在给予反馈和引导也没pua大概是一个40左右的哥体验非常好整体100分钟很累下午看已经通过等约面函数式编程
Lambda
(参数列表) - {代码}new Thread( () - {System.out.println(语法糖);}
).start();public static void main(String[] args){for (int val) {sout(val);}
}参数类型省略
方法体只有一句代码时大括号和唯一一句代码的分号可以省略
Stream流
ListAuthor authors getAuthors();
authors.stream().distinct().filter(author - author.getAge() 19).forEach(author - System.out.println(author.getName()));// 单列集合
ListAuthor authors gatAuthors();
StreamAuthor stream authors.stream();
// 双列集合
MapString, Integer map new HashMap();
map.put(XXX, 11);
StreamMap.EntryString, Integer stream map.entrySet().stream();中间操作
filter过滤
map对流中的元素进行计算和转换Integer存在装箱操作浪费时间 优化方式 - mapToInt
authors.stream().map(author - author.getName()).map(s - s 1).forEach(s - sout(s));distinct去重 在实体类中添加EqualsAndHashCode 相当于equals
sort排序
.sort((o1, o2)) - o1.getAge() - o2.getAge())// 空参条件下需要在实体类中实现Comparable实体类接口limit限制条数
skip跳过流中的前n个元素返回剩下的元素
flatMap
说明map只能把一个对象转换成一个对象来作为流中的元素而flatMap可以把一个对象转换成多个对象作为流中的元素
// author实体类中有ArrayListBook
ListAuthor authors getAuthors();
authors.stream().flatMap(author - author.getBooks().stream()).distinct().forEach(book - sout(book,getName()));// 根据种类分开打印
flatMap(book - Arrays.stream(book.getCategory().split(,)))终结操作
forEach
count
min max
collection将当前元素转换成一个集合
.collection(Collectors.toList()); // 将元素转化为集合anyMatch boolean类型判断是否有匹配类型
allMatch 判断所有
noneMatch 都不符合
findAny 获取流中的任意一个元素该方法没有办法保证获取的一定是流中的第一个元素
findFirst 获取流中的第一个元素
reduce归并对流中的数据按照制定的计算方式计算出一个结果缩减操作
.reduce(0,(result, element) - result element); // 累加
// identit0 相当于result的初始值Optional
避免空指针异常
// 无论传入的参数是否为null都不会出现问题
Author authors getAuthors();
OptionalAuthor authorOptional Optional.ofNullable(author);
// ifPresent 安全消费值
// 会判断其中封装的数据是否为空不为空才会执行具体的消费代码
authorOptional.filter(author - author.age() 19)ifPresent(author - sout(author.getName()));Author authors getAuthors();
OptionalAuthor authorOptional Optional.ofNullable(author);
// 获取数据如果数据不为空则获取该数据如果为空则抛出异常
try {Author author authorOptional.orElseThrow((SupplierThrowable) () - new RuntimeException(author为空) );sout(author.name);
}catch{res 0;
}map 数据转换
函数式接口
只有一个抽象方法的接口
FunctionalInterface
方法引用
类名或对象名 ::方法名// 引用类的静态方法把重写的抽象方法中的所有参数都按照顺序传入了这个静态方法中
ListAuthor authors getAuthors();
StreamAuthors authorStream authors.stream();authors.parallelStream() // 并行流stream.parallel().filter(num - num 5)authorStream.map(author - author.getAge()).map(String::valueOf);// 引用对象的实例方法
StringBuilder sb new StringBuilder();
authorStream.map(author - author.getName())// .forEach(name - sb.append(name)).forEach(sb::append);// 构造器引用
// forEach(str - sout(str))
.forEach(System.out::println)// .map(name - new StringBuilder(name)).map(StringBuilder::new)代码规范
判断所有集合内部的元素是否为空,使用isEmpty()方法,而不是size() 0
项目总结
Controller 类 0. Try catch 1.参数校验不用每个参数都做校验、判断对象不为空即可2.iml实现3.result的code返回。
catch中不能有return通过修改res的数值来进行return。
前端先写死然后和用户沟通确保样式后修改
空仓库中的.git文件拖动到要提交的文件中然后commit提交文件
数据库字符集utf8mb4排序规则utf8mb4_general_ci数据库索引状态/性别tintint 1主键 varchar 20/ 50/ Long -- id日期datatime
多线程考虑加锁的同步机制、原子性(事物要么全部提交成功,要么全部失败)
方法.var 自动补充对象
名称
boolean valid 有效的常量实体类
枚举类
// 非空判断
String.trim().length 0 || Object.isEmpty();// 方法参数注解
NotEmpt // 非空
Email // 邮箱
easy-captcha // 验证码读代码ctrl shift - 收缩代码只看每个方法的作用了解代码结构
Target(TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_CARIABLE)
// 用于 类 字段 方法 参数 构造函数 局部变量
Retention(RetentionPolicy.SOURCE)
// 只在源代码中存在编译后被丢弃通用常量类可结合枚举类使用通常是一个类或接口里面定义一组 public static final 变量。常量类不允许实例化通常会将构造函数设为私有。
使用场景适用于定义不需要关联行为的常量常常用于配置项、系统常量等。
public class Constants {public static final String TASK_CLASS_NAME TASK_CLASS_NAME;public static final int SUCCESS 200;public static final String[] COLUMNTYPE_TIME { datetime, time, date, timestamp };public static final String UTF8 UTF-8;public static final String GBK GBK;public static final String WWW www.;public static final String HTTPS https://;
}枚举类自定义参数
使用场景适用于需要固定一组常量并且这些常量可能需要关联一些行为或属性的情况例如状态、类型、分类等。
public enum Status {// 正常NORMAL(0);// 暂停PAUSE(1);private String value;private Status(String value) {this.value value;} public String getValue() {return value;}
}// 业务操作类型
public enum BusinessType
{OTHER, // 其他INSERT, // 添加UPDATE, // 修改DELETE, // 删除GRANT, // 授权EXPORT, // 导出IMPORT, // 导入FORCE, // 强退GENCODE,// 生成代码CLEAN, // 清空数据
}public enum DataSourceType {MASTER, // 主库SLAVE // 从库
}// 请求方式
public enum HttpMethod
{GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;private static final MapString, HttpMethod mappings new HashMap(16);static{for (HttpMethod httpMethod : values()){mappings.put(httpMethod.name(), httpMethod);}}Nullablepublic static HttpMethod resolve(Nullable String method){return (method ! null ? mappings.get(method) : null);}public boolean matches(String method){return (this resolve(method));}
}测试
压测内容 压测线程数 吞吐量 / s 90%响应时间 99%响应时间
写excel表格测试用例、测试数据、预期结果、有效/无效
性能测试JMH
!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-core --
dependencygroupIdorg.openjdk.jmh/groupIdartifactIdjmh-core/artifactIdversion1.23/version
/dependency
!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-generator-annprocess --
dependencygroupIdorg.openjdk.jmh/groupIdartifactIdjmh-generator-annprocess/artifactIdversion1.23/versionscopeprovided/scope
/dependency测试代码
BenchmarkMode(Mode.AverageTime) // 测试完成时间
OutputTimeUnit(TimeUnit.NANOSECONDS)
Warmup(iterations 2, time 1, timeUnit TimeUnit.SECONDS) // 预热 2 轮每次 1s
Measurement(iterations 5, time 1, timeUnit TimeUnit.SECONDS) // 测试 5 轮每次 1s
Fork(1) // fork 1 个线程
State(Scope.Thread) // 每个测试线程一个实例
public class HashMapCycleTest {static MapInteger, String map new HashMap() {{// 添加数据for (int i 0; i 100; i) {put(i, val: i);}}};public static void main(String[] args) throws RunnerException {// 启动基准测试Options opt new OptionsBuilder().include(HashMapCycle.class.getSimpleName()) // 要导入的测试类.output(/Users/admin/Desktop/jmh-map.log) // 输出测试结果的文件.build();new Runner(opt).run(); // 执行测试}Benchmarkpublic void entrySet() {// 遍历IteratorMap.EntryInteger, String iterator map.entrySet().iterator();while (iterator.hasNext()) {Map.EntryInteger, String entry iterator.next();Integer k entry.getKey();String v entry.getValue();}}Benchmarkpublic void forEachEntrySet() {// 遍历for (Map.EntryInteger, String entry : map.entrySet()) {Integer k entry.getKey();String v entry.getValue();}}Benchmarkpublic void keySet() {// 遍历IteratorInteger iterator map.keySet().iterator();while (iterator.hasNext()) {Integer k iterator.next();String v map.get(k);}}Benchmarkpublic void forEachKeySet() {// 遍历for (Integer key : map.keySet()) {Integer k key;String v map.get(k);}}Benchmarkpublic void lambda() {// 遍历map.forEach((key, value) - {Integer k key;String v value;});}Benchmarkpublic void streamApi() {// 单线程遍历map.entrySet().stream().forEach((entry) - {Integer k entry.getKey();String v entry.getValue();});}// 此方法为多线程,一定是最好,就不参与测试public void parallelStreamApi() {// 多线程遍历map.entrySet().parallelStream().forEach((entry) - {Integer k entry.getKey();String v entry.getValue();});}
}