1.3. 演示超卖现象
接下来咱们使用jmeter压力测试工具,高并发下压测一下,添加线程组:并发100循环50次,即5000次请求。
给线程组添加HTTP Request请求:
填写测试接口路径如下:
再选择你想要的测试报表,例如这里选择聚合报告:
启动测试,查看压力测试报告:
测试结果:请求总数5000次,平均请求时间202ms,中位数(50%)请求是在173ms内完成的,90%请求是在344ms内完成的,最小耗时12ms,最大耗时1125ms,错误率0%,每秒钟平均473.8次。
查看mysql数据库剩余库存数:还有4870
此时如果还有人来下单,就会出现超卖现象(别人购买成功,而无货可发)。
1.4. jvm锁问题演示
使用jvm锁(synchronized关键字或者ReetrantLock)试试:
重启tomcat服务,再次使用jmeter压力测试,效果如下:
查看mysql数据库:
并没有发生超卖现象,完美解决。
1.4.2. 原理
添加synchronized关键字之后,StockService就具备了对象锁,由于添加了独占的排他锁,同一时刻只 有一个请求能够获取到锁,并减库存。此时,所有请求只会one-by-one执行下去,也就不会发生超卖现象。
1.5. 多服务问题
使用jvm锁在单工程单服务情况下确实没有问题,但是在集群情况下会怎样? 接下启动多个服务并使用nginx负载均衡,结构如下:
启动三个服务(端口号分别8000 8100 8200),如下:
1.5.1. 安装配置nginx
基于安装nginx:
1. # 拉取镜像 2. 3. docker pull nginx:latest 4. 5. # 创建nginx对应资源、日志及配置目录 6. 7. mkdir -p /opt/nginx/logs /opt/nginx/conf /opt/nginx/html 8. 9. # 先在conf目录下创建nginx.conf文件,配置内容参照下方 10. 11. # 再运行容器 12. 13. docker run -d -p 80:80 --name nginx -v /opt/nginx/html:/usr/share/nginx/html 14. 15. -v /opt/nginx/conf/nginx.conf:/etc/nginx/nginx.conf -v 16. /opt/nginx/logs:/var/log/nginx nginx
1. user nginx; 2. worker_processes 1; 3. 4. error_log /var/log/nginx/error.log warn; 5. pid /var/run/nginx.pid; 6. 7. events { 8. worker_connections 1024; 9. } 10. 11. http { 12. include /etc/nginx/mime.types; 13. default_type application/octet-stream; 14. 15. log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 16. '$status $body_bytes_sent "$http_referer" ' 17. '"$http_user_agent" "$http_x_forwarded_for"'; 18. 19. access_log /var/log/nginx/access.log main; 20. 21. sendfile on; 22. #tcp_nopush on; 23. 24. keepalive_timeout 65; 25. 26. #gzip on; 27. 28. #include /etc/nginx/conf.d/*.conf; 29. 30. upstream distributed { 31. server 172.16.116.1:8000; 32. server 172.16.116.1:8100; 33. server 172.16.116.1:8200; 34. } 35. 36. server { 37. listen 80; 38. server_name 172.16.116.100; 39. location / { 40. proxy_pass http://distributed; 41. } 42. } 43. 44. }
在浏览器中测试:172.16.116.100是我的nginx服务器地址
经过测试,通过nginx访问服务一切正常。