miaosha秒杀项目整体认识

秒杀项目整体认识  https://github.com/imyzt/imooc_miaosha  
	项目相关问技术问题解释https://blog.csdn.net/qq_41216743/article/details/106539159
	1)redis做对象缓存:(因为redis毕竟有网络开销,有些地方可以使用conCurrentHashMap代替redis)

将商品秒杀对象缓存在redis中减少mysql的io

用户登录token(分布式session)

常用的数据标记在redis中(如:数据是否被秒杀了,是否重复秒杀等等)

(2)ajax前端静态化:将html缓存在客户端,减少网络数据传输(vue是更好的选择,如果会前端编程可以用nodejs相关框架)

(3)加密使用的是两次MD5:前端一次MD5传到后端,后端一次MD5,最后加入数据库

(4)validate自定义注解(JSR303):访问数据前对数据正则判断,不符合要求的一律不允许通过,用注解统一管理使得代码更加优雅简洁

(5)全局异常处理:使得就算报错,前端也不会跳出奇怪的异常界面,而是在后端控制台显示已经捕获的异常

(6)本项目的util也提供了雪花算法生成id的方式,虽然为了简化代码量没有使用,但是提供简单的demo供大家学习。
也可以参考雪花算法的使用:https://blog.csdn.net/qq_35688140/article/details/100152631

(7)rabbitmq:为了减少数据库一次性写入太多数据而无法承受,故设置了rabbitmq作为数据的缓冲,稍后再写入到数据库。

(8)隐藏秒杀的url:在调用秒杀的url之前多加了一层验证,防止机器人不停刷秒杀用的url,该验证层使用限流算法限制流量

(9)限流设置:使用自定义注解的方式限制用户的流量,一旦流量大于5秒内5次,就返回刷新频率过高。(因为采用注解的方式,可以手动传入秒数和次数)
限流算法:https://blog.csdn.net/qq_35688140/article/details/100775820

(10)服务器可以nginx+多个tomcat实现分担负载
————————————————
版权声明:本文为CSDN博主「LUK流」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_35688140/article/details/100522023

搭建过程问题集锦
	0.项目数据库表,使用项目中自带的miaosha.sql全部和miaosha1.sql中的miaosha_message、miaosha_message_user即可
	1.Unable to load authentication plugin 'caching_sha2_password'
		mysql-connector的版本不对,我之前是3.0.16,旧版本不支持sha,替换为新版本即可,我替换为了8.0.15
	2.lombok @Setter@Getter未生效
		intelij idea需要添加lombok插件,然后重新启动intelij idea 
	3.generatorConfiguration 配置生成器
		https://blog.csdn.net/qq_42872629/article/details/91417620
	4.注册页面的注册码单击事件无法生效  
		由
			$("#verifyCodeImg").attr("src", "/miaosha/verifyCodeRegister");
		改为
			$("#verifyCodeImg").attr("src", "/miaosha/verifyCodeRegister?"+Math.random());
		本质上是通过点击事件获取到验证码图片的URL 地址,实现自动刷新
	5:注册失败 调试查看console提示内容如下
		错误
			Cause: java.sql.SQLIntegrityConstraintViolationException: Column 'id' cannot be null
			; SQL []; Column 'id' cannot be null; nested exception is java.sql.SQLIntegrityConstraintViolationException: Column 'id' cannot be null

		@Insert("insert into miaosha_user (id , nickname ,password , salt ,head,register_date,last_login_date)value (#{id},#{nickname},#{password},#{salt},#{head},#{registerDate},#{lastLoginDate}) ")
		@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
		public void insertMiaoShaUser(MiaoshaUser miaoshaUser);
	原因
		数据库设计时没有采取id自动递增
		且dao层改为如下 取消id有关字段设置
		@Insert("insert into miaosha_user (nickname ,password , salt ,head,register_date,last_login_date)value (#{nickname},#{password},#{salt},#{head},#{registerDate},#{lastLoginDate}) ")
		@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
		public void insertMiaoShaUser(MiaoshaUser miaoshaUser);
		
		//Logininfo{id=null, nickname='18088886666', password='b7797cce01b4b131b433b6acf4add449', salt='1a2b3c4d', head='null', registerDate=Mon Mar 22 15:03:57 CST 2021, lastLoginDate=null, loginCount=null}
	再注册则成功	
		{
		  "id": 18912341235,
		  "loginCount": 0,
		  "nickname": "18088886666",
		  "password": "b7797cce01b4b131b433b6acf4add449",
		  "registerDate": 1616398679000,
		  "salt": "1a2b3c4d"
		}
		18088886666
		123456
		b7797cce01b4b131b433b6acf4add449   123456
	
6. intelij idea F7 into,F8 over,F9 pass
7.public String list(HttpServletRequest request, HttpServletResponse response, Model model, MiaoshaUser user) {...}
	Model model, MiaoshaUser user 映射的解释
	Model model:modelmap,modelandview
				https://blog.csdn.net/yongwa123/article/details/85017551
				https://blog.csdn.net/u013541707/article/details/108886764
				参考问题9
	
	MiaoshaUser user:UserArgumentResolvers类的使用原理
						https://blog.csdn.net/liurui50/article/details/100156253
						https://blog.csdn.net/mikezzmeric/article/details/87562475
						
8. 登录页面流程排错
9.SpringBoot源码——请求全过程源码分析——一步一步详细分析  由访问url到intercept到controller(model)到render到themyleafviewresover、jspviewresover等
	https://www.dazhuanlan.com/2020/01/15/5e1f14aa65ac8/
10.miaosha项目源码
	https://gitee.com/Cui-YJ/miaosha
11.AccessInterceptor extends HandlerInterceptorAdapter
	prehandler:https://www.iteye.com/blog/elim-1750680
	aftercompletion:https://www.iteye.com/blog/elim-1750680
	render:	这个render是为了在prehandler不通过false时候,
			自定义的返回浏览器的方法 而不是继承来的方法,与controller 的render要区别开来,
			如果prehandler执行通过了true,那么这个render的方法就不会执行
	
12.唯一索引,在数据库表中进行设定
		UNIQUE KEY `u_uid_gid` (`user_id`,`goods_id`) USING BTREE
秒杀项目解决的问题列表一一进行代码层面的分析
13.@ControllerAdvice实现优雅地处理异常
14.basecontroller中的render
	为自定义的返回页面处理方法
	借助redis实现了页面级缓存thymeleafViewResolver,
	节省了页面重新ViewResolver的过程,
	减少服务端处理的压力
15.springboot中的mybatis-spring-boot-starter初始化原理及调用过程分析,即数据源+dao(sql语句)是如何整合和执行的

	简单介绍:https://blog.csdn.net/crq1205/article/details/88040582
	源码介绍:https://blog.csdn.net/wrz115533/article/details/107723232
16.通过内存标记 + redis预减库存 + RabbitMQ异步处理下单
	详细参看MiaoshaController下的miaosha方法内的代码
	或
	https://blog.csdn.net/qq_41216743/article/details/106539159
	
	
	在用户发起秒杀访问时,先访问本地已经初始化好的map,看当前秒杀商品id的库存是否已售罄,若已售罄,直接返回秒杀结束异常,若库存还有,在执行下面的操作。通过内存标记可以减少对后面步骤中的redis访问操作,降低redis的压力,不然每个请求都将访问一次redis

	系统启动时,即将商品和库存数据初始化到redis中,所有的抢购操作都在redis中进行处理,通过Redis预减少库存来减少数据库访问

	通过使用RabbitMQ用异步队列处理下单,实现系统高响应。此处响应客户端后,一般都是抢购成功了,当然不排除例外,此时客户端通过ajax请求轮询访问下单结果接口,直到响应状态成功或者失败

17.高并发项目中ThreadLocal+UserContext管理用户信息
	https://blog.csdn.net/weixin_37841366/article/details/109264300
	miaosha项目主要在UserArgumentResolver中使用参看
	https://www.jianshu.com/p/40606baf49b8


18.rabbitmq 连接报错 An unexpected connection driver error occured
	起先以为是配置错误,确认配置没问题后,百度一下,发现是给用户授予了角色,只能登录控制台,
	但是没有给读写以及管理队列的权限,通过控制台admin按钮查看

	通过命令授权
	语法: set_permissions [-p <vhostpath>] <user> <conf> <write> <read>
	执行: rabbitmqctl set_permissions -p / admin .* .* .* 完成对admin的授权,然后启动项目就正常了
19.系统初始化时,把提供秒杀的物品goods_miaosha信息同步到redis库中
	如何找到,在redisservice中找到set方法右键找到find usages选型进行一一定位比对,找到符合要求的
	MiaoshaController/afterPropertiesSet()
20.Spring afterPropertiesSet方法
	https://blog.csdn.net/u013013553/article/details/79038702
	在看用redis实现异步消息队列时,遇到了注册Event,其中看到了afterPropertiesSet。然后查博客,记录下。
	一、简单介绍
	1、init-method方法,初始化bean的时候执行,可以针对某个具体的bean进行配置。init-method需要在applicationContext.xml配置文档中bean的定义里头写明。例如:<bean id="TestBean" class="nju.software.xkxt.util.TestBean" init-method="init"></bean>
	这样,当TestBean在初始化的时候会执行TestBean中定义的init方法。
	2、afterPropertiesSet方法,初始化bean的时候执行,可以针对某个具体的bean进行配置。afterPropertiesSet 必须实现 InitializingBean接口。实现 InitializingBean接口必须实现afterPropertiesSet方法。
	3、BeanPostProcessor,针对所有Spring上下文中所有的bean,可以在配置文档applicationContext.xml中配置一个BeanPostProcessor,然后对所有的bean进行一个初始化之前和之后的代理。BeanPostProcessor接口中有两个方法: postProcessBeforeInitialization和postProcessAfterInitialization。 postProcessBeforeInitialization方法在bean初始化之前执行, postProcessAfterInitialization方法在bean初始化之后执行。
	总之,afterPropertiesSet 和init-method之间的执行顺序是afterPropertiesSet 先执行,init-method 后执行。从BeanPostProcessor的作用,可以看出最先执行的是postProcessBeforeInitialization,然后是afterPropertiesSet,然后是init-method,然后是postProcessAfterInitialization。
21.生产环境JVM内存溢出案例分析
	https://blog.csdn.net/prestigeding/article/details/89075661
	收集Dump文件有两种方式:
	设置JVM启动参数
	-XX:+HeapDumpOnOutOfMemoryError
	-XX:HeapDumpPath=/opt/jvmdump

	dump分析工具
		MAT
		Visual VM
		IBM HeapAnalyzer
		JDK 自带的Hprof工具
22.如何设置dump文件和JVM参数
	https://blog.csdn.net/weixin_41930050/article/details/106624333
	三个地方
		Idea中修改JVM内存大小
		windows下修改tomcat JVM内存大小
		Linux下修改JVM内存大小
23.生产环境JVM内存大小配置  
	a.可以通过jstack可以查看每隔一段时间内存发生的变化,应用稳定后,可以看到每块内存的占用情况,jvisualvm,tomcat-manger等
	b.对于Java8而言,堆内存的初识容量为机器实际内存大小的1/64, 最大内存不超过机器实际内存的1/4.
	我们的生产环境一般最大4G内存是上限了,这个视具体业务而定,流量大的互联网公司单机内存占用超过16G就会考虑分布式环境了。
	参数实例:
	JAVA_OPTS="-server -Xmx4g -Xms4g -Xmn256m -Xss256k -XX:+DisableExplicitGC  -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -Duser.timezone=GMT+8"
	参考链接:
	https://segmentfault.com/q/1010000016814231
	https://blog.csdn.net/xmtblog/article/details/89326226
24.生产环境CPU的负载飙高应该如何处理
	直观表现系统运行缓慢,
	分析原因有几点可能方向
		full gc次数过多(VM Thread都是gc相关线程):
			解决方式:jsatck+dump+mat分析查看;
			引起原因:a.代码中一次获取了大量的对象,导致内存溢出,此时可以通过eclipse的mat工具查看内存中有哪些对象比较多;
					  b.内存占用不高,但是Full GC次数还是比较多,此时可能是显示的System.gc()调用导致GC次数过多,这可以通过添加-XX:+DisableExplicitGC来禁用JVM对显示GC的响应
	    CPU过高:
			解决方式:top(的消耗高德进程id)=>top -Hp <pid>(得进程中的线程id 超过80%(为合理)以上为比较高)=>jstack+线程id(查看线程具体堆栈信息)
			引起原因:full gc...
		不定期出现的接口耗时现象:
			解决方式:以上两种解决方式就无法解决这个问题了,通过压测工具不断加大访问力度
			引起原因:
		某个线程进入WAITING状态:
			解决方式:jsatck 查看线程具体堆栈信息 找到waiting态线程进行分析
			引起原因:
		死锁:
			解决方式:jsatck
			引起原因:
		线上可能出现的五种导致系统缓慢的情况,我们进行线上日志分析时,主要可以分为如下步骤:
		1、通过top命令查看CPU情况,如果CPU比较高,则通过top -Hp <pid>命令查看当前进程的各个线程运行情况,找出CPU过高的线程之后,将其线程id转换为十六进制的表现形式,然后在jstack日志中查看该线程主要在进行的工作。这里又分为两种情况

		如果是正常的用户线程,则通过该线程的堆栈信息查看其具体是在哪处用户代码处运行比较消耗CPU;
		如果该线程是VM Thread,则通过jstat -gcutil <pid> <period> <times>命令监控当前系统的GC状况,然后通过jmap dump:format=b,file=<filepath> <pid>导出系统当前的内存数据。导出之后将内存情况放到eclipse的mat工具中进行分析即可得出内存中主要是什么对象比较消耗内存,进而可以处理相关代码;
		2、如果通过top命令看到CPU并不高,并且系统内存占用率也比较低。此时就可以考虑是否是由于另外三种情况导致的问题。具体的可以根据具体情况分析:

		如果是接口调用比较耗时,并且是不定时出现,则可以通过压测的方式加大阻塞点出现的频率,从而通过jstack查看堆栈信息,找到阻塞点;

		如果是某个功能突然出现停滞的状况,这种情况也无法复现,此时可以通过多次导出jstack日志的方式对比哪些用户线程是一直都处于等待状态,这些线程就是可能存在问题的线程;

		如果通过jstack可以查看到死锁状态,则可以检查产生死锁的两个线程的具体阻塞点,从而处理相应的问题。

		如果是接口调用比较耗时,并且是不定时出现,则可以通过压测的方式加大阻塞点出现的频率,从而通过jstack查看堆栈信息,找到阻塞点;

		如果是某个功能突然出现停滞的状况,这种情况也无法复现,此时可以通过多次导出jstack日志的方式对比哪些用户线程是一直都处于等待状态,这些线程就是可能存在问题的线程;

		如果通过jstack可以查看到死锁状态,则可以检查产生死锁的两个线程的具体阻塞点,从而处理相应的问题。

		本文主要是提出了五种常见的导致线上功能缓慢的问题,以及排查思路。当然,线上的问题出现的形式是多种多样的,也不一定局限于这几种情况,如果我们能够仔细分析这些问题出现的场景,就可以根据具体情况具体分析,从而解决相应的问题。

25.生产环境因该给应用分配多少的线程合适


26.生产环境发生了溢出如何处理
	生产hprof文件,用mat等工具分析是否发生内存泄漏

	在没发生溢出时可以通过jmap把内存映像打印出来,可以通过多次分析定位问题

27.生产环境应该给服务器分配多少内存合适
	可以通过jstack可以查看每隔一段时间内存发生的变化,应用稳定后,可以看到每块内存的占用情况,jvisualvm,tomcat-manger等

28.如何对垃圾收集器的性能调优
	不同垃圾收集器有不同的调优策略,串行,并行,并发(CMS、G1)
	重要衡量指标:吞吐量、最大停顿时间
	调优目标:保证吞吐量的时候,降低最大停顿时间
29.生产环境CPU负载飚高如何处理
	死循环、IO等待(wait)
	用jstack可以jvm中所有的线程,使用top命令可以找到cpu飚高的线程id,可以看到cpu飚高的线程在做什么操作,判断是否线程不够,还是线程发生等待,还是死循环……
30.生产环境应该给应用分配多少线程合适
	用jstack观察线程状态,假如给应用分配100个线程,100个线程全是runnable,说明线程不够,需要加服务器,如果是10个runable,80是wait,说明有等待的情况,可能需要异步的操作来提高应用的性能……通过分析线程的状态,来确定分配多少个线程合适
31.不加log如何确定请求是否执行了某一行代码
	Btrace:Java动态跟踪分析工具
32.不加log如何实时查看某个方法的入参与返回值
	Btrace
33.JVM字节码是什么东西
	用javap将class文件打印出相应的字节码指令,基于栈的架构
34.循环体中做字符串+拼接为什么效率低
	因为每次都要new stringBuilder对象进行append
35.字符串+拼接一定是StringBuilder.append吗
	Constant Variable(带final的String)
	.intern()(String的字面常量)
36.string常量池怎么回事
	https://blog.csdn.net/udahci/article/details/100132850
37.用字节码分析 i++,++i 到底哪种效率高 
	一样的
	https://blog.csdn.net/goldenfish1919/article/details/80906847
	
	
38.jvm+gc调优 |_ JVM的内存结构以及各个分区
             |_ 常见垃圾回收算法
             |_ 垃圾回收期调优
             |_ 如何分析内存日志
             |_ 垃圾回收器 
             |_ GC日志格式详解
             |_ ParallelGC调优
             |_ G1调优
39.three-high-import 高可用 高可靠 高性能 三高多线程导入系统(该项目意义为理论贯通)
	https://github.com/qiurunze123/threadandjuc
40.数据库、表设计规范和注意点
	https://gitee.com/Cui-YJ/miaosha/blob/master/docs/mysql.md
41.秒杀nginx优化
	https://gitee.com/Cui-YJ/miaosha/blob/master/docs/linux.md
42.
MiaoShaUserKey:tk7dff0989125a41fc80a1a246e07e53ec
14.redis存数据的规则
15.rebbitmq存数据的规则
https://www.bilibili.com/video/BV127411j7SH/?spm_id_from=autoNext
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值