37
Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации Русанов Петр LinguaLeo http://lingualeo.com

CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Embed Size (px)

DESCRIPTION

http://2013.codefest.ru/doklad/60

Citation preview

Page 1: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Есть ли жизнь в оффлайне?Кеш, транзакционный лог и проблемы синхронизацииРусанов ПетрLinguaLeohttp://lingualeo.com

Page 2: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Зачем нам оффлайн если интернет есть везде?

Page 3: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

В городах полно Wi-Fi спотов

Page 4: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

На улице есть 3G

Page 5: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Интернет есть даже в транспорте

Page 6: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

И в самых неожиданных местах

• На Северном полюсе

• На вершине горы Эверест

• В пустынях ОАЭ

• На МКС

Page 7: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Вроде бы все прекрасно, все счастливы и можно

не париться

Page 8: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

К сожалению, реальность такова:• 3G доступен только в больших городах, покрытие не 100%

• 3G не везде безлимитный, порой очень дорогой

• В роуминге цены на 3G достигают безумных цифр

• Интернет в самолетах стоит примерно ~$20 за 10 Mб, средняя скорость ~0.05 Мбит/сек

• В метро связь доступна только на станциях и то не на всех

• Даже домашний интернет могут отключить, если забыл оплатить :)

Page 9: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

История из жизни

Page 10: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Лечу в Новосибирск на CodeFest

Page 11: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Лететь долго, занятьсянечем

Выучу пожалуй пару фраз на испанском

Page 12: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации
Page 13: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

WHUUUT??

Page 14: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Итого

• Пользователю все равно: находится он в онлайне или нет, доступна сейчас сеть или пропала

• Пользователи расстраиваются если приложение перестает функционировать в отсутствии интернета

• При дальних перелетах/поездках/в метро у людей полно свободного времени, но нет интернета — это НУЖНО использовать, особенно в образовательных приложениях, где львиную долю функций можно реализовать без необходиомости постоянного доступа к сети

Page 15: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Есть решение!

• Кеширование медиа-файлов

• Хранение всех пользовательских данных в локальной БД

• Сохранение действий пользователя, произведенных в оффлайне

• Синхронизация с сервером при появлении доступа к сети

Page 16: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Кеширование

Page 17: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Кеши бывают разные

Требования

1. Возможность хранения данных не только в памяти, но и на диске

2. Поддержка политик (изменяемое поведение для разных типов запросов)

3. Строгое следование заголовкам HTTP, обозначающим правила кеширования и перевалидации (Cache-Control, Expires, Last-Modified)

4. Возможность отправки conditional GET

HTTP code: 200Age: 0Via: 1.1 varnishX-Varnish: 1103200550Accept-Ranges: bytes, bytesLast-Modified: Tue, 11 Sep 2012 14:01:07 GMTContent-Type: audio/mpegConnection: keep-aliveExpires: Tue, 26 Mar 2013 18:32:41 GMTServer: nginx/1.2.7Content-Length: 4752Date: Tue, 19 Mar 2013 18:32:41 GMTCache-Control: max-age=604800

Page 18: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Что кешировать?

• НЕ нужно кешировать всё - долго и занимает много места на диске

• Данные, без которых оффлайн работа будет невозможна

• Опциональные наборы данных лучше кешировать по запросу пользователя

Page 19: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Политики кеширования

•Политика определяет поведение при наличии закешированных данных и при ошибке

•Оффлайн режим для разработчика по сути представляет собой выполнение всех запросов с ошибкой

•Для запросов данных, которые предполагается кешировать для оффлайн работы, важно указать именно политику при ошибке (напр. в ASIHTTPRequest для iOS это ASIFallbackToCacheIfLoadFailsCachePolicy)

•В оффлайне лучше показать устаревшие данные, чем ошибку

Page 20: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Итого

• Выбираем правильную библиотеку для кеширования, соответствующую описанным требованиям

• Выставляем правильные политики для кешируемых запросов

• Реализуем выборочное кеширование и по запросу пользователя

Page 21: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Сохраняем историю действий пользователя

Page 22: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Я знаю, что вы сделали прошлым летом

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

Для этого нужно понятное, автоматизированное и прозрачное решение, которое не требует значительных изменений в коде

Page 23: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Не нужно изобретать велосипедМожно использовать принцип, аналогичный триггерам в транзакционных SQL или хукам в VCS (post commit):

Пользователь совершил действие

Изменился объект в БД

Произошел commit в базу

Сработал post-commit

hook

Изменение сохранилось в лог

Page 24: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

• Доступ к данным осуществляется исключительно через Data Access Objects (DAO), полностью инкапсулирующих в себе работу с БД

• Через proxy-классы перехватываются методы DAO для добавления/удаления/изменения объектов и устанавливаются transaction listener-ы в качестве post-commit хуков (триггеров)

• Сразу после коммита в БД вызываются transaction listener-ы и сохраняют изменения в БД в виде записей транзакционного лога, содержащие тип операции (добавление/удаление/изменение), таймштамп, сам измененный объект и вспомогательные данные

• Взаимоисключающие и дополняющие операции объединяются для компактности данных

Реализация: как это сделано в LinguaLeo

Page 25: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Реализация: DAO и вложенные транзакцииВ каждом объекте DAO имеется экземпляр объекта транзакции

В основе объекта транзакции лежит счетчик открытых и закрытых транзакций (аналогично счетчику ссылок retainCount у NSObject в Objective-C)

При выполнении [transaction begin] счетчик увеличивается

При выполнении [transaction commit] счетчик уменьшается

Как только счетчик стал равен нулю, выполняется реальный commit в базу данных и сразу после выполняется метод didCommitTransaction у всех transaction listener-ов

Page 26: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Пример: transaction listener и DAO@implementation LLLoggingOfAddingBonusTransactionListener

- (void)didCommittedTransaction { LLTransactionLogRecord *record = [LLTransactionLogRecord bonusLog]; record.operation = @(LLOperationTypeInsert); record.loggedEntity = self.bonus; [self.transactionLogDAO insertRecord:record];}

@end

@protocol LLQuestDAO <LLDAO>

- (void)deleteAllBonuses;- (NSArray *)bonusesForType:(LLQuestType)type;- (void)insertBonus:(LLBonus *)bonus;- (void)udpateBonus:(LLBonus *)bonus;

- (LLQuest *)currentQuestStateForType:(LLQuestType)type;- (void)updateCurrentQuestState:(LLQuest *)questState forType:(LLQuestType)type;

@end

Page 27: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Пример: proxy-класс для DAO@implementation LLAOPLoggingDAOProxy

+ (id)newProxyForWordDAO:(id <LLWordDAO>)wordDAO { id result = [[[LLAOPLoggingDAOProxy alloc] initWithInstance:wordDAO] autorelease]; [result interceptMethodEndForSelector:@selector(insertWordsToUserDictionary:) interceptorSelector:@selector(logAddingNewWords:)]; [result interceptMethodEndForSelector:@selector(insertWordsFromGlossaryToUserDictionary:) interceptorSelector:@selector(logAddingNewWordFromSimpleWords:)]; [result interceptMethodStartForSelector:@selector(updateWord:) interceptorSelector:@selector(logUpdatingWord:)]; [result interceptMethodStartForSelector:@selector(updateWords:) interceptorSelector:@selector(logUpdatingWords:)]; [result interceptMethodStartForSelector:@selector(deleteWordsFromUserDictionary:) interceptorSelector:@selector(logDeletingWords:)]; [result interceptMethodStartForSelector:@selector(updateSimpleWords:asKnown:) interceptorSelector:@selector(logUpdatingSimpleWord:)];

return result;}

@end

Page 28: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Пример: транзакционный логВ итоге лог выглядит примерно так:[

{

'data': { ... },//поля объекта класса LLBonus

'entity_type':1,//тип сущности (LLBonus)

'operation':0,//тип операции (0 - вставка, 1 - обновление, 2 - удаление)

'timestamp':'2013-02-20T10:33:46+0200'//таймштамп

},

{

'data': { ... },

'entity_type':0,//LLWord

'operation':1,//обновить

'timestamp':'2013-02-21T11:25:40+0200'

}

...

]

Page 29: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Итого

• Всю работу с БД осуществляем в DAO

• Сохраняем все действия пользователя в лог не смотря на наличие/отсутствие сети

• Стараемся сделать лог компактным, объединяя записи

Page 30: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Синхронизация

Page 31: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Да будет сеть!Как только появляется доступ к сети, нужно синхронизовать данные с сервером:

• отправить на сервер сохраненные операции

• принять операции от сервера, совершенные на сайте и других устройствах

• данных могло накопиться много - нужно упаковать данные, чтобы синхронизация прошла быстро и не "съела" много траффика

Page 32: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Проблемы синхронизации У пользователя может быть несколько устройств

Какие-то из них могут находиться в оффлайне

В них будет накапливаться история операций на основе устаревших данных

При выходе этих устройств в сеть могут возникать конфликты

Page 33: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Ничего не напоминает?

Page 34: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Принцип VCS для синхронизации

Это самый обычный кейс для систем контроля версий вроде SVN или Git

Все решается вводом численного обозначения ревизии данных (или хеша), которое контролирует сервер

При синхронизации:

Если на устройстве устаревшая версия данных, сначала накатываются и мержатся изменения с сервера (svn up/git pull) и только затем делается аплоад накопившихся операций на сервер (svn commit/git push)

Page 35: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Синхронизация: схема VCS

rev 0

register

rev 0

login

rev 0

добавить ‘get up’ с переводом ‘вставать’

добавить ‘get up’ с переводом ‘дорожать’

syncpush

rev 1

syncpush

client revison is old!

syncpull

MERGEwithrev 1

syncpush

rev 2

syncpull

rev 2

обновить ‘get up’: перевод ‘дорожать’

rev 2

Page 36: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Итого

• Регулярно делаем синхронизацию, чтобы минимизировать объем отправляемых данных за раз

• Применяем методы синхронизации из систем контроля версий

• При неудачной синхронизации делаем rollback

Page 37: CodeFest 2013. Русанов П. — Есть ли жизнь в оффлайне? Кеш, транзакционный лог и проблемы синхронизации

Русанов Петр,LinguaLeo

http://lingualeo.com

[email protected]+7 (920) 0269579

я

Вопросы?