Сообщение Eventual consistency от 07.07.2018 17:54
Изменено 07.07.2018 18:27 Slicer [Mirkwood]
Eventual consistency
Всем привет.
Вот есть система, которой присущ сабж. Для конкретного примера — который меня вдобавок в первую очередь интересует — возьмем Elasticsearch.
Есть по меньшей мере три наиболее неприятных ситуации, которые могут возникать.
1) Пользователь выполняет создание некой сущности в каком-то веб-приложении, потом запрашивает список этих сущностей — но не видит в нем созданную, потому что приложение ищет через elasticsearch, и (как одна из причин) попадает на тот шард, который еще не успел получить реплику сущности. Как после этого пользователю открывать созданный документ — с ходу непонятно (хотя если дать кнопку "обновить" то вероятно постепенно привыкнет, но выглядит это как-то некрасиво).
2) Аналогично п.1, но еще подлее. Пользователь то видит в списке созданную сущность, то не видит — вплоть до того что например он открывает редактор созданной сущности, вносит изменения туда, а при попытке сохранить получает ошибку из-за того, что сущности якобы нет (потому что опять сходил не на тот шард). Конечно не все приложения при сохранения изменений пойдут в эластик искать там сущность (все-таки мало кто эластик использует как первичную БД), но если вместо эластика например Кассандра — вполне возможно; или могут упасть если они пытаются делать при сохранении UPDATE эластика, а он ведь вроде падает если документа с таким id не нашлось.
3) Код клиента вызывает после создания или сохранения сущности ее повторное чтение (ну например в форме редактирования кнопка "Сохранить" по замыслу не должна закрывать эту форму). И соответственно повторное чтение не может найти сущность или находит ее вариант до изменений. Ну хотя бы для этого сценария есть решение достаточно очевидное — структурировать код клиента так, чтобы не запрашивать данные заново с бека, а использовать те, которые мы отправляли на сохранение.
Так вот, как вы с этим в своих проектах справляетесь?
Ну я знаю что кто-то никак не заморачивается, дескать ну получит юзер ошибку — ну и ладно, значит бог его все равно не любит; а если не увидит документ то дадим ему кнопку Обновить. По 1-ой проблеме еще наверно можно как-то по websocket подписываться на апдейты и подтягивать автоматически, чтобы не заставлять обновлять самостоятельно; еще я слышал о людях которые добавляли к получаемому от бека списку фиктивные строки для только что созданных документов, но при запросах по одной странице — если пагинация используется — это будет конфликтовать с сортировкой, которая по идее проводится на бэке, ведь неясно на какую страницу должна попасть эта фиктивная строка.
Еще я читал про read own writes консистентность и про monotonic read консистентность, они бы позволили решить эти проблемы (монотонность решила бы хотя бы 2-ую). Но как их подружить с системой, которая изначально их сама не поддерживает (тот же эластик например), я не представляю. Вот например для read-own-writes в одной статье предлагали PouchDB применять как локальное хранилище для копии вносимых изменений, но если есть такой кэш, какие должны быть правила eviction для него? До каких пор держать в нем наши изменения? И что если сессии пользователя — не sticky, и следующий запрос его может прийти на другой инстанс приложения — уже в другой pouchdb? Или даже если они sticky например, но использовавшийся в последний раз инстанс — отвалился? Тут по идее надо распределенный кэш тогда вместо pouchdb — но опять возникают вопросы, ведь такой кэш тоже должен быть AP системой (как и сам эластик ну или там кассандра) и потому при переключении клиента на другую ноду может оказаться, что там в этот момент еще не самое свежее состояние сессии. Бида короче =) А как прикрутить к эластику monotonic read consistency, если у него нет глобального понятия "версия всех данных", я тоже не понимаю.
Slicer
Вот есть система, которой присущ сабж. Для конкретного примера — который меня вдобавок в первую очередь интересует — возьмем Elasticsearch.
Есть по меньшей мере три наиболее неприятных ситуации, которые могут возникать.
1) Пользователь выполняет создание некой сущности в каком-то веб-приложении, потом запрашивает список этих сущностей — но не видит в нем созданную, потому что приложение ищет через elasticsearch, и (как одна из причин) попадает на тот шард, который еще не успел получить реплику сущности. Как после этого пользователю открывать созданный документ — с ходу непонятно (хотя если дать кнопку "обновить" то вероятно постепенно привыкнет, но выглядит это как-то некрасиво).
2) Аналогично п.1, но еще подлее. Пользователь то видит в списке созданную сущность, то не видит — вплоть до того что например он открывает редактор созданной сущности, вносит изменения туда, а при попытке сохранить получает ошибку из-за того, что сущности якобы нет (потому что опять сходил не на тот шард). Конечно не все приложения при сохранения изменений пойдут в эластик искать там сущность (все-таки мало кто эластик использует как первичную БД), но если вместо эластика например Кассандра — вполне возможно; или могут упасть если они пытаются делать при сохранении UPDATE эластика, а он ведь вроде падает если документа с таким id не нашлось.
3) Код клиента вызывает после создания или сохранения сущности ее повторное чтение (ну например в форме редактирования кнопка "Сохранить" по замыслу не должна закрывать эту форму). И соответственно повторное чтение не может найти сущность или находит ее вариант до изменений. Ну хотя бы для этого сценария есть решение достаточно очевидное — структурировать код клиента так, чтобы не запрашивать данные заново с бека, а использовать те, которые мы отправляли на сохранение.
Так вот, как вы с этим в своих проектах справляетесь?
Ну я знаю что кто-то никак не заморачивается, дескать ну получит юзер ошибку — ну и ладно, значит бог его все равно не любит; а если не увидит документ то дадим ему кнопку Обновить. По 1-ой проблеме еще наверно можно как-то по websocket подписываться на апдейты и подтягивать автоматически, чтобы не заставлять обновлять самостоятельно; еще я слышал о людях которые добавляли к получаемому от бека списку фиктивные строки для только что созданных документов, но при запросах по одной странице — если пагинация используется — это будет конфликтовать с сортировкой, которая по идее проводится на бэке, ведь неясно на какую страницу должна попасть эта фиктивная строка.
Еще я читал про read own writes консистентность и про monotonic read консистентность, они бы позволили решить эти проблемы (монотонность решила бы хотя бы 2-ую). Но как их подружить с системой, которая изначально их сама не поддерживает (тот же эластик например), я не представляю. Вот например для read-own-writes в одной статье предлагали PouchDB применять как локальное хранилище для копии вносимых изменений, но если есть такой кэш, какие должны быть правила eviction для него? До каких пор держать в нем наши изменения? И что если сессии пользователя — не sticky, и следующий запрос его может прийти на другой инстанс приложения — уже в другой pouchdb? Или даже если они sticky например, но использовавшийся в последний раз инстанс — отвалился? Тут по идее надо распределенный кэш тогда вместо pouchdb — но опять возникают вопросы, ведь такой кэш тоже должен быть AP системой (как и сам эластик ну или там кассандра) и потому при переключении клиента на другую ноду может оказаться, что там в этот момент еще не самое свежее состояние сессии. Бида короче =) А как прикрутить к эластику monotonic read consistency, если у него нет глобального понятия "версия всех данных", я тоже не понимаю.
Slicer
Eventual consistency
Всем привет.
Вот есть система, которой присущ сабж. Для конкретного примера — который меня вдобавок в первую очередь интересует — возьмем Elasticsearch.
Есть по меньшей мере три наиболее неприятных ситуации, которые могут возникать.
1) Пользователь выполняет создание некой сущности в каком-то веб-приложении, потом запрашивает список этих сущностей — но не видит в нем созданную, потому что приложение ищет через elasticsearch, и (как одна из причин) попадает на тот шард, который еще не успел получить реплику сущности. Как после этого пользователю открывать созданный документ — с ходу непонятно (хотя если дать кнопку "обновить" то вероятно постепенно привыкнет, но выглядит это как-то некрасиво).
2) Аналогично п.1, но еще подлее. Пользователь то видит в списке созданную сущность, то не видит — вплоть до того что например он открывает редактор созданной сущности, вносит изменения туда, а при попытке сохранить получает ошибку из-за того, что сущности якобы нет (потому что опять сходил не на тот шард). Конечно не все приложения при сохранения изменений пойдут в эластик искать там сущность (все-таки мало кто эластик использует как первичную БД), но если вместо эластика например Кассандра — вполне возможно; или могут упасть если они пытаются делать при сохранении UPDATE эластика, а он ведь вроде падает если документа с таким id не нашлось.
3) Код клиента вызывает после создания или сохранения сущности ее повторное чтение (ну например в форме редактирования кнопка "Сохранить" по замыслу не должна закрывать эту форму). И соответственно повторное чтение не может найти сущность или находит ее вариант до изменений. Ну хотя бы для этого сценария есть решение достаточно очевидное — структурировать код клиента так, чтобы не запрашивать данные заново с бека, а использовать те, которые мы отправляли на сохранение.
Так вот, как вы с этим в своих проектах справляетесь?
Ну я знаю что кто-то никак не заморачивается, дескать ну получит юзер ошибку — ну и ладно, значит бог его все равно не любит; а если не увидит документ то дадим ему кнопку Обновить. По 1-ой проблеме еще наверно можно как-то по websocket подписываться на апдейты и подтягивать автоматически, чтобы не заставлять обновлять самостоятельно; еще я слышал о людях которые добавляли к получаемому от бека списку фиктивные строки для только что созданных документов, но при запросах по одной странице — если пагинация используется — это будет конфликтовать с сортировкой, которая по идее проводится на бэке, ведь неясно на какую страницу должна попасть эта фиктивная строка.
Еще я читал про read own writes консистентность и про monotonic read консистентность, они бы позволили решить эти проблемы (монотонность решила бы хотя бы 2-ую). Но как их подружить с системой, которая изначально их сама не поддерживает (тот же эластик например), я не представляю. Вот например для read-own-writes в одной статье предлагали PouchDB применять как локальное хранилище для копии вносимых изменений, но если есть такой кэш, какие должны быть правила eviction для него? До каких пор держать в нем наши изменения? И что если сессии пользователя — не sticky, и следующий запрос его может прийти на другой инстанс приложения — уже в другой pouchdb? Или даже если они sticky например, но использовавшийся в последний раз инстанс — отвалился? Тут по идее надо распределенный кэш тогда вместо pouchdb — но опять возникают вопросы, ведь такой кэш тоже должен быть AP системой (как и сам эластик ну или там кассандра) и потому при переключении клиента на другую ноду может оказаться, что там в этот момент еще не самое свежее состояние сессии. Бида короче =) А, ну еще наверно можно было бы на стороне клиента держать кэш вместо этого, но там опять непонятно как настроить eviction так, чтоб кэш не разрастался безгранично.
Как прикрутить к эластику monotonic read consistency, если у него нет глобального понятия "версия всех данных", я тоже не понимаю.
Короче, какое бы решение я ни рассматривал, ко всякому вроде бы можно придумать такой сценарий, при котором клиент может не увидеть только что внесенные им изменения. Или то видеть их, то не видеть.
Slicer
Вот есть система, которой присущ сабж. Для конкретного примера — который меня вдобавок в первую очередь интересует — возьмем Elasticsearch.
Есть по меньшей мере три наиболее неприятных ситуации, которые могут возникать.
1) Пользователь выполняет создание некой сущности в каком-то веб-приложении, потом запрашивает список этих сущностей — но не видит в нем созданную, потому что приложение ищет через elasticsearch, и (как одна из причин) попадает на тот шард, который еще не успел получить реплику сущности. Как после этого пользователю открывать созданный документ — с ходу непонятно (хотя если дать кнопку "обновить" то вероятно постепенно привыкнет, но выглядит это как-то некрасиво).
2) Аналогично п.1, но еще подлее. Пользователь то видит в списке созданную сущность, то не видит — вплоть до того что например он открывает редактор созданной сущности, вносит изменения туда, а при попытке сохранить получает ошибку из-за того, что сущности якобы нет (потому что опять сходил не на тот шард). Конечно не все приложения при сохранения изменений пойдут в эластик искать там сущность (все-таки мало кто эластик использует как первичную БД), но если вместо эластика например Кассандра — вполне возможно; или могут упасть если они пытаются делать при сохранении UPDATE эластика, а он ведь вроде падает если документа с таким id не нашлось.
3) Код клиента вызывает после создания или сохранения сущности ее повторное чтение (ну например в форме редактирования кнопка "Сохранить" по замыслу не должна закрывать эту форму). И соответственно повторное чтение не может найти сущность или находит ее вариант до изменений. Ну хотя бы для этого сценария есть решение достаточно очевидное — структурировать код клиента так, чтобы не запрашивать данные заново с бека, а использовать те, которые мы отправляли на сохранение.
Так вот, как вы с этим в своих проектах справляетесь?
Ну я знаю что кто-то никак не заморачивается, дескать ну получит юзер ошибку — ну и ладно, значит бог его все равно не любит; а если не увидит документ то дадим ему кнопку Обновить. По 1-ой проблеме еще наверно можно как-то по websocket подписываться на апдейты и подтягивать автоматически, чтобы не заставлять обновлять самостоятельно; еще я слышал о людях которые добавляли к получаемому от бека списку фиктивные строки для только что созданных документов, но при запросах по одной странице — если пагинация используется — это будет конфликтовать с сортировкой, которая по идее проводится на бэке, ведь неясно на какую страницу должна попасть эта фиктивная строка.
Еще я читал про read own writes консистентность и про monotonic read консистентность, они бы позволили решить эти проблемы (монотонность решила бы хотя бы 2-ую). Но как их подружить с системой, которая изначально их сама не поддерживает (тот же эластик например), я не представляю. Вот например для read-own-writes в одной статье предлагали PouchDB применять как локальное хранилище для копии вносимых изменений, но если есть такой кэш, какие должны быть правила eviction для него? До каких пор держать в нем наши изменения? И что если сессии пользователя — не sticky, и следующий запрос его может прийти на другой инстанс приложения — уже в другой pouchdb? Или даже если они sticky например, но использовавшийся в последний раз инстанс — отвалился? Тут по идее надо распределенный кэш тогда вместо pouchdb — но опять возникают вопросы, ведь такой кэш тоже должен быть AP системой (как и сам эластик ну или там кассандра) и потому при переключении клиента на другую ноду может оказаться, что там в этот момент еще не самое свежее состояние сессии. Бида короче =) А, ну еще наверно можно было бы на стороне клиента держать кэш вместо этого, но там опять непонятно как настроить eviction так, чтоб кэш не разрастался безгранично.
Как прикрутить к эластику monotonic read consistency, если у него нет глобального понятия "версия всех данных", я тоже не понимаю.
Короче, какое бы решение я ни рассматривал, ко всякому вроде бы можно придумать такой сценарий, при котором клиент может не увидеть только что внесенные им изменения. Или то видеть их, то не видеть.
Slicer