Переход в хранилище данных, вероятно, будет более дорогим, чем использование memcache. Иначе memcache не был бы таким уж полезным: -)
Я бы порекомендовал первый вариант.
Если у вас разумный уровень запросов, вы можете реализовать его еще проще:
1) update the value in memcache
2) if the returned updated value is evenly divisible by N
2.1) add N to the datastore counter
2.2) decrement memcache by N
Предполагается, что вы можете установить достаточно длительный тайм-аут в своей кэше памяти, чтобы он жил между последовательными событиями, но если события настолько редки, что время вашей памяти кэша истекло, скорее всего, вам не понадобится счетчик "высокого параллелизма": -)
Для больших сайтов, использование одного кэша памяти для выполнения таких операций, как подсчет общего количества просмотров страниц, может привести к проблемам; в этом случае вы действительно хотите разделить свои кэши памяти и обновить случайный экземпляр счетчика; агрегация счетчиков произойдет при обновлении базы данных.
При использовании memcache, однако, имейте в виду, что некоторые клиентские API предполагают, что тайм-аут в одну секунду означает, что значение отсутствует. Если пакет TCP SYN для экземпляра memcache будет отброшен, это означает, что ваш запрос ошибочно предположит, что данных там нет. (Подобные проблемы могут возникнуть с UDP для memcache)