Как можно сохранить информацию о кликах и времени их совершения в кликере?

Всем привет. <br/> Я разработал кликер для нашей компании в Телеграме с использованием PHP и JavaScript. Изначально каждый клик сохранялся в базе данных (MySQL), и на каждый клик выполнялись три запроса: <br/> 1. Проверка количества кликов за последние 4 часа (существовало ограничение); <br/> 2. Увеличение количества очков на +1; <br/> 3. Сохранение времени клика в отдельную таблицу. <br/><br/> На этапе тестирования все работало корректно. Однако при увеличении нагрузки (около 100 пользователей) база данных не справлялась, и вместо ожидаемых 100 кликов людям засчитывало около 40. <br/><br/> В результате я изменил скрипт, чтобы сохранять количество очков в localStorage, а время кликов в cookies. Тем не менее, я понимаю, что это не самый оптимальный подход, так как пользователи могут заходить с нескольких устройств (например, с телефона и ПК). В качестве альтернативы я рассматриваю возможность собирать данные о кликах и их времени каждые 3-5 секунд, но как быть с теми, кто быстро кликает и выходит?
  • 30 октября 2024 г. 7:53
Ответы на вопрос 2
Чтобы эффективно сохранять информацию о кликах и времени их совершения в вашем кликере и избежать проблем с нагрузкой на базу данных, можно рассмотреть несколько стратегий. Вот некоторые из них:

### 1. **Сжатие запросов**
Вместо того чтобы выполнять три отдельных запроса на каждый клик, вы можете комбинировать их в один запрос. Например, вы можете сначала сохранить клик временно (например, в массиве на стороне клиента) и отправить данные на сервер одним запросом через определённый промежуток времени. Это уменьшит количество обращений к базе данных.

### 2. **Использование фоновых задач**
Если у вас есть возможность использовать очереди (например, через Redis, RabbitMQ или другие системы), вы можете отправлять клики в очередь, а затем обрабатывать их в фоновом режиме. Это поможет распределить нагрузку и избежать блокировок в базе данных.

### 3. **Дебаунсинг кликов**
Если пользователь кликает несколько раз за короткий промежуток времени, вы можете игнорировать лишние клики, используя технику дебаунсинга. Например, если пользователь кликает быстрее чем 100 мс между кликами, можно считать это как один клик. Пример реализации на JavaScript:

```javascript
let lastClickTime = 0;
const debounceTime = 100; // 100 мс

function handleClick() {
    const currentTime = Date.now();
    if (currentTime - lastClickTime > debounceTime) {
        lastClickTime = currentTime;
        // отправка клика на сервер
    }
}
```

### 4. **Сохранение данных на стороне клиента и синхронизация**
Вы можете продолжать использовать `localStorage` и `cookies` для временного хранения кликов, но обязательно синхронизируйте эти данные с сервером при следующем соединении. Например, когда пользователь закрывает вкладку или через определённые промежутки времени, вы отправляете данные на сервер.

### 5. **Оптимизация базы данных**
Убедитесь, что у вас правильно настроены индексы в базе данных, чтобы запросы на проверку количества кликов и их сохранение выполнялись быстрее. Также можно рассмотреть возможность временного хранения кликов в памяти (например, в Redis), если это допустимо в вашей архитектуре.

### 6. **Лимитирование кликов на уровне приложения**
Если это допустимо, вы можете ограничить максимальное количество кликов на уровне клиента — к примеру, если клик сделан за последнюю секунду, игнорировать его на клиенте.

### 7. **Обработка сценария выхода**
Если пользователь быстро кликает и выходит, вы можете реализовать механизмы, отслеживающие активность пользователя. Например, хранить последний клик в `localStorage` и периодически (например, каждые 3-5 секунд) отправлять накопленные клики на сервер. Этот подход подойдет для пользователей, которые могут быть активны, но не хотят оставаться на странице слишком долго.

С помощью этих стратегий можно значительно повысить устойчивость и надежность вашего кликера, а также улучшить пользовательский опыт.
вместо условных 100 кликов людям засчитывало ~40
судя по sql у тебя количество сохраняемых кликов считается как сначала запросом получить текущее значение, затем сохранить его увеличенным... что естественно неправильно обсчитывается, если одновременно на бакэнд идут несколько запросов, и завершаются в разном порядке (т.е. первый, получил значение 1, затем его обогнал второй, получил то же значение 1, оба отправляют +1 значение, т.е. 2, вместо ожидаемого 3.

Правильно: одним обновлением в базе нужно - проверять допустимость клика (проверить время последнего клика), обновить время последнего клика и увеличить количество кликов на 1... после чего бакэнд проверяет, сколько записей было обновлено, если 0 - значить выход за лимиты, если 1 - все ок.
update set clicks=clicks+1, last_click_time=now() where last_click_time+:ALLOWED_CLICK_INTERVAL<now() and id=:current_id


p.s. даже очень слабая машина позволит делать сотню запросов в секунду на обновление, а хорошая - десяток тысяч

Можно больше, но тогда понадобится разнести таблицу аналитики и таблицу событий, в таблицу событий записывают события, но она без индексов, а в аналитику зааливать данные из всех собранных событий, в цикле
Похожие вопросы