Cosmos DB заранее анонсировала общедоступность Gremlin (Graph API). Вероятно, к концу 2017 года он выйдет из предварительного просмотра, поэтому мы можем считать его достаточно стабильным для производства. Это подводит меня к следующему:
Мы разрабатываем систему с ориентировочной пользовательской базой до 100 миллионов пользователей. У каждого пользователя будет несколько документов в Cosmos для хранения пользовательских данных, эти документы разделены по идентификатору пользователя (Guid). Таким образом, когда оценки сбудутся, у нас будет не менее 100 миллионов разделов, каждый из которых будет содержать кучу документов.
Мы будем хранить не только пользовательские данные, но и взаимосвязанные данные (отношения) между пользователями. На бумаге Cosmos должен очень хорошо подходить для таких сценариев, используя его кросс-API с Document API для обычных данных и Graph API исключительно для отношений.
Примером одного из таких отношений является Follow. Например, UserX
может следовать UserY
. Чтобы реализовать эту взаимосвязь, мы создали запрос Gremlin, который создает Edge
:
g.V().hasId('{userX.Id}').has('pkey','{userX.Partition}')
.addE('follow').to(g.V().hasId('{userY.Id}').has('pkey','{userY.Partition}'))
Результирующий Edge
автоматически назначается разделу UserX
, потому что UserX
является выходной вершиной.
При запросе исходящих ребер (всех пользователей, за которыми следит UserX
) все в порядке, потому что запрос ограничен разделом для UserX
.
g.V().hasId('{userX.Id}').has('pkey','{userX.Partition}').outE('follow').inV()
Однако при инвертировании запроса (поиск всех последователей UserY
) при поиске входящих ребер ситуация меняется - насколько мне известно, это приведет к полному межраздельному запросу:
g.V().hasId('{userY.Id}').has('pkey','{userY.Partition}').inE('follow').outV()
На мой взгляд, полный межсекционный запрос со 100 миллионами разделов неприемлем.
Я попытался поместить Edge
между UserX
и UserY
внутри отдельного раздела, но API Graph не позволяет мне это сделать. (Изменить: Cosmos изменен на Graph API)
Теперь я подошел к реализации пары ребер между UserX
и UserY
, одного исходящего Edge
для UserX
и одного исходящего Edge
для UserY
, пытаясь сохранить их синхронизацию. Все это для того, чтобы оптимизировать скорость моих запросов, а также для того, чтобы внести больше работы для достижения конечной согласованности.
Опять же, мне интересно, действительно ли Graph API подходит для таких сценариев - или мне действительно чего-то здесь не хватает?