1.数据库的优化
-
选取最适用的字段属性,可以将表中字段的宽度设得尽可能小
-
使用连接(JOIN)来代替子查询
-
使用联合(UNION)来代替手动创建的临时表
-
防止数据的完整性,使用事务
-
如果用户访问数据库较大时可以通过锁定表的方式来获得更好的性能
-
使用外键,锁定表的方法可以维护数据的完整性,但是它却不能保证数据的关联性。这个时候我们就可以使用外键
-
使用索引,提高数据库的性能便于快速检索
-
优化的查询语句,索引可以提高查询的速度但如果SQL语句使用不恰当的话,索引将无法发挥它应有的作用
-
分库分表:
①只分库不分表:数据库的读或者写的QPS过高,导致数据库的连接不足时(没遇到过这样的场景)
②只分表:单表数据量非常大时,存储和查询性能遇到了瓶颈
③分库分表:数据库连接不够并且表单的数据量也很大
2.JVM的调优问题
使用在JDK中自带的工具jconsole,对JVM中内存,线程和类等的监控
- 如果是堆内存不够: 尝试调整
-Xmx
(最大堆内存),--Xms
选项(初始化堆内存的大小) - **如果是想提高系统的并发性能:**可以尝试降低--Xss的值(每个线程的堆栈大小),JDK5.0以后每个线程堆栈大小为1MB。应根据应用线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。别调太小了,太小了栈溢出了。
- 调整对象在年轻代存活的时间: -XX:MaxTenuringThreshold 默认值15,这个值代表垃圾最大年龄。对于老年代比较多的应用,减少这个值可以提高效率。对于年轻代比较多的应用,增加这个值可以增加数据在年轻代即被回收的概率。这个值调整需要尤其注意,设置小了可能引发老年代频繁full GC,设置大了可能导致某些数据长期存活于新生代,每一次Minor GC都要拷贝它,很影响性能的。
- 调整CMS垃圾回收器并行线程数:
-XX:ConcGCThreads=4
CMS垃圾回收器并行线程线,推荐值为CPU核心数。 - 尽量把永久代的初始值与最大值设置为同一值 ,因为永久代的大小调整需要进行FullGC才能实现。设置为同一个就可以防止内存抖动。
3.Nginx在项目中的应用
请求转发;负载均衡;动静分离
1.轮询(默认),按照时间顺序逐一分配到指定的服务器
2.权重 ,指定轮询机率,修改weight属性大小
4.MQ的消息丢失/重复/积压的理解
消息丢失
原因:消息发送出去,由于网络问题没有抵达服务器
解决方案:1.做好容错方法(try-catch),发送消息失败使用重试机制;2.做好日志记录,每个消息状态是否都被服务器收到都应该被记录;3.做好定期重发,如果消息没有发送成功,定期去数据库扫描未成功的消息进行重发
消息重复
原因:1.成功消费,ACK时宕机,消息由unack变为ready,Broker又重新发送;2.消息消费失败,由于重试机制,自动又将消息发送出去;
解决方案:1.消费者的业务消费接口应该设计成幂等性(对于同一操作发起的一次请求或者多次请求的结果是一致的);2.使用防重表(redis, mysql) 唯一索引,发送消息每一个都有业务的唯一标识,处理过就不用再处理。
消息积压
原因:1.消费者宕机;2.消费者消费能力不足;3.发送者发送流量过大;
解决方案:1.上线更多消费者,进行正常消费;2.上线专门的队列消费服务,将消息先批量取出来,记录数据库,离线慢慢处理
5.redis
面试题(你们是怎么用redis):使用springboot整合,基于springboot的缓存注解做的
1.Redis 持久化机制
Redis是一个支持持久化的内存数据库,通过持久化机制把内存中的数据同步到硬盘文件来保证数据持久化。当Redis重启后通过把硬盘文件重新加载到内存,就能达到恢复数据的目的。
缓存雪崩我们可以简单的理解为:由于原有缓存失效,新缓存未到期间(加锁)
缓存穿透是指用户查询数据,在数据库没有(查询的时候返回数据为空)
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统(定时刷新缓存)
缓存降级当访问量剧增、服务出现问题(Redis出现问题,不去数据库查询,而是直接返回默认值给用户)
redis的数据类型
(一)String
这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。
(二)hash
这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。
(三)list
使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。本人还用一个场景,很合适---取行情信息。就也是个生产者和消费者的场景。LIST可以很好的完成排队,先进先出的原则。
(四)set
因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。
另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。
(五)Zset
Zset多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。
6.Git和Svn的不同
git
1、分布式,每个参与开发的人的电脑上都有一个完整的仓库,不担心硬盘出问题;
2、在不联网的情况下,照样可以提交到本地仓库,可以查看以往的所有log,等到有网的时候,push到远程即可;
3、(缺点)权限管理不是很方便,需要安装插件gitolite,配置有点麻烦,或者直接使用gitlab管理。
svn
1、较好的权限管理功能,可以精确控制每个目录的权限;
2、使用相对git要简单一点。
3、集中式,如果中心服务器出现问题,所有人都不能正常干活,恢复也很麻烦,因为SVN记录的是每次改动的差异,不是完整文件;
4、分支功能没有git强大;
5、速度没有git快,如果有五个分支,是把五个分支的文件全部拷下来;必须联网才能commit。
Oauth2.0
OAuth 2.0 是一个开放标准的授权协议,它允许用户提供一个令牌而不是用户名和密码来访问他们存储在特定服务提供者的数据。OAuth 2.0 使得第三方应用可以在不获取用户密码的情况下,代表用户访问其资源。
tex
OAuth 2.0 提供了四种授权流程:
授权码模式(Authorization Code Grant):适用于有自己的服务器的Web应用。这种模式下,授权码先交给客户端,然后客户端再交换令牌。
简化模式(Implicit Grant):适用于没有后端服务器的客户端应用,如JavaScript前端应用。在这种模式下,令牌直接通过浏览器传给客户端。
密码模式(Resource Owner Password Credentials Grant):适用于用户对客户端高度信任的情况,如操作系统或企业内部应用。用户将用户名和密码直接提供给客户端,客户端使用这些信息获取令牌。
客户端凭证模式(Client Credentials Grant):适用于客户端访问自己的资源服务器,不涉及用户。
安全性
虽然OAuth 2.0增加了安全性,但它也引入了一些潜在的安全问题,如重定向URI劫持、交叉站点请求伪造(CSRF)等。因此,实施OAuth 2.0时,建议采取相应的安全措施,比如使用HTTPS,验证重定向URI,以及使用最新的OAuth 2.0安全最佳实践。
OAuth 2.0 已经成为现代互联网应用中授权的事实标准,被广泛应用于各种场景中,包括Google、Facebook、Twitter等大型服务的API授权。
自我介绍
面试官你好,我叫***,做开发有3年的时间。在成都广力软件任职,后端经验丰富,熟悉前端技术。做过四川省事业编人事管理系统,医科大人事管理系统,西南科技大学招聘管理系统。看了贵公司的职务,我有三个优势,第一就是经历了多个产品,从0~1,1到100的过程,无论是技术选型还是难点攻克,我都有参与主导。第二个就是技术栈和业务的匹配,除了正常的业务开发,还有性能优化和调式。第三就是我工作态度严谨负责,善于思考能够很快融入到工作中。