Giter VIP home page Giter VIP logo

jseckill's People

Contributors

bootsrc avatar dependabot[bot] avatar ercargo avatar tajinshi avatar zhangjxpon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jseckill's Issues

RabbitMQ问题

  1. 是否没有配置消息队列最大长度限制以及溢出行为,队列满了之后默认会丢弃队头的元素,先进入队列的反而被丢弃了?
  2. 入队前redis判断库存并没有减库存,则可能导致远超库存限制的SeckillMsgBody进入队列,同个id的请求也可能重复进入队列,这样增加了MQ和consumer的压力,需要处理很多无效的请求?是否可以添加一个 set 记录历史入队的id,入队前判断已入队数量和是否重复入队再考虑是否需要入队?

请删除无效字符

/jseckill-backend/src/main/java/com/liushaoming/jseckill/backend/boot/InitTask.java:24

需要删除无效字符。

@Component

public class InitTask implements CommandLineRunner {
    private static final Logger logger = LoggerFactory.getLogger(InitTask.class);
å
    @Resource(name = "initJedisPool")
    private JedisPool jedisPool;

客户端轮询秒杀是否成功,换成websocket是否更好

一些 web 应用不采用 webocket有一个原因是多页面重开。你想想,同时打开几个秒杀页面就是几个 websocket 连接,这个比较难处理。不像客户端,登录一个可以踢掉另一个,在 web 上这种情况很普遍,轮询处理简单很多。
而且一旦查询到秒杀成功或者失败,就马上停止轮询,不会太消耗服务器的带宽.

demo

1.大佬问一下支付功能怎么体现,我在输入手机号后秒杀成功,然后也没有支付界面,mysql中库存也没变。。。
2.大佬,Jemeter怎么传不同的手机号啊。。。

rabbitmq的生产和消费是只用了一个队列吗?

不是很懂rabbitmq,所以希望有大佬能解释一下,因为看那个流程图上画的是,在redis进行秒杀的时候就是发送到名字为seckill的队列中,在支付的时候发送到另外一个队列中去。所以就有疑问,秒杀的时候是放到一个队列中去吗?

关于mysql读写分离

大佬你好,想问一下你文档中说的MySQL读写分离这里你是在哪里配置的呢,谢谢

是否存在情况当未在指定时间段内收到ACK返回,但Redis却被处理的情况(handleInRedis方法正常执行),导致redis库存数-1的情况

是否存在情况当未在指定时间段内收到ACK返回,

    boolean sendAcked = false;
        try {
            sendAcked = channel.waitForConfirms(100);  100ms时间内
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }

但Redis却被处理的情况(handleInRedis方法正常执行),

 @Override
    public void handleInRedis(long seckillId, long userPhone) throws SeckillException {
        Jedis jedis = jedisPool.getResource();

        String inventoryKey = RedisKeyPrefix.SECKILL_INVENTORY + seckillId;
        String boughtKey = RedisKeyPrefix.BOUGHT_USERS + seckillId;

        String inventoryStr = jedis.get(inventoryKey);
        int inventory = Integer.valueOf(inventoryStr);
        if (inventory <= 0) {
            logger.info("handleInRedis SECKILLSOLD_OUT. seckillId={},userPhone={}", seckillId, userPhone);
            throw new SeckillException(SeckillStateEnum.SOLD_OUT);
        }
        if (jedis.sismember(boughtKey, String.valueOf(userPhone))) {
            logger.info("handleInRedis SECKILL_REPEATED. seckillId={},userPhone={}", seckillId, userPhone);
            throw new SeckillException(SeckillStateEnum.REPEAT_KILL);
        }
        jedis.decr(inventoryKey);
        jedis.sadd(boughtKey, String.valueOf(userPhone));
        logger.info("handleInRedis_done");
    }

导致redis库存数-1,且用户无法继续购买的问题

12/17-17:18:54 [http-nio-27000-exec-2] INFO  com.liushaoming.jseckill.backend.mq.MQProducer-  [mqSend] '{"seckillId":1000,"userPhone":18668042850}'
12/17-17:18:54 [pool-3-thread-6] INFO  com.liushaoming.jseckill.backend.mq.MQConsumer- ---receive_threadId_1=42
12/17-17:18:54 [pool-3-thread-6] INFO  com.liushaoming.jseckill.backend.mq.MQConsumer- [mqReceive]  '{"seckillId":1000,"userPhone":18668042850}'
12/17-17:18:54 [pool-3-thread-6] INFO  com.liushaoming.jseckill.backend.service.impl.SeckillServiceImpl- handleInRedis_done
12/17-17:18:54 [pool-3-thread-6] INFO  com.liushaoming.jseckill.backend.mq.MQConsumer- ------processIt----
12/17-17:18:54 [pool-3-thread-6] INFO  com.liushaoming.jseckill.backend.mq.MQConsumer- ---->ACK
java.util.concurrent.TimeoutException
	at com.rabbitmq.client.impl.ChannelN.waitForConfirms(ChannelN.java:229)
	at com.rabbitmq.client.impl.recovery.AutorecoveringChannel.waitForConfirms(AutorecoveringChannel.java:697)
	at com.liushaoming.jseckill.backend.mq.MQProducer.send(MQProducer.java:53)
	at com.liushaoming.jseckill.backend.service.impl.SeckillServiceImpl.handleSeckillAsync(SeckillServiceImpl.java:172)
	at com.liushaoming.jseckill.backend.service.impl.SeckillServiceImpl.executeSeckill(SeckillServiceImpl.java:124)
	at com.liushaoming.jseckill.backend.service.impl.SeckillServiceImpl$$FastClassBySpringCGLIB$$85f44643.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:684)
	at com.liushaoming.jseckill.backend.service.impl.SeckillServiceImpl$$EnhancerBySpringCGLIB$$4cd4b877.executeSeckill(<generated>)
	at com.liushaoming.jseckill.backend.controller.SeckillController.execute(SeckillController.java:90)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)
12/17-17:18:54 [http-nio-27000-exec-2] INFO  com.liushaoming.jseckill.backend.mq.MQProducer- sendAcked=false
12/17-17:18:54 [http-nio-27000-exec-2] INFO  com.liushaoming.jseckill.backend.mq.MQProducer- !!!mqSend_NACKED,NOW_RETRY>>>
12/17-17:18:54 [http-nio-27000-exec-2] INFO  com.liushaoming.jseckill.backend.service.impl.SeckillServiceImpl- ENQUEUE_PRE_SECKILL>>>seckillId=1000,userPhone=18668042850
12/17-17:18:54 [pool-3-thread-3] INFO  com.liushaoming.jseckill.backend.mq.MQConsumer- ---receive_threadId_1=38
12/17-17:18:54 [pool-3-thread-3] INFO  com.liushaoming.jseckill.backend.mq.MQConsumer- [mqReceive]  '{"seckillId":1000,"userPhone":18668042850}'
12/17-17:18:54 [pool-3-thread-3] INFO  com.liushaoming.jseckill.backend.service.impl.SeckillServiceImpl- handleInRedis SECKILL_REPEATED. seckillId=1000,userPhone=18668042850
12/17-17:18:54 [pool-3-thread-3] INFO  com.liushaoming.jseckill.backend.mq.MQConsumer- ------processIt----
12/17-17:18:54 [pool-3-thread-3] INFO  com.liushaoming.jseckill.backend.mq.MQConsumer- --LET_MQ_ACK REASON:SeckillStateEnum.SOLD_OUT,SeckillStateEnum.REPEAT_KILL

如果希望采用多个服务器进行消息的消费,是不是在操作redis减库存的时候加分布式锁呢?

` @OverRide
public void handleInRedis(long seckillId, long userPhone) throws SeckillException {
Jedis jedis = jedisPool.getResource();
//获取前缀,+商品的秒杀id=当前秒杀商品的key
String inventoryKey = RedisKeyPrefix.SECKILL_INVENTORY + seckillId;
//key前缀+商品的秒杀id
String boughtKey = RedisKeyPrefix.BOUGHT_USERS + seckillId;
//获取商品库存
String inventoryStr = jedis.get(inventoryKey);
//转换成int
int inventory = Integer.valueOf(inventoryStr);
if (inventory <= 0) {
logger.info("handleInRedis SECKILLSOLD_OUT. seckillId={},userPhone={}", seckillId, userPhone);
throw new SeckillException(SeckillStateEnum.SOLD_OUT);
}
//这里使用了redis的set集合,使用秒杀商品的id作为key,value是一个set集合,
//这里是先判断当前秒杀商品的秒杀集合中是否存在了用户的电话,如果存在,说明该用户已经秒杀过一次了,抛出重复秒杀异常
if (jedis.sismember(boughtKey, String.valueOf(userPhone))) {
logger.info("handleInRedis SECKILL_REPEATED. seckillId={},userPhone={}", seckillId, userPhone);
throw new SeckillException(SeckillStateEnum.REPEAT_KILL);
}
//商品redis中库存-1
jedis.decr(inventoryKey);
//往商品的set集合中添加手机号,作为成员,代表该手机号用户已经秒杀了该商品
jedis.sadd(boughtKey, String.valueOf(userPhone));
logger.info("handleInRedis_done");

}`

我给您的这个方法添加了一些注释,是不是需要在 jedis.decr(inventoryKey);这里使用分布式锁,防止多余的减库存请求进入redis,或者是在消费者调用这个方法的时候就使用分布式锁,我感觉后面这个比较好一些呢

秒杀输入手机号问题

大佬你好,我在github上看到了你的秒杀项目,想问一下:
1.第一次启动项目时可以输入手机号,后来启动就再也没有输入手机号这个功能了是什么原因?
2.这个项目可以用测试工具测试吗?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.