Проблема параллелизма в Spring Data Redis - PullRequest
3 голосов
/ 26 мая 2020

У меня большая проблема при использовании нескольких потоков с данными spring-redis, и это настолько легко воспроизвести, что я думаю, что упустил что-то тривиальное.

Прямо к делу

Если я запрашиваю CrudRepository при выполнении операций сохранения, он иногда (до 60%) не находит запись в Redis.

Среда

Код

Несмотря на полный код можно найти по ссылке выше, это основные компоненты:

CrudRepository

@Repository
public interface MyEntityRepository extends CrudRepository<MyEntity, Integer> {

}

Entity

@RedisHash("my-entity")
public class MyEntity implements Serializable {

    @Id
    private int id1;

    private double attribute1;
    private String attribute2;
    private String attribute3;

Controller

    @GetMapping( "/my-endpoint")
    public ResponseEntity<?> myEndpoint () {

        MyEntity myEntity = new MyEntity();
        myEntity.setAttribute1(0.7);
        myEntity.setAttribute2("attr2");
        myEntity.setAttribute3("attr3");
        myEntity.setId1(1);

        myEntityRepository.save(myEntity);//create it in redis

        logger.info("STARTED");

        for (int i = 0; i < 100; i++){
            new Thread(){
                @Override
                public void run() {
                    super.run();

                    myEntity.setAttribute1(Math.random());

                    myEntityRepository.save(myEntity); //updating the entity

                    Optional<MyEntity> optionalMyEntity = myEntityRepository.findById(1);
                    if (optionalMyEntity.isPresent()) {
                        logger.info("found");
                    }else{
                        logger.warning("NOT FOUND");
                    }
                }
            }.start();

        }

        return ResponseEntity.noContent().build();
    }

Результат

2020-05-26 07:52:53.769  INFO 30655 --- [nio-8080-exec-2] my-controller-logger                     : STARTED
2020-05-26 07:52:53.795  INFO 30655 --- [     Thread-168] my-controller-logger                     : found
2020-05-26 07:52:53.798  WARN 30655 --- [     Thread-174] my-controller-logger                     : NOT FOUND
2020-05-26 07:52:53.798  WARN 30655 --- [     Thread-173] my-controller-logger                     : NOT FOUND
2020-05-26 07:52:53.806  INFO 30655 --- [     Thread-170] my-controller-logger                     : found
2020-05-26 07:52:53.806  WARN 30655 --- [     Thread-172] my-controller-logger                     : NOT FOUND
2020-05-26 07:52:53.812  WARN 30655 --- [     Thread-175] my-controller-logger                     : NOT FOUND
2020-05-26 07:52:53.814  WARN 30655 --- [     Thread-176] my-controller-logger                     : NOT FOUND
2020-05-26 07:52:53.819  WARN 30655 --- [     Thread-169] my-controller-logger                     : NOT FOUND
2020-05-26 07:52:53.826  INFO 30655 --- [     Thread-171] my-controller-logger                     : found
2020-05-26 07:52:53.829  INFO 30655 --- [     Thread-177] my-controller-logger                     : found

Итак, с 10 потоками 6 из них не находят результат в db.

Замена на данные пружины redis

Как уже упоминалось здесь замена в redis данными spring redis содержит не менее 9 операций.

Первый вывод

* 104 4 * Итак, чтобы заменить значение в redis, он должен удалить ha sh, индексы, а затем снова добавить новый ha sh и новые индексы, возможно, поток находится в середине выполнения этих операций в то время как другой поток пытается найти значение по индексу, а этот индекс еще не добавлен.

Второй вывод

Я думаю, что почти невозможно, чтобы данные Spring с data-redis имели такую ​​ошибку, поэтому мне интересно, что я не понимаю в data-redis или redis. Поскольку у Redis есть параллелизм, я думаю, что может происходить что-то другое, но в приведенном примере это похоже на то ...

Заранее спасибо всем вам

1 Ответ

0 голосов
/ 26 мая 2020

У вас есть один MyEntity экземпляр:

MyEntity myEntity = createEntity();

Затем вы запустили 10 потоков, каждый из которых обновляет этот один объект myEntity.set....

Затем, когда вы его сохраняете как в myEntityRepository.save(myEntity);, невозможно определить, какое значение сохраняется, поскольку все потоки соревнуются, чтобы вставить свое собственное значение.

Когда вы вызываете myEntityRepository.save, он может сохранять (снова) значение это было написано myEntity другим потоком. Таким образом, у этого потока никогда не было возможности записать его значение в репо, поэтому вы его не найдете!

Я не знаю @RedisHash, поэтому я могу ошибаться, но я думаю, вам нужно создать новый объект сущности каждый раз, когда вы хотите сохранить запись.

Другая не связанная с вашим кодом проблема - это создание неограниченного потока (если вы не планируете использовать его в производственной среде).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...