Снижение производительности SharePoint при увеличении уникальных Security Scopes на больших списках

в 8:31, , рубрики: .net, microsoft, sharepoint, Блог компании EastBanc Technologies, метки: ,

Всем привет!

В этой статье мы решили поделиться своими жизненными наблюдениями за проблемой производительности больших списков в SharePoint.

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

Сначала немного терминологии:

ACL (Access Control List) – упорядоченный список принципалов, которые определяют права на элемент или группу элементов.

Security Scopes – набор пар групп или пользователь + ACL.

Рекомендации Microsoft

Microsoft рекомендует соблюдать достаточно простые правила: избегать количества одновременных Security Scopes более 5 000 на одну библиотеку документов или на один список.

Почему так? Откуда взялось ограничение? Для начала ответим на вопрос, каким образом MS SharePoint обрабатывает запрос к списку.

  1. Делает обращение к БД содержимого и читает:
    a. Метаданные списка, т.е. определение списков полей и т.п.
    b. Computed fields, определения обработчиков событий и много чего еще.
    c. Все scope списка (точнее представления).
  2. На стороне front-end определяет: в scope попадает пользователь.
  3. Вытаскивает уже непосредственно данные.

Такому подходу есть объяснения, и связаны они с поддержкой модели внешних поставщиков членства и ролей в первую очередь (AD, т.е. AD является наиболее широко распространенным поставщиком членства и ролей).

На практике можно видеть, что проблемы начинаются уже с 1000 элементов с уникальными правами.

С помощью этих SQL-запросов можно посчитать, сколько сейчас у вас Security Scopes:

SELECT [SiteId], [ScopeId], [RoleDefWebId], [WebId], [ScopeUrl], [Acl]   
FROM [your Content DB].[dbo].[Perms]   order by scopeurl  

An even better query exposes the web URL

SELECT [fullurl],perms.[SiteId] , perms.[ScopeId], [RoleDefWebId], [WebId], [ScopeUrl], [Acl]   
FROM [dbo].[Perms],[dbo].allwebs   
where perms.WebId = allwebs.id
order by scopeurl

As an aside, you can see the number of security principals per scope, using this SQL:

select COUNT(ra.PrincipalId) as [Count],p.ScopeUrl from RoleAssignment ra with(nolock) 
join Perms p with(nolock) 
on p.SiteId = ra.SiteId and p.ScopeId = ra.ScopeId 
group by p.ScopeUrl 
order by p.ScopeUrl desc

Как Microsoft предлагает решать проблему:

  1. Использовать папки для инкапсуляции прав доступа на группы элементов с похожими правами.
  2. Разбивать на разные списки или библиотеки документов и использовать наследованные права.
  3. Никогда не выходить за лимит 5 000 уникальных права на листе.

К чему приводит нарушение этих рекомендаций:

  1. Снижение производительности на 20% на каждые 1 000 уникальных прав на листе.
  2. Программные ошибки при попытках разорвать права на элементе и выдать уникальные.

Для решений на базе MS SharePoint критически важно, чтобы ферма держала нагрузку, и вот почему.

Для разработчика нет поддержки транзакций. И наборы операций вида (т.е. если создать элемент, разорвать права, выдать на него права в MS SharePoint):

 var item = list.AddItem(...);
                    // ...
                    item.Update();
                    item.BreakRoleInheritance(false);
                    item.RoleAssignments.Add(new SPRoleAssignment(...));

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

Понятно, что рекомендации 2 и 4 носят более камерный характер и не решают задачу хранения элементов вместе и уникальных прав, поэтому остановимся на первом как самом действенном способе – использование папок.

Наш пример

Для примера возьмем список из реально работающей системы, в которой на текущий момент 132 073 элементов:

Снижение производительности SharePoint при увеличении уникальных Security Scopes на больших списках

В ней 3 590 Security Scopes – выглядит примерно вот так:

Снижение производительности SharePoint при увеличении уникальных Security Scopes на больших списках

Внутри списка 721 папка...:

Снижение производительности SharePoint при увеличении уникальных Security Scopes на больших списках

… на которые выданы права следующим образом:

Снижение производительности SharePoint при увеличении уникальных Security Scopes на больших списках

По данным Google Analytics, среднее время загрузки страницы менее секунды — при уровне посещений именно этого списка за этот период порядка 968 в день, в рабочее время.

Снижение производительности SharePoint при увеличении уникальных Security Scopes на больших списках

Наш подход

В соответствии с нашим подходом права раздаются вот так:

  public static void ProcessItem(SPListItem item, SPFolder folder)
        {
            var file = item.Web.GetFile(item.UniqueId);
            // Внимание не используйте item.File т.к. он во многих случаях будет null
            // http://msdn.microsoft.com/ru-ru/library/microsoft.sharepoint.splistitem.file.aspx            
            file.MoveTo(string.Format("{0}/{1}", folder.Url, item[SPBuiltInFieldId.LinkFilename]));            
        }  

Также хочется добавить, что если наборы прав различаются не разрешениями на чтение видимости, а возможностью изменения, можно использовать Event Handler, который будет запрещать изменения.

 class PermissionEventHandler : SPItemEventReceiver
    {
        public override void  ItemUpdating(SPItemEventProperties properties)
        {
            var updatingAllowed = CheckUserHasPermission(properties.Web.CurrentUser, properties.ListItem);
            // определить может ли пользователь изменять элемент
            if (!updatingAllowed)
            {
                properties.Cancel = true;
                properties.ErrorMessage = "Access denied";
            }               
        }

        public override void ItemAdding(SPItemEventProperties properties)
        {
            //...
        }      
        //...
    }

До изобретения этого подхода нам пришлось в течение 5 лет плотно заниматься SharePoint, съесть немало собак и кактусов. У него есть свои нюансы, но он абсолютно точно работает — опробовано уже на двух порталах.

Как всегда, рады были поделиться опытом!

Автор: eastbanctech

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js