1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/evan_chen_1-jseckill

Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

jseckill

лицензия


📘 🛫 🐱 🏛 🛒 🚀 💡
введение демонстрация технологическая стопка схема архитектуры процесс скилла Quick Start анализ исходного кода
📌 🔨 💌
список задач вопросы и ответы делать вклад связаться с автором

введение

jseckill: веб-сайт для скилла, реализованный на Java, основан на Spring Boot 2.X.

jseckill: Seckill website implemented with Java, based on Spring Boot 2.X.

Благодарим вас за поддержку этого проекта
Пожалуйста, нажмите здесь, чтобы Star

демонстрация

Нажмите, чтобы перейти к демонстрации:http://jseckill.appjishu.com

Примечание: при вводе номера телефона введите любые 11 цифр, не требуется вводить свой действительный номер телефона

Эффекты демонстрации

  

технологическая стопка

  • Spring Boot 2.X
  • MyBatis
  • Redis, MySQL
  • Thymeleaf + Bootstrap
  • RabbitMQ
  • Zookeeper, Apache Curator

схема архитектуры

Схема развертывания (zookeeper временно не используется, можно пропустить)



## Процесс скилла Процесс скилла включает два шага: Шаг 1 (скилл): скилл выполняется в Redis. В этом шаге количество параллельных запросов очень велико, и если пользователь выигрывает, ему предоставляется 30 минут на оплату. Если пользователь не оплатит в течение этого времени, Redis увеличит количество доступных товаров на 1, считая, что пользователь автоматически отказался от оплаты.

Шаг 2 (оплата): после успешной оплаты пользователем, сервер сохраняет запись об оплате в MySQL. В этом шаге количество параллельных запросов меньше, и используется транзакция базы данных для решения вопроса согласованности данных.

Теперь подробно рассмотрим шаг 1, процесс скилла

Схема процесса скилла

  1. Схема шага 1: сначала проходит через балансировку нагрузки и распределение трафика Nginx2. Вход в jseckill для обработки. Ограничение скорости с помощью Google guava RateLimiter. При большом количестве параллельных запросов часть запросов пользователей отбрасывается. 3. Redis проверяет, было ли уже совершено снайпинг. Для предотвращения повторного снайпинга. Если снайпинг еще не был совершен, имя пользователя (в данном случае это номер телефона) и seckillId упаковываются в сообщение и отправляются в RabbitMQ, что приводит к последовательной обработке запросов. Немедленно возвращается состояние "в очереди" клиенту, который отображает "в очереди...". 4. В фоновом режиме слушаем сообщения в RabbitMQ, извлекаем по одному сообщению, парсим его и отправляем запрос в Redis для уменьшения количества товара на 1 (команда decr). Затем подтверждаем получение сообщения (ACK) в очереди. Если уменьшение количества товара выполнено успешно, записываем номер телефона пользователя userPhone в Redis как успешное уменьшение количества товара.5. Шаг 2 в схеме: после успешной записи пользователя в очередь, клиент периодически запрашивает сервер о том, был ли пользователь уведомлен о успешном уменьшении количества товара. Затем клиент проверяет Redis на успешное уменьшение количества товара.
    Если уменьшение количества товара выполнено успешно, или если попытка уменьшения количества товара не удалась, периодические запросы прекращаются.
    Если пользователь все еще находится в очереди, периодические запросы продолжаются.

Детали см. в документации исходного кода

Быстрый старт

  • клонируем исходный код

git clone https://github.com/liushaoming/jseckill.git

  • импортируем файл pom.xml из корневой директории в IntelliJ IDEA/eclipse, затем импортируем файл pom.xml из директории jseckill-backend, и дождёмся завершения загрузки зависимостей Maven Подробные инструкции:

Если используется IDEA, сначала открыть IDEA | File | Open..., выбрать файл pom из корневой директории jseckill, затем выбрать Open as project для импорта корневого проекта jseckill.

Используем меню View | Tool Windows | Maven Projects. Нажимаем "+", добавляем pom из директории jseckill-backend.

Теперь в Maven Projects есть корневой проект jseckill и jseckill-backend. Как показано на рисунке ниже.

Если используется Eclipse, импортируем Maven проект, выбираем два файла pom из директорий jseckill и jseckill-backend.- Измените конфигурацию подключения Redis, MySQL, Zookeeper, RabbitMQ в файле application.properties

  • Правой кнопкой мыши на JseckillBackendApp.java, выберите run as | Java Application

Начинаем отладку

Анализ исходного кода

👉 Перейти к анализу исходного кода

Ограничение скорости на Java-сервере

Используем RateLimiter из Google guava для ограничения скорости
Например: разрешено только OnClickListener 10 человек в секунду для входа в процесс уменьшения количества товара. (возможно, блокировка 90% запросов пользователей, после блокировки возвращается сообщение "К сожалению, товар закончился")
Код AccessLimitServiceImpl.java

package com.liushaoming.jseckill.backend.service.impl;

import com.google.common.util.concurrent.RateLimiter;
import com.liushaoming.jseckill.backend.service.AccessLimitService;
import org.springframework.stereotype.Service;

/**
 * Ограничение скорости перед уменьшением количества товара.
 * Используется RateLimiter из Google guava
 */
@Service
public class AccessLimitServiceImpl implements AccessLimitService {
    /**
     * Разрешено только 10 токенов в секунду, запросы с этими токенами могут войти в процесс уменьшения количества товара
     */
    private RateLimiter seckillRateLimiter = RateLimiter.create(10);

Список задач

  • Реализация истечения срока действия заказа через 30 минут после успешного проведения акции "скидка"План: A: Использование Redis для установки времени истечения ключа и мониторинга истечения времени. После успешного проведения акции "скидка" заказ сохраняется в Redis, время истечения ключа устанавливается на gst 30 минут вперед от текущего времени. Когда ключ истекает, происходит срабатывание монитора, и запускается увеличение количества товаров на складе в Redis на 1.

Исправление: "гст 30 минут" должно быть "30 минут"

Итоговый текст: План: A: Использование Redis для установки времени истечения ключа и мониторинга истечения времени. После успешного проведения акции "скидка" заказ сохраняется в Redis, время истечения ключа устанавливается на 30 минут вперед от текущего времени. Когда ключ истекает, происходит срабатывание монитора, и запускается увеличение количества товаров на складе в Redis на 1.## Вопросы и ответы

Q: Почему иногда можно заметить, что сообщение было отправлено в очередь, но не было обработано?

A: Одной из возможных причин является то, что вы отладываете программу jseckill-backend на своем компьютере, а также запускаете ту же программу на своем сервере. Если обе программы подключены к одному и тому же RabbitMQ, они будут одновременно обрабатывать сообщения, что может привести к такому поведению. Это связано с тем, что в методе

com.liushaoming.jseckill.backend.mq.MQConsumer#receive ограничено количество потребителей.

channel.basicQos(0, 1, false);
```## Исключение ошибок при отладке
 - 1. java.net.SocketException: Socket Closed--nested exception is com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED

03/10-16:51:28 [main] WARN org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext - Исключение, возникшее во время инициализации контекста - отмена попытки обновления: org.springframework.beans.factory.BeanCreationException: Ошибка создания бина с именем 'initTask': не удалось внедрить зависимости ресурсов; вложенные исключения: org.springframework.beans.factory.BeanCreationException: Ошибка создания бина с именем 'MQConsumer': не удалось внедрить зависимости ресурсов; вложенные исключения: org.springframework.beans.factory.UnsatisfiedDependencyException: Ошибка создания бина с именем 'seckillServiceImpl': не удовлетворенная зависимость, выраженная через поле 'mqProducer'; вложенные исключения: org.springframework.beans.factory.UnsatisfiedDependencyException: Ошибка создания бина с именем 'MQProducer': не удовлетворенная зависимость, выраженная через поле 'mqChannelManager'; вложенные исключения: org.springframework.beans.factory.BeanCreationException: Ошибка создания бина с именем 'MQChannelManager': не удалось внедрить зависимости ресурсов; вложенные исключения: org.springframework.beans.factory.BeanCreationException: Ошибка создания бина с именем 'mqConnectionSeckill' определенного в класс-путь ресурсе [com/liushaoming/jseckill/backend/config/MQConfig.class]: Ошибка создания бина через фабричный метод; вложенные исключения: org.springframework.beans.BeanInstantiationException: Не удалось создать экземпляр [com.rabbitmq.client.

03/10-16:51:28 [AMQP Connection 47.99.196.243:5672] ERROR com.rabbitmq.client.impl.ForgivingExceptionHandler - Произошла неожиданная ошибка драйвера соединения
java.net.SocketException: Socket Closed
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
	at java.net.SocketInputStream.read(SocketInputStream.java:170)
	at java.net.SocketInputStream.read(SocketInputStream.java:141)
	at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
	at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
	at java.io.DataInputStream.readUnsignedByte(DataInputStream.java:288)
	at com.rabbitmq.client.impl.Frame чтение из (Frame.java:91)
	at com.rabbitmq.client.impl.SocketFrameHandler.readFrame(SocketFrameHandler.java:164)
	at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:596)
	at java.lang.Thread.run(Thread.java:745)
03/10-16:51:28 [主线] INFO com.alibaba.druid.pool.DruidDataSource - {dataSource-1} закрыто
03/10-16:51:28 [主线] INFO org.apache.catalina.core.StandardService - Остановка сервиса [Tomcat]
03/10-16:51:28 [主线] INFO org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener - Ошибка при запуске ApplicationContext. Чтобы отобразить отчет о состоянии, перезапустите приложение с включенным режимом 'debug'.```
Анализ:
Ключевым моментом является <code>вложенный исключение: com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED</code>  <br/>
И далее указано, что <code>- вход был отклонен с использованием механизма аутентификации PLAIN</code>

Это указывает на неудачу аутентификации имени пользователя и пароля RabbitMQ. Вам необходимо изменить соответствующие настройки в файле application-dev.properties.


- 2. Необходимо ли ручное создание очередей?
Ответ: Ручное создание не требуется. Программа автоматически создает необходимые очереди. По умолчанию создается очередь с именем "seckill", в которую попадают запросы на сейл, а затем они извлекаются и обрабатываются в Redis.


<br/>

## Внести вклад
Особая благодарность разработчикам, внесшим вклад в открытое ПО

| Номер | GitHub разработчика | QQ | Электронная почта |
| :-------: | :-------- | :-------: | :-------- |
| 1 | [liushaoming](https://github.com/liushaoming) | 944147540 | [liushaomingdev@163.com](mailto:liushaomingdev@163.com) |
| 2 | [tajinshi](https://github.com/tajinshi) | OnClickListener 605091800 | [605091800@qq.com](mailto:605091800@qq.com)


## Связаться с автором
|  Контактная информация |  |
| :-------- | :-------- |
| **Лидер** | liushaoming |
| email | [liushaomingdev@163.com](mailto:liushaomingdev@163.com) |
| QQ | 944147540 |


Присоединяйтесь к QQ-группе для обсуждения
<br/>
![](doc/image/group-qrcode.png)

Публичный аккаунт WeChat

![](doc/image/public-account.jpg)

==

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Java снэпшот покупки (Flash Sale на основе Spring Boot) Развернуть Свернуть
Apache-2.0
Отмена

Обновления

Пока нет обновлений

Участники

все

Язык

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/evan_chen_1-jseckill.git
git@api.gitlife.ru:oschina-mirror/evan_chen_1-jseckill.git
oschina-mirror
evan_chen_1-jseckill
evan_chen_1-jseckill
master