Главная SQL, Без рубрики, Новое SQL 2008 R2, Конкурс
  • Установка Microsoft SQL Server 2008 R2 в деталях

    logo_sql_server_2008R2 Здравствуйте. Сегодня я хочу написать статью, посвящённую такой неинтересной и казалось бы обычной вещи как установка “SQL Server”. Для тех кто ставит SQL Server в первый раз, или просто сомневается в выборе какой-то настройки по ходу процесса установки, эта статья станет прекрасным руководством. Вероятно, те кто уже хоть раз устанавливал сиквел, скажут “Зачем мне это? Я уже и так всё знаю, да и нечего там знать, но в статье я освещу и такие, необязательные но интересные атрибуты установки как Slipstream и файлы конфигурации, и искренне надеюсь, что кому-то это будет полезно. Итак с предисловием покончено, приступаем к делу.

  • Главная SQL, Без рубрики, Новое SQL, SQL 2008 R2, Конкурс
    • SQL Server 2008 R2 для многопроцессорных систем

      Вашему вниманию предлагается обзор современных возможностей SQL Server 2008 R2 по поддержке многопроцессорных серверных архитектур. Статья относится только к платформе Windows и затрагивает только те архитектурные особенности многопроцессорных систем, которые показались автору значимыми при развёртывании приложений баз данных SQL Server.
      Статья адресована опытным администраторам баз данных SQL Server, знакомым с архитектурой SQLOS и современными платформами Intel и AMD.

      Оглавление

      Введение

      До недавнего времени, наиболее распространённой архитектурой систем с большим числом физических процессоров являлась архитектура неоднородного доступа к памяти Non-Uniform Memory Architecture (NUMA). В основе этой архитектуры лежит такой способ организации доступа к оперативной памяти сервера, который зависит от её расположения (удалённости) по отношению к процессору. Внутренняя организация такой серверной архитектуры отличается от архитектуры SMP систем набором дополнительных компонент, которые обеспечивают взаимодействие процессорных блоков – узлов между собой. Говоря упрощённо, эти компоненты как бы связывают несколько обычных SMP серверов на одной или на нескольких материнских платах, обеспечивая обращения процессоров из одного узла к памяти на другом узле, если это оказывается необходимо.
      Сегодня мы с вами становимся свидетелями смены тенденции в развитии архитектур неоднородного доступа к памяти. Классические типы архитектур, которые запомнились, прежде всего, своей высокой стоимостью решений, заменяются близкими по смыслу, но построенными на более дешёвых компонентах, архитектурными решениями. Если сделать краткий экскурс в историю, то мы увидим, что долгое время наиболее распространённой была архитектура NUMA с обеспечением когерентности процессорных кэшей. Вам должна быть знакома аббревиатура ccNUMA. Существовало несколько протоколов и реализаций поддержки когерентности кэшей, некоторые из них были подробно описаны в работе: Архитектура S2MP – свежий взгляд на cc-NUMA. Если кратко, то суть сводится к тому, что изменение в кэше приводит к удалению копий данных из кэшей других процессоров, а информация о копиях хранится в виде битового вектора, в специальном “оглавлении”, которое иногда называют кэшем четвёртого уровня, который, по сути, является кэшем метаданных. Пример реализации и описание подобной архитектуры можно найти в статье: Архитектура серверов HP Superdome. Один из вариантов реализации архитектуры ссNUMA был предложен компанией Sequent, и получил название NUMA-Q (это ссNUMA с кводами). Компания была приобретена IBM, и развитие описываемых в статье технологий можно видеть в современных решениях этого вендора.
      В последние годы существенно возросло число физических ядер процессоров на один процессорный разъем – сокет (многоядерные процессоры). Существуют решения, например, IBM X-Architecture, которые позволяют ещё больше увеличить число процессорных ядер, что осуществляется за счёт объединения многоядерных SMP систем в блоки серверов. Такие серверные “бутерброды” способны по числу процессоров и по производительности конкурировать с традиционными NUMA системами. По сути, обычные шасси SMP серверов связываются между собой специальными межсоединениями. Многоядерность сама по себе уже вносит неоднородность в доступ к памяти. В случае же, когда несколько серверов с многоядерными процессорами объединяются в единый серверный блок (управляемый одной операционной системой или гипервизором), доступ процессорных ядер к оперативной памяти другого шасси носит ярко выраженный неоднородный характер. Всё это размывает разницу между классическими NUMA – системами и современными SMP-решениями. Некоторые вендоры даже называют построенную на SMP многопроцессорную архитектуру – NUMA-like Architecture.
      В современных массовых процессорных архитектурах тоже используется неоднородный доступ к памяти. Например, такая схема реализована для Intel QuickPath Integrated Memory Controller. Это решение отличается тем, что в нём отказались от архитектуры фронтальной шины. Вместе с процессорами на одном кристалле интегрирован контроллер памяти, посредством которых, по схеме точка – точка, подключаются модули оперативной памяти. Такое решение позволяет сгладить “застарелые” проблемы с поддержкой когерентности NUMA. Кроме того, за счёт применения дополнительных чипсетов (например, IBM eX5), удаётся с ущественно нарастить объём оперативной памяти, выделенной каждому процессорному ядру. Это позволяет очень сильно сократить трафик ввода-вывода через процессорные межсоединения. По сути, межсоединениям останется обслуживание только задач поддержки когерентности процессорных кэшей. О современных шинах межсоединений можно почитать в этих статьях: Intel QuickPath Interconnect и HyperTransport.
      Что же дальше? Очень похоже на то, что нелинейность доступа к ресурсам останется головной болью администраторов надолго. Появление таких массовых архитектурных решений, как решения на основе QPI, и их “творческое” воплощение разными вендорами способно породить большое разнообразие топологий NUMA. Но это ещё не всё. Сегодня появляются решения, в основе которых заложена парадигма обратной виртуализации. Очень может оказаться, что изложенные в настоящей статье рекомендации и методики окажутся непригодны для таких нетрадиционных решений. Остаётся надеяться, что таким технологиям, как ScaleMP, не покорятся горизонты платформы Windows, и мне не придётся дополнять эту статью главой о NUMAlink.
      Современные операционные системы уже немыслимы без поддержки NUMA. Эта поддержка обретает новые качественные улучшения от версии к версии. Так, например, в Windows 2003 была доработана поддержка NUMA в планировщике потоков и диспетчере памяти, а в Windows 2008 поддержка NUMA была добавлена в диспетчере запросов ввода-вывода и внесены усовершенствования в диспетчере памяти.
      Существует утилита, которая позволяет увидеть топологию NUMA вашего компьютера. Эта утилита создана Марком Русиновичем, и скачать её можно с сайта sysinternals.com Название утилиты: “Coreinfo“. Она позволяет получить данные о ядрах (параметр -c), о группах (параметр -g) и о NUMA – узлах (параметр -n).
      Последние версии SQL Server тоже оптимизированы для работы в архитектуре NUMA. Особенности работы SQL Server в NUMA и способы настройки для оптимальной работы NUMA c нагрузками SQL Server будут разобраны в этой статье, а также вашему вниманию будут предложены ссылки на материалы, которые помогут уточнить или углубить представленные в статье рекомендации и описания.
      Для успешного использования многопроцессорных платформ, системным администраторам и разработчикам приложений требуются дополнительные средства и меры, позволяющие влиять на распределение потоков между процессорами и закрепление за процессорами ресурсов сервера. Именно о таких мерах и средствах пойдёт речь в этой статье.

      К оглавлению

      Традиционная архитектура NUMA

      В этой статье речь идёт об особенностях работы SQL Server на платформе с архитектурой NUMA. Мы ограничимся в своём рассмотрении только теми компьютерами, на которые устанавливается версия операционной системы старше Windows 2000. Традиционной для использования с этой СУБД и ОС архитектурой NUMA являлась платформа на базе процессоров Intel Itanium. В этой главе вам будет представлен краткий обзор особенностей этой архитектуры. Долгие годы серверы масштаба предприятия строились именно на таких процессорах. В 2010 году было объявлено о выходе новой линейки процессоров Itanium, и в этом же году Корпорация Майкрософт объявила о прекращении поддержки этой платформы в своих новых версиях операционных систем, которые появятся после Windows Server 2008 R2.
      В традиционной архитектуре NUMA каждый процессорный NUMA – узел имеет локальную по отношению к нему память, доступ к которой процессоры узла осуществляют симметрично и с минимальными задержками. Процессоры работают с памятью через специализированный контроллер памяти, который имеется у каждого узла. Этот контроллер решает и другие задачи, к числу которых относится организация взаимодействия с устройствами ввода-вывода и доступ к памяти других NUMA – узлов компьютера. Для доступа к памяти других узлов контроллеры использует специальную шину, позволяющую процессорам использовать память других узлов. Память других узлов будет являться для них удалённой, и доступ к ней будет с большей задержкой, чем к локальной памяти. Неоднородность доступа в этой архитектуре главным образом относится к памяти, что является основным отличием этой многопроцессорной архитектуры от SMP, и именно такой метод доступа к памяти определяет её название. Задержки обращения к удалённой по отношению к узлу памяти могут иногда на порядок отличаться от задержек обращения к локальной памяти узла. Современные архитектуры серверов используют механизмы “горячих” страниц, которые позволяют отслеживать наиболее активно используемые NUMA узлом участки удалённой по отношению к нему памяти и переносить располагаемые там данные в локальную память.
      Кроме локальной памяти, каждый NUMA узел может иметь собственный канал ввода-вывода. Это позволяет соотносить NUMA узлы портам ввода-вывода и локализовать на этом узле только те задачи, которые поступили по предписанным узлам портам.
      В качестве шины поддержки когерентности кэшей часто используются специализированные коммутаторы, которые позволяют масштабировать подключения контроллеров памяти. Контроллер памяти может иметь несколько портов, которые выделенной шиной подключаются к отдельным коммутаторам масштабируемости. Ещё одной задачей таких коммутаторов является обеспечение подключения контроллеров памяти к концентраторам ввода-вывода. Концентратор ввода-вывода через мосты подключается к дисковым устройствам ввода-вывода, а также другим, унаследованным устройствам ввода-вывода.
      Основной целью NUMA является масштабируемость. Традиционно, наиболее сложными для масштабируемости являются массовые сетевые запросы. Основным недостатком NUMA – систем является их более высокая стоимость относительно традиционных SMP систем. Кроме того, сервера построенные не на платформе Itanium (NUMA-like системы) по числу ядер уже вплотную подобрались к традиционным NUMA системам. Ну и самой плохой новостью является уже упомянутый отказ Майкрософт поддерживать в будущих версиях семейство процессоров Intel Itanium.
      Дополнительную информацию о неоднородном доступе к памяти можно найти в электронной документации Microsoft SQL Server Books Online: “Основные сведения о неоднородном доступе к памяти“.

      К оглавлению

      Особенности NUMA-like архитектур

      Появление архитектуры NUMA-like обусловлено желанием масштабирования недорогих SMP серверов. Выглядит NUMA-like как многоядерный блок из нескольких шасси серверных SMP систем. В NUMA-like неоднородным становится не только доступ к памяти, но и дисковый ввод-вывод, сетевой ввод-вывод, доступ к устройствам на шинах PCI или USB. Такие устройства, как гибкие магнитные диски и приводы CD-ROM могут выборочно отключаться, поскольку классическая архитектура персонального компьютера не предусматривает наличие этих устройств на нескольких шинах.
      Когда мы имеем дело с одним шасси сервера, процессоры могут обращаться ко всей его памяти, ко всем присутствующим шинам и адаптерам ввода-вывода. Разницы в производительности у процессоров при работе с памятью практически не будет. Всё меняется, когда шасси соединяются с помощью кабеля/разъёма масштабируемости. В этом случае, та память, шины и адаптеры ввода-вывода, которые будут с процессорами на одном шасси, позволят получать наибольшую операционную производительность. Аналогичные же устройства во втором шасси будут работать с процессорами первого шасси с издержками, которые могут оказаться весьма значительными. Кроме этих издержек, на производительность системы в целом могут повлиять и другие факторы, косвенно или напрямую зависящие от использования схемы с несколькими шасси.
      В отличие от традиционной архитектуры NUMA, для которой выпускались специальные версии ОС и СУБД, архитектурные решения NUMA-like становятся чувствительны к выбору платформы, версий и редакций. Неверный выбор редакции или настроек операционной системы может породить проблемы. Например, возможна неверная оценка лицензий при учёте процессорных ядер, вследствие чего система будет неверно представлять прикладному уровню группировку ядер физических процессоров (сокетов). Неудачные реализации или настройки BIOS, а также драйверов устройств, тоже могут породить проблемы для определения точной топологии ресурсов соединённых межсоединениями серверов. Ещё одним возможным источником проблем могут стать неадаптированные к подобной схеме прикладные программы. Причиной деградации производительности таких программ может стать неправильная нагрузка на несколько шасси, приводящая к большому трафику по межсоединениям. Нужно очень тщательно подходить к планированию таких систем. Тут нет мелочей. Как уже отмечалось, даже выбор редакции операционной системы может сказаться на возможностях и производительности системы. Наиболее полный набор возможностей для многопроцессорных систем имеет редакция Datacenter. Проконсультируйтесь у вендора по поводу планируемой конфигурации и выбору версий и редакций её компонент.
      В NUMA-like системе физическая память каждого из подключённых в одну систему серверов объединяется в единое, последовательное адресное пространство. С точки зрения организации доступа к памяти, это очень похоже на традиционную архитектуру NUMA. Физическая память каждого из серверов будет ближе к процессорным ядрам этого же сервера, чем к ядрам процессоров других SMP – серверов. Топология узла NUMA-like может включать в один узел все процессоры, относящиеся к одному шасси. Изменить такое формирование узлов позволяет только настройка Soft-NUMA, о которой речь пойдёт ниже.
      У NUMA-like обращение к памяти другого сервера подвержено существенным задержкам, точно так же, как это было в традиционной архитектуре NUMA. Это необходимо учитывать при планировании нагрузки системы. Нужно учитывать и увеличение времени ожидания в процессорных очередях. Как ни странно, но численное увеличение числа ядер провоцирует увеличение числа передач контекста пользовательских запросов с одного сервера на другой. Это увеличивает затраты на исполнение запроса, но делает лучше параллелизм.
      Более сложными становятся протоколы работы ядер с локальным кэшем. Например, в стандартном для SMP протоколе MESI (Modified. Exclusive. Shared. Invalid), используемом для определения актуальности состояния находящегося в кэше контекста, могут появиться дополнительные типы состояний. Обработка новых состояний тоже потребует дополнительных ресурсов. Да и сами размеры кэшей должны быть существенно больше, что обусловлено необходимостью снижения нагрузки на фронтальную шину FSB, если речь идёт о старых платформах Intel. Впрочем, одноранговые межпроцессорные соединения тоже не упрощают и не удешевляют такие решения.
      Ещё одним отличием от традиционной NUMA является то, что соединяющие шасси серверов шины масштабируемости будут обслуживать не только задачи доступа к удалённой памяти. Межсоединения могут взять на себя ещё и задачи ввода-вывода с устройств, подключаемых по шинам PCI или USB. Такое произойдёт, если запросы ввода-вывода будут направлены с одного шасси на другое. В общем случае, для того, чтобы производительность не страдала от архитектурных особенностей NUMA-like, требуется добиться исполнения следующих трёх условий:

      1. Частота обращений к удаленной памяти должна оставаться существенно ниже, чем к локальной памяти шасси. Тут стоит стремиться к отношению 20% к 80%.
      2. Задержки удаленного доступа должны быть незначительны, т.е. они должны отличаться от задержек обращения к локальной памяти не больше чем в 10 раз.
      3. Пропускная способность межсоединения должна в идеале быть больше, чем та, которая требуется для SQL Server.

      Бывают случаи, когда использовать возможности NUMA мешают другие аппаратные возможности. Например, у некоторых многопроцессорных серверов на базе процессоров AMD в BIOS может быть включена опция “Node memory interleave”, которая фактически перетасовывает адресное пространство разных узлов и делает невозможным использование возможностей NUMA. Для обеспечения поддержки NUMA эта опция должна быть заблокирована.

      К оглавлению

      Поддержка NUMA в операционной системе

      Поддержка NUMA реализована в Windows Server 2003/2003R2/2008/2008R2 Enterprise Edition и Datacenter Edition. Для того чтобы операционная система могла задействовать предоставляемые NUMA и NUMA-like возможности, ей должно быть передано с аппаратного уровня описание физической топологии системы. Для этого задействуется специальный интерфейс расширений конфигурации, который определяет спецификацию передаваемой операционной системе таблицы статической привязки ресурсов – Static Resource Affinity Table (SRAT). Если на сервере запущено несколько операционных систем, таблица ресурсов будет включать только выделенные каждой системе ресурсы. Таблица привязки ресурсов может изменяться, при добавлении новых ресурсов, например “горячей” памяти, или вследствие физического изъятия ресурсов.
      Во время запуска операционной системы для каждого узла NUMA формируется граф стоимости доступа ядер процессоров к ресурсам. Оценка стоимости основана на величине задержки запросов на доступ к памяти. Подсистема обслуживания листания памяти в Windows Server дополняется новым типом реакции на события доступа к странице памяти – “soft page fault”. В отличие от “hard page fault”, который показывал, что страницу нужно забрать с диска, этот новый признак говорит о том, что искомая страница находится на дальнем узле.
      В спецификацию входит понятие доменов близости, которое позволяет объединить локальные ресурсы с точки зрения NUMA-узла в одну, прикреплённую к этому узлу логическую группу. Операционная система использует информацию из таблицы привязки ресурсов для того, чтобы выбрать используемую по умолчанию привязку процессора, процессов и потоков. Механизм доменов близости позволяет системе преимущественно планировать потоки одного процесса на процессоры одного и того же узла NUMA. Кроме того, система старается распределять для такого процесса локальную по отношению к выбранному узлу память. Таким образом система старается минимизировать дорогостоящие обращения процессоров одного узла к ресурсам других узлов. Каждый новый процесс будет планироваться на следующий по порядку NUMA узел.
      Алгоритм работы с ближней и дальней памятью развивается вместе с появлением новых версий Windows. Мы затронем только те особенности, которые присутствовали в Windows 2003 и проследим некоторые изменения и улучшения этих алгоритмов в последующих версиях.
      Для управления памятью система создаёт видимые и скрытые пулы для каждого домена близости, которые сопоставляются узлам NUMA. Аналогичным образом распределяется и расширенная для процесса память, доступная через окно трансляции адресов AWE. После первоначального выделения участков памяти для каждого из узлов, система не может динамически перераспределять для нужд приложения уже выделенные участки локальной по отношению к узлу памяти. В Windows 2003 это приводило к тому, что распределение памяти происходило за счёт ресурсов других узлов. Такое наблюдалось в тех случаях, когда поток, которому уже была выделена локальная память, нуждался в дополнительном распределении памяти, и такое распределение уже не возможно было сделать из локальных ресурсов NUMA-узла. Вследствие такого поведения, увеличивались задержки доступа к памяти, поскольку память являлась удалённой по отношению к работающему с ней процессору. Работа с удалённой памятью приводила к снижению производительности за счёт увеличения времени доступа примерно на 100ns. Фактически, по некоторым оценкам, стоимость доступа к удалённой памяти оказывается от 40% до – 300% больше, чем стоимость доступа к локальной памяти. Хотя эта стоимость существенно ниже стоимости доступа к физическим дискам. SQL Server очень часто используется в таких приложениях, которым свойственно большое число потоков. В этом случае, память должна делиться между большим числом потоков или процессов. Операционная система не способна самостоятельно оптимально распределить память, потоки и процессы. Это приводит к тому, что сервер баз данных на системе NUMA будет страдать от частого обращения к удаленным страницам памяти. Ещё одной проблемой становилась такая ситуация, когда процесс короткое время работал на неоптимальном по удалению от памяти узле, мог получать дальнейшее распределения памяти на этом же, неоптимальном узле. Такое распределение тоже снижало эффективность выполняемых операций.
      В Windows Server 2003 необходимо особое внимание уделить настройке параметров устройств ввода-вывода и управляющего ими программного обеспечения. Это обусловлено тем, что в этой операционной системе возможности обслуживания ввода – вывода с учётом специфики NUMA были реализованы ещё не в полной мере. Если подсистема ввода – вывода постоянно взаимодействует с одним и тем же NUMA – узлом, снижение нагрузки на дисковую подсистему может быть достигнуто за счёт использования механизмов прямого доступа к памяти – DMA. Если же NUMA – узел должен взаимодействовать с внешней дисковой подсистемой, которая подключена к серверу посредством нескольких адаптеров, схема в вода – вывода будет многоканальной. Это потребует такой настройки программного уровня поддержки ввода – вывода, которая обеспечит обслуживание запросов на ввод – вывод по каждому каналу на тех узлах, которые располагают необходимыми для этих запросов ресурсами. В такой конфигурации прямой доступ к памяти не будет разделяться между несколькими узлами. В операционной системе реализованы возможности оптимизации многоканального ввода – вывода для многопроцессорных систем, но эти возможности должны быть предусмотрены производителем внешней дисковой подсистемы, который должен обеспечить необходимую поддержку для программного уровня.
      Дисковая подсистема пока ещё является одним из ключевых компонентов производительности. Поскольку NUMA-like узел потенциально может иметь прямой доступ к дисковому вводу-выводу, операционная система может получить преимущество, обслуживая прерываниями локальных для узла устройств на локальных процессорах. В Windows Server 2003, операционная система умела получать топологию NUMA, но это ограничивалось получением числа узлов и памяти в каждом из узлов. В следующих версиях ситуация стала существенно лучше.

      К оглавлению

      Windows 2008 и NUMA

      В Windows Server 2008 алгоритмы распределения памяти были существенно доработаны и улучшены. Операционная система теперь старается распределять память на идеальном с точки зрения близости узле. Этот выбор будет сделан даже в том случае, если процесс начал выполняться на узле неоптимальном с точки зрения близости ресурсов. Если у оптимального узла нет свободной памяти, по таблице SRAT будет выбран наиболее близкий к идеалу узел. Такая политика распределения ресурсов повышает вероятность того, что процесс и его ресурсы будут обслуживаться на одном и том же узле или будет выбрана наиболее оптимальная альтернатива. Наверное, самым важным преимуществом Windows Server 2008 по отношению к Windows Server 2003 в поддержке NUMA является то, как оптимально они управляют близостью ресурсов. Улучшения планировщика в этом направлении позволили заметно оптимизировать размещение ресурсов в узлах NUMA.
      Имеющиеся в операционной системе программные интерфейсы позволяют получать информацию о топологии NUMA из прикладных программ. Кроме того, через эти интерфейсы разработчики могут управлять привязкой задач к NUMA узлам. Приложения Windows могут получать информацию о NUMA через специализированный программный интерфейс (API). Вот несколько доступных для этого функций:

      • GetNumaHighestNodeNumber – возвращает число узлов;
      • GetNumaProcessorNode – возвращает номер узла данного процессора;
      • GetNumaNodeProcessorMask – возвращает бинарную маску процессоров данного узла;
      • GetNumaAvailableMemoryNode – возвращает размер доступной узлу памяти.

      Приложения, адаптированные для использования возможностей предоставляемых интерфейсами NUMA , могут в полной мере воспользоваться масштабируемостью современных архитектур, и демонстрировать высокие показатели производительности. К таким приложениям относится SQL Server. Используя упомянутые выше API, высокопроизводительные приложения могут самостоятельно задавать или изменять привязку потоков к процессорам, чтобы они использовали ресурсы домена близости одного узла. Это особенно полезно, когда потоки сильно зависимы от одних и тех же структур памяти. Адаптированные приложения могут создавать множество потоков, и для этих потоков разработчики приложений смогут использовать возможности оптимизации распределений неоднородной памяти. За счёт этого, адаптированные приложения будут более эффективны в системах с числом процессоров более четырёх, и повышение числа процессоров будет позитивно сказываться на общей производительности.
      В Windows 2008 добавилась возможность получения не только топологии процессоров, но и ввода-вывода. Например, можно узнать, на каких шасси NUMA-like системы размещены адаптеры шины (HBA). Имея такую расширенную информацию, можно заметно оптимизировать использование процессоров, настраивая привязку прерываний устройств к ближним процессорам. Это позволяет оптимизировать использование процессоров для обслуживания запросов ввода-вывода. Можно привязать обслуживающие ввод-вывод прерывания к наиболее оптимальным для производительной работы процессорам. В Windows 2003 ввод-вывод мог обслуживаться не тем процессором, который инициировал ввод-вывод. Таким образом данные могли попадать в память не того узла, через который к ним был получен доступ. Поэтому Windows 2008 старается обслуживать ввод-вывод и процедуры отложенного вызова (DPC) на процессорах того узла, где они были инициированы.
      Кроме того, в Windows Server 2008 появился новый способ управления прерываниями. В Windows Server 2003 использовались прерывания в виде строки. Прерывание инициировалось устройством, путём подачи электрического сигнала на нужном штырьке (строка прерывания). Такая схема сильно затрудняла привязку нужного процессора к заданному устройству. В Windows Server 2008 устройство генерирует прерывание в виде сообщения, записывая значения данных по специальному адресу. С помощью MSI можно менять приоритет прерывания и для обслуживания прерываний стало возможно указывать конкретные процессоры. Мало того, если система оснащена PCI шиной с поддержкой расширения стандарта MSI-X, управлять обслуживанием прерываний ввода-вывода можно на уровне драйверов устройств. Делается это через специализированные программные интерфейсы Windows 2008. Т.о. прерывание ввода-вывода может быть сразу привязано к тому процессору, который инициировал этот ввод-вывод. Получить дополнительную информацию о поддержке NUMA операционной системой и специализированных функциях можно на сайте Майкрософт, в статье: “NUMA Support“.
      Диспетчер памяти операционной системы Windows 2008 при размещении невыгружаемого пула, т.е. тех участков оперативной памяти, которые распределяются для ядра и драйверов, учитывает топологию NUMA узлов. Он старается распределять их так, чтобы эти участки памяти выделялись на том NUMA-узле, на котором было инициировано это выделение памяти. Так, например, в случае возникновения необходимости распределения новой страницы PTE (таблица распределения страниц), она окажется на том узле, который инициировал распределение, а не на любом узле, как это было в Windows 2003.
      В Windows 2008 диспетчер памяти всегда пытается распределять память потоку из пула наиболее подходящего узла, даже если поток в это время обслуживается другим узлом. Если же на идеальном узле недостаточно памяти, диспетчер проанализирует задержки доступа к другим процессорам и узлам, и на основании полученной информации выберет для распределения тот узел, задержки к которому меньше всего. Кроме того, если поток переходит в состояние ожидания доступа к данным или коду, диспетчер памяти переместит соответствующие страницы в список ожидания наиболее удачного для этого потока NUMA-узла.
      Операционная система Windows Server 2008 выбирает оптимальный процессор на основе приоритетов, и если идеальный процессор недоступен, поток планируется на ближайшем к идеальному процессоре локального узла. Если все процессоры локального узла недоступны, операционная система планирует поток на самом ближнем к локальному узлу процессоре. Такая привязка потока к неоптимальному процессору называется мягкой. Привязку потока к процессору можно сделать жёсткой, чтобы впоследствии этот поток не мог быть привязан к другому NUMA узлу. В случае мягкой или жёсткой привязки, операционная система не может просигнализировать приложению, чтобы оно самостоятельно изменило привязку потока. Кроме того, операционная система не сможет самостоятельно перемещать данные из локальной памяти одного узла в локальную память другого узла. Такое перемещение можно осуществить из приложения. Кроме этого, данные могут быть перемещены естественным путём, за счёт механизма листания, который позволяет выгружать давно неиспользуемые страницы данных и по мере необходимости распределять их снова. В последнем случае высока вероятность того, что данные после повторного распределения окажутся в локальной памяти того узла, к которому относится запрашивающий данные поток.
      Хотелось бы обратить внимание на то, что вполне вероятна ситуация, когда поток привязан к одному из процессоров NUMA узла, и ему необходимо выполнить распределение памяти, но для этого ему недостаточно локальной памяти этого узла. Важно понимать, что у администратора нет возможности повлиять на распределение памяти в рамках этого узла, и воспрепятствовать распределению потоку дальней по отношению к его узлу памяти. Только в самом приложении, за счёт использования соответствующих программных интерфейсов операционной системы, можно препятствовать тому, чтобы для потока кэшировалась дальняя память. Однако, при таком подходе велика вероятность того, что не занятая приложением дальняя память может быть помечена, как свободная, и будет задействована для других нужд. Вендоры не отмечают каких-либо существенных отличий в адаптации операционной системы к NUMA-like системе, относительно традиционной NUMA. Может возникнуть необходимость в изменении привязки ввода-вывода SQL Server к процессорным ядрам. Например, IBM для своих серверов серии “System x” рекомендует устанавливать адаптеры ввода-вывода (HBA) равномерно распределив их по всем шасси (как вариант: по 2 в каждом шасси). Если адаптеры ввода-вывода устанавливаются не во все шасси, то с помощью параметра глобальной конфигурации сервера “affinity I/O mask” лучше настроить привязку ввода-вывода для ядер тех узлов, в домене близости которых расположены имеющиеся адаптеры, т.е. в тех шасси серверов, куда физически адаптеры были установлены. По поводу привязки сетевых интерфейсов из разных шасси инженеры из IBM рекомендуют при планировании использования для нужд SQL сервера нескольких IP-адресов (например, для балансировки нагрузки или для обеспечения гарантированной производительности передачи данных пользователей и серверов приложений), и привязывать эти адреса к разным NUMA-узлам. Если планируется использовать только один IP-адрес, то никакой привязки делать не надо.

      К оглавлению

      Windows 2008 R2 и NUMA

      Начиная с Windows Server 2008 R2 добавлена возможность работы сервера с числом процессорных ядер больше 64-х. Это изменение напрямую повлияло на поддержку операционной системой многопроцессорных архитектур NUMA и non-NUMA. Наиболее заметным новшеством стало добавление ещё одной сущности – групп процессорных узлов. Если процессорных ядер больше 64 – число групп становится больше одной. По существу, с помощью механизма групп разделяются зоны планирования потоков, концентрируя в каждой группе возможности предыдущей версии Windows Server 2008. Это означает, что процесс может работать с несколькими группами одновременно, а поток может исполняться только в рамках одной группы. Кроме того, прерывание может вызываться только для процессоров той же группы. В рамках одной группы работа драйверов и приложений происходит точно так же, как это было в системах, где число процессоров не превышало 64. Это позволяет сохранить обратную совместимость для приложений, которые не были рассчитаны на работу с числом процессоров больше 64. Кроме этого, с помощью групп можно локализовать те аппаратные компоненты, работа которых зависит от места запуска связанных с ними программ, что может положительно сказаться на работе таких программно-аппаратных комплексов.
      Каждая группа представляется статическим набором ядер, число которых не превышает 64. В Windows Server 2008 R2 администратору не предоставлено возможности влиять на формирование групп. Принадлежность ядер группе устанавливается во время начальной загрузки Windows, и каждое процессорное ядро может включаться только в одну группу. Операционная система старается минимизировать число групп. Кроме того, все логические процессоры ядра, и все ядра одного физического процессора тоже помещаются в одну и ту же группу. В одной и той же группе оказываются те процессоры, которые физически близки друг к другу. Группа может содержать процессоры одного или нескольких узлов архитектуры NUMA. Если в одном узле ядер больше 64-х, этот узел может быть поделён между несколькими группами. Если сервер non-NUMA, формирование групп основано только на ограничении в 64 ядра, а ядра по группам распределяются равномерно. Концепция групп процессорных ядер допускает горячее добавление процессоров. Если в системе есть сокеты, куда можно будет добавить процессоры, это будет учтено при создании групп, чтобы горячее добавление процессоров не привело к нарушению уже изложенных выше принципов формирования групп.
      Каждый процесс или порождённые им процессы могут быть привязаны к неограниченному числу групп, однако в каждый момент времени одиночный процесс может принадлежать только одной группе. Разработчики операционной системы старались обеспечить наилучшую производительность приложений, потоки которых обслуживаются в одной группе (прежде всего, в целях поддержки унаследованных приложений). Кроме того, выбор процессорной группы для приложения может быть обусловлен близостью к тем аппаратным компонентам, к которым приложение обращается. Если приложение явно распределяет свои потоки по нескольким группам, потери производительности не произойдёт только при условии, что работа потоков из разных групп независима, например, приложение умеет выделять независимые секции данных для этих потоков. Иначе, производительность может оказаться существенно ниже варианта с обслуживанием потоков в одной группе.
      В прежних версиях Windows, процесс или поток могли быть привязаны к указанному процессору, что гарантировало их исполнение на этом процессоре. В Windows Server 2008 R2 это стало немного сложнее, добавилась концепция групп. Вначале процессы не распределяются последовательно между процессорами групп. Процесс начинает исполняться в рамках только одной группы. Первый поток процесса будет исполняться в той группе, которую ему назначила Windows, если это не изменить из приложения (такая возможность существует и реализуется посредством интерфейсов). Каждый новый поток будет по умолчанию назначен в ту же группу, где обслуживается создавший его поток. Однако, при создании потока, приложение может определить группу, на которую он назначен.
      В начале, все потоки процесса создаются в одной группе. Получить назначение в несколько групп может только системный процесс во время запуска системы. Все другие процессы должны быть явно назначены в несколько групп. Это им нужно для того, чтобы использовать все присутствующие в системе процессоры. Т.о. процесс может разрастись, и его потоки будут присутствовать во всех группах, но каждый поток единовременно может исполняться только в одной группе, хотя и может потом сменить её на другую. Смена группы потока отдаётся на откуп приложению, которое будет ответственно за привязку потока к правильной группе, считается, что разработчик может сделать это лучше. Если ничего не предпринимать, то каждое приложение будет удерживаться в рамках одной группы.
      Системный пул потоков тоже был доработан и поддерживает теперь привязанную к узлу очередь. Это означает, что Windows будет планировать задачи из очереди узла для потоков этого узла. Если процесс в этом узле недоступен, Windows гарантирует, что задача будет обслужена в той же группе, из которой она попала в очередь. Такой механизм облегчает сохранение близости задачи приложения к её ресурсам. Однако есть несколько документированных исключений из последнего правила, которые выходят за рамки темы этой статьи.

      К оглавлению

      NUMA I/O

      Для настройки привязки прерываний устройств ввода-вывода к процессорам или узлам используется специализированный инструмент Майкрософт, который называется Interrupt-Affinity Policy Tool (IntPolicy). Привязка прерывания к одному процессору или группе в документации называется “Interrupt Affinity”. Ранее для аналогичных целей использовался Interrupt-Affinity Filter (IntFiltr). Для устройства ввода-вывода IntPolicy позволяет выбрать одну из политик доступности данного устройства или задать маску привязки процессоров. Но даже без такой искусственной привязки, Windows Server 2008 будет стараться обслуживать ввод-вывод на тех процессорах и распределять для него память того узла, который является локальным для этого устройства ввода-вывода. Всё это стало возможно из-за усовершенствования механизма прерываний в Windows Server 2008. Пример использования утилиты IntPolicy для привязки прерываний сетевых интерфейсов можно найти в статье Майкрософт: We Loaded 1TB in 30 Minutes with SSIS, and So Can You. Следует помнить, что неверный выбор привязки прерываний может привести к деградации производительности.
      Прерывание может применяться к процессорам только одной группы. В Windows Server 2008 R2 появилась возможность для PCI-адаптеров систем хранения динамически переадресовать прерывания и отложенные вызовы процедур. В документации эта функциональность названа соответственно: “Dynamic interrupt redirection” и “DPC redirection”, где DPC это аббревиатура: “Deferred Procedure Call”. Такой функционал получил название “NUMA I/O”. Задача NUMA I/O – помочь многопроцессорной системе лучше секционировать рабочую нагрузку, повысить норму удачного попадания в кэш, и высвободить встроенные аппаратные средства межсоединений от передачи большого трафика ввода-вывода.
      Windows Server 2008 R2 из коробки поддерживает работу сетевых адаптеров по протоколу Receive Side Scaling (RSS). Эта реализация RSS также адаптирована к NUMA. Данные из сетевых пакетов, которые посредством RSS распределяются между процессорами, будут обслуживаться теми же процессорными ядрами, которые обслуживают это TCP-подключение. Пакеты будут переданы на обслуживание физическим процессорам, без учёта гиперпоточности. Операционная система, балансируя средствами RSS входящие пакеты между процессорами, учитывает близость ресурсов узлов NUMA. Причём, при запуске адаптеры с более высокой пропускной способности получают больше процессоров, а несколько равноценных адаптеров поделят имеющиеся процессоры поровну. В системном реестре, в ветке “HKLM\system\CurrentControlSet\Control\class\{XXXXX72-XXX}\<номер сетевого адаптера>\”, можно найти несколько ключей, которые показывают закрепление процессоров за адаптерами:

      • RssBaseProcNumber – номер первого процессора из диапазона выделенных RSS адаптеру процессоров.
      • MaxRSSProcessors – максимальное число процессоров для этого адаптера.
      • NumaNodeID – NUMA узел на котором адаптер может распределять память.

      К оглавлению

      Hard-NUMA

      В SQL Server поддержка архитектуры NUMA появилась, в ограниченном виде, начиная с SQL Server 2000 SP4. После этого, разработчиками следующей версии SQL Server 2005 была проделана очень большая работа по совершенствованию механизмов взаимодействия с аппаратной платформой и операционной средой. Были выполнены необходимые доработки компонентов ядра сервера баз данных, для того чтобы обеспечить поддержку новшеств, появившихся в SQL Server 2005. Одной из первостепенных задач при разработке компонентов ядра было повышение масштабируемости сервера за счёт использования возможностей, заложенных в современные аппаратные платформы многопроцессорных серверов. В SQL Server 2005 поддержка NUMA была добавлена без каких-либо оговорок. Эта поддержка подразумевает, что планировщики непривилегированного режима (UMS) автоматически группируются точно так же, как группируются в NUMA узлы физические процессорные ядра. Необходимую для этого информацию получает специальный программный слой ядра сервера баз данный – SQLOS. Для этих целей используются описанные ранее программные интерфейсы операционной системы.
      Операционная система передаёт в SQL Server аппаратную конфигурацию NUMA, которую принято называть Hard-NUMA. SQL Server создает для каждого узла памяти свой логический планировщик, так, чтобы привязка планировщиков соответствовала аппаратной конфигурации. Изменить привязку планировщиков к ядрам процессоров можно с помощью системной хранимой процедуры sp_configure и параметра глобальной конфигурации сервера “affinity mask”. Впоследствии SQL Server старается удерживать планировщиков за своими узлами, если только какой-нибудь процессор не выйдет из строя или не будет отключен.
      Если с аппаратного уровня передаётся информация о наличии NUMA – системы, но в топологии присутствует всего один процессор, SQL Server поведёт себя так, как будто он имеет дело с компьютером без NUMA (Non-NUMA).
      Для администратора баз данных полезным является тот факт, что при запуске службы SQL Server обнаруженная конфигурация NUMA выводится в виде сообщения в журнал ошибок SQL Server. По этим сообщениям администратор может судить о том, какая конфигурация процессорных узлов используется сервером баз данных в настоящий момент.
      В случае с Hard-NUMA, при изменении параметра глобальной конфигурации “max server memory”, память для экземпляра SQL Server будет равномерно поделена между доступными ему узлами. SQLOS старается так распределить страницы буферного пула между узлами Hard-NUMA, чтобы потом потоки обращались к страницам буферного пула преимущественно в домене близости локального узла, а не из памяти удалённого узла. Однако возникает необходимость контроля равномерности распределения памяти между узлами. Во время отработки сигнала вытеснения памяти в системе с Hard-NUMA на процесс управления буферным пулом SQL Server будет влиять физическое расположение страниц памяти. Т.е. по сути, это повлияет на то, попадут ли страницы в домен близости данного узла. Однако если страница памяти оказалась вне домена близости узла, к которому относится работающий с ней поток, меры к перемещению страниц буферного пула в ближнюю память предприняты не будут. Если для работы SQL Server выделены не все процессоры, это означает, что при запуске будет предпринята попытка равномерного разделения буферного пула между всеми выделенными экземпляру процессорными узлами. Чтобы не допустить использование под буферный пул одного экземпляра всей оперативной памяти, необходимо задать максимальный размер используемой экземпляром памяти.
      Встроенный в SQL Server стабилизатор нагрузки может перемещать процессы от одного процессора к другому. Следуя логике доменов близости, привязка процесса подразумевает то, что он не будет перемещён на процессор, который относится к другому узлу, т.е. на процессор вне домена близости первоначального процессора.
      Когда сервер баз данных работает с Hard-NUMA, системный процесс отложенной записи (Lazy Writer) будет присутствовать в одном экземпляре на каждом процессорном узле. Сделано это для того, чтобы работа с памятью была локализована внутри домена близости каждого узла, а также это способствует сокращению числа страниц вне домена близости. Процесс отложенной записи будет вызываться для обслуживания каждой явной и неявной контрольной точки, поэтому работа на NUMA-системе приведёт к увеличению частоты появления контрольной точки.
      С помощью системной хранимой процедуры sp_configure можно на ходу менять привязку процессоров к экземпляру сервера баз данных. Т.о. можно отключить процессоры, процессорные узлы и обслуживающие их планировщики. В Hard-NUMA, пока хотя бы один планировщик активен, активным считается и весть NUMA узел. Узел может считаться отключенным, только если все приписанные к нему планировщики отключены. Используемая до этого узлом память будет высвобождена и перераспределена между другими узлами. Если перераспределение памяти нежелательно, необходимо соответствующим образом уменьшить максимальный размер выделяемой серверу памяти. Исполнители, которые работали с отключенным планировщиком, перейдут к активным планировщикам.
      Есть небольшая хитрость в том, к какому узлу в Hard-NUMA будут привязаны планировщики с самыми первыми идентификационными номерами. Дело в том, что SQL Server учитывает тот факт, что нулевой физический процессорный узел после запуска операционной системы будет загружен сильнее других, и у него будет меньше других свободной физической памяти. Поэтому, SQL Server перемещает узел по умолчанию с нулевого физического узла на другой узел, вследствие чего основные структуры данных для SQL Server будут обслуживаться на узле, который не так сильно обременён задачами операционной системы. Однако это не означает, что нулевому физическому процессорному узлу память SQL Server распределяться не будет, ему достанется примерно одна треть от нормы.

      К оглавлению

      SQLOS и NUMA

      Чтобы лучше понять базовые принципы дизайна и взаимодействия компонент SQLOS в многопроцессорной среде, давайте немного углубимся в архитектуру SQLOS. Узлы процессоров являются подмножеством узлов памяти. Для наглядности, этот факт проиллюстрирован на Рисунке 1. Более подробно о месте узлов памяти в архитектуре SQLOS можно узнать в серии переводов статей Славы Окс на сайте sql.ru: Архитектура SQL Server.

      SQLOSРисунок 1. Вариант упрощённой блок – схемы SQLOS

      Как видно из рисунка, основным элементом управления процессорными ресурсами является узел памяти SQLOS. Все процессорные ядра, попадающие в один узел NUMA, объединяются в узел процессора SQLOS, который сопоставляется с одним узлом памяти SQLOS. Т.о. производительность сервера может быть оптимальной, если приложение способно ограничиваться ресурсами одного узла памяти, либо оно физически так секционировано, что каждой секции данных достаточно одного узла памяти. Это достигается за счёт сбалансированной з агрузки доступных экземпляру сервера аппаратных и программных ресурсов. Однако даже если удастся оптимально секционировать нагрузку по процессорным узлам, останется возможность конфликтов за ресурсы памяти для ядер одного процессорного узла. Такие конфликты возможны, когда ядра разделяют в своей работе одну и ту же область оперативной памяти или общий кэш сокета.
      В идеале, нагрузка пользовательских приложений должна секционироваться по всем процессорам или узлам NUMA. В реальных условиях этого достичь очень трудно, особенно, если такое секционирование не было заложено на этапе первоначального дизайна приложения. Операционная система и сервер баз данных должны настраиваться таким образом, чтобы каждый поток попадал на отдельный процессор и на этом же процессоре должно обслуживаться прерывание отдельного сетевого интерфейса, а также порта обслуживания дискового ввода-вывода. Т.е. число сетевых плат и дисковых контроллеров (или HBA) должно равняться числу процессорных ядер, или хотя бы числу узлов NUMA. Продвинутые модели сетевых коммутаторов умеют поддерживать работу с множеством сетевых плат одного сервера. В качестве альтернативы большому числу сетевых плат можно использовать современные сетевые адаптеры, которые поддерживают Receive Side Scaling (RSS) и адаптированы для NUMA архитектур.
      В реальных системах достичь равномерного распределения нагрузки между ресурсами сервера оказывается очень сложно. Вероятность обращений к ресурсам вне домена близости процессора оказывается достаточно высокой. Однако прогресс не стоит на месте, и современные архитектурные решения позволяют существенно снизить потери от обращений к ресурсам других узлов. В первую очередь это относится к архитектурам, где процессор обращается к памяти посредством собственного контроллера, по схеме точка – точка, а не через общую шину. Чаще всего, приходится жертвовать оптимизацией загрузки узлов и ядер. Это обусловлено не только сложностью такой оптимизации, но и то, что потери на межузловых взаимодействиях с каждым годом становятся заметно меньше, а встроенные возможности операционных систем и адаптированных к NUMA приложений становятся всё лучше и лучше. Однако стоит помнить, что в резерве остаётся возможность повысить эффективность за счёт приближения распределения нагрузки между ресурсами сервера к идеалу.
      Некоторые структуры данных, такие как блокировки или планы исполнения запросов, были адаптированы к использованию на NUMA системах. Такие структуры контролируют своё местоположение и стараются оставаться на том же узле, где они были созданы. Например, блокировки связаны со структурами данных, которые используются для обслуживания транзакций. Если бы они не придерживались единого местоположения, это могло бы породить проблемы. К примеру, стала бы возможна ситуация, когда, несколько организованных координатором распределённых транзакций сеансов попадут для обслуживания на разные узлы. Получается, что один из сеансов должен будет завершить всю транзакцию и получить доступ ко всем структурам данных блокировок. Это приведёт к потерям производительности, поскольку структуры памяти блокировок рассредоточены по разным узлам. По той же самой причине контролирует своё местоположение и буферный пул, т.е. обслуживающие блокировки структуры памяти будут возвращены в тот список свободных буферов, который относится к тому узлу, который владеет выделяемой под структуры памятью.
      Посмотреть, сколько памяти распределено на каждом узле, можно с помощью команды DBCC MEMORYSTATUS. Описание этой команды можно найти в статье Базы Знаний Майкрософт: “How to use the DBCC MEMORYSTATUS command to monitor memory usage on SQL Server 2005“.
      Давайте рассмотрим особенности работы SQL Server со страницами памяти и буферами, которые для процессорного ядра считаются удалёнными, т.е. принадлежащими другому узлу процессора SQLOS. Буферный пул SQL Server может находиться в трёх состояниях. Вначале происходит инициализация буферного пула. Следующее состояние некого переходного периода, когда удалённые относительно локальных процессорных узлов буферы возвращаются операционной системе. После переходного периода наступает устойчивое состояние, когда положение буферов в пуле стабилизируется относительно узлов. Восьмикилобайтный буфер относительно узла может быть внешним или локальным. Число внешних буферов можно определить с помощью счётчика производительности: SQL Server: Buffer Node: Foreign pages. Он показывает число страниц, не относящихся к страницам памяти узла процессора SQLOS, т.е. распределённых узлу из дальней о тносительно узла памяти.
      В начальном состоянии буферный пул каждого узла увеличивается до достижения расчётного максимума. При этом SQL Server сортирует выделяемые узлу буферы по двум спискам. В лист свободных буферов попадают те буферы, которые в ближней к узлу памяти. Остальные буферы попадают в лист неблизких буферов. Чтобы сократить использование удалённой памяти, SQL Server не использует буферы из второго списка, Увидеть распределение буферов по разным типам можно с помощью команды DBCC MEMORYSTATUS. К сожалению, в административном динамическом представлении sys.dm_os_buffer_descriptors нет информации о том, какими являются буферы, внешними или локальными. После того, как число буферов достигнет требуемого значения, лист неблизких буферов сбрасывается. Буферы, попавшие в лист неблизких буферов, возвращаются системе. Пока этого не произойдёт, дальнейший “захват” памяти под буферный пул не выполняется. После сброса неблизких буферов, процесс повторяется. Когда буферный пул, после завершения переходной фазы, достигнет заданных величин, его состояние стабилизируется. Листы свободных буферов закрепляются за узлами окончательно, а лист неблизких буферов больше не используется. В таком состоянии, SQL Server пытается по возможности распределять местную память из листа свободных буферов. Если будет использована внешняя страница, это будет отражено в значениях представленного чуть выше счётчика Foreign pages. Т.е., несмотря на то, что SQL Server во время запуска пытается оптимизировать выделение буферов в соответствии с их близостью узлу, наличие внешних страниц не исключается. Мало того, все последующие распределения могут включать внешние страницы. Последующие сжатия и рост буферных пулов NUMA узлов также может приводить к увеличению числа внешних страниц. Для решения подобной проблемы, может оказаться полезным установить в параметрах глобальной конфигурации SQL Server одинаковых значений для максимального и минимального объёма оперативной памяти, выделяемой экземпляру сервера.
      Дополнительную информацию можно найти в статьях:

      Важно также помнить, что SQL Server использует для всех NUMA узлов один и тот же откомпилированный план исполнения запроса, но этот план базируется на использовании локальной памяти узла.
      Выделенное Административное Соединение (DAC) тоже зависит от того, используется ли NUMA система. SQL Server просто создает в одном из узлов планировщик и узел памяти, необходимые для DAC, и привязывает порт DAC к этому узлу. Дополнительную информацию о поддержке SQL Server архитектуры NUMA можно найти в электронной документации Microsoft SQL Server Books Online: “Как SQL Server поддерживает архитектуру NUMA“.

      К оглавлению

      Soft-NUMA

      В SQL Server 2005 появилась возможность создавать программные абстракции физических NUMA-узлов, которые могут переопределять число NUMA-узлов и процессорный состав узлов. Это предоставляет администратору баз данных возможность самостоятельно изменить порядок группировки процессоров, с учётом особенностей архитектуры сервера. Такие абстракции получили название Soft-NUMA. Создавать эти абстракции можно путём добавления специальных ключей в системный реестр операционной системы. Подразумевается, что в каждый такой узел может входить один или несколько процессоров.
      Soft-NUMA влияет на компоненты SQLOS, которые адаптированы к NUMA. Ели сервер и платформа поддерживают NUMA, то для расщепления узлов Hard-NUMA можно использовать узлы Soft-NUMA. С помощью узлов Soft-NUMA можно перераспределить планировщики и привязать к узлам порты сетевых интерфейсов. Soft-NUMA позволяет вносить изменения только в работу планировщиков и сетевых интерфейсов SQL Server (то, что в англоязычной документации относится к I/O Completion Threads). Число и привязка узлов памяти остаётся неизменно. Это нужно учитывать, т.к. с помощью Soft-NUMA невозможно изменить привязку памяти к узлам Hard-NUMA. Кроме того, узлы Soft-NUMA не получают свой процесс отложенной записи, как это происходит с физическими узлами.
      Убедиться в том, что число потоков отложенной записи не превышает числа узлов Hard-NUMA, позволяет следующий сценарий:

        SELECT scheduler_id FROM sys.dm_os_workers AS w
        JOIN   sys.dm_os_schedulers AS s
        ON     w.scheduler_address = s.scheduler_address
        AND    w.last_wait_type LIKE '%LAZYWRITER%'

      Важным является также тот факт, что использование Soft-NUMA не изменяет поведение буферного пула (Buffer Pool Locality). Во время инициализации буферного пула происходит его распределение для Hard-NUMA или для Soft-NUMA. В случае с Soft-NUMA, получается, что память узла может резервироваться из локальной и условно удалённой относительно такого узла памяти. Расположение страниц памяти буферного пула не отслеживается, как это делается в Hard-NUMA. Т.е. возможна ситуация обращения к удалённой памяти, что потенциально может привести к снижению производительности. С другой стороны, удалённая для Soft-NUMA узла память может оказаться (и, скорее всего, окажется) локальной для узла Hard-NUMA. Как было описано выше, сервер старается минимизировать работу с удалёнными страницами, что способствует их высвобождению. А поскольку новые страницы распределяются с приоритетом у локальной по отношению к узлу памяти, ситуация с большим количеством страниц в удалённой памяти может постепенно улучшаться.
      Если по каким – либо причинам нежелательно разделение буферного пула между узлами Hard-NUMA, есть возможность изменить это поведение. Заставить SQL Server работать со всей памятью, выделенной под буферный пул, как с единственным узлом памяти (плоский доступ), можно включив флаг трассировки 8015, который отключает поддержку NUMA в SQL Server. Подробности о таком режиме использования буферного пула можно найти в статье: How It Works: Soft NUMA, I/O Completion Thread, Lazy Writer Workers and Memory Nodes.
      По сути, наиболее важными возможностями Soft-NUMA являются две вещи. С помощью Soft-NUMA можно жёстко задать какие процессорные ядра будут задействованы для обслуживания запроса, направленного на заданный порт сетевого интерфейса. Это будет относиться только к пакетам TDS, и не будет касаться активности базы данных и журналирования этих операций. Каждый узел Soft-NUMA может иметь ассоциированный с ним порт сетевого ввода-вывода. В соответствии с выбранными настройками сетевого протокола, такие порты могут прослушиваться на разных сетевых интерфейсах, что позволяет балансировать не только процессоры, но и сетевой трафик, используя для этого сегментацию локальной сети. Т.е. запросы клиентов будут утилизировать те процессоры, Soft-NUMA узел которых привязан к указанному клиентом порту в строке подключения. Вторая возможность, это увеличение с помощью Soft-NUMA числа потоков завершения ввода-вывода (I/O Completion), о чём пойдёт речь ниже.
      Soft-NUMA узлы можно создавать и для систем с обычной архитектурой симметричного доступа процессоров к памяти (SMP). Например, для Non-NUMA серверов, которые оборудованы многоядерными процессорами, характерно совместное, конкурентное использование кэшей второго и/или третьего уровней. Узлы Soft-NUMA можно определять на основе близости процессоров к таким кэшам. В этом случае за счёт объединения в один узел нескольких процессорных ядер оптимизируется использование ими кэша третьего или второго уровня. Также это позволяет частично балансировать загрузку процессоров, распараллеливая рабочую нагрузку среди процессоров Soft-NUMA узла. К слову, можно отметить, что некоторые возможности балансирования нагрузки между процессорами присутствовали и в предшествующих SQL Server 2005 версиях. К таким возможностям можно было отнести: параметры глобальной конфигурации “max degree of parallelism” и “cost threshold for parallelism”, подсказку оптимизатору MAXDOP, опцию сервера и запроса – “query governor cost limit”, а также методы, подобные описанным в книге Кена Хендерсона “Профессиональное руководство по SQL Server: хранимые процедуры, XML, HTML”, и реализованных в виде расширенной хранимой процедуры xp_setpriority.
      В случае серверов Non-NUMA, наиболее значительный эффект Soft-NUMA может дать для оптимизации ввода-вывода. Кроме уже упомянутого выше выигрыша от оптимизации за счёт снижения конкурентного доступа к кэшу третьего или второго уровня, дополнительный выигрыш можно получить за счёт увеличения числа потоков ввода-вывода. Увеличение числа потоков происходит потому, что для каждого Soft-NUMA узла будет создан свой поток завершения ввода-вывода. В Non-NUMA сервере существует только один узел с точки зрения NUMA. Современные многоядерные процессоры способны содержать до шести и больше ядер. Т.о. потенциально можно увеличить число потоков ввода-вывода во столько раз, сколько ядер размещено на одном кристалле процессора.
      Получить информацию о процессорах и Soft-NUMA узлах, которые доступны SQL Server, можно с помощью специального динамического административного представления (Dynamic Management Views), вызвать которое можно так:

        SELECT * FROM sys.dm_os_schedulers;
        GO

      Это динамическое представление выводит по одной строке для каждого присутствующего в системе планировщика. Каждый планировщик закреплён за одним из процессоров. Представление позволяет диагностировать состояние планировщиков и определять меру их активности, для чего в представлении присутствует множество полей со счётчиками разнообразных событий планировщиков. Принадлежность планировщика к NUMA узлу можно определить по полю parent_node_id, а по полю cpu_id можно определить привязку к процессору. Значение равное 255 в последнем из этих двух полей говорит о том, что планировщик не привязан ни к одному из присутствующих в системе процессоров. Другие поля позволяют определить статус планировщика, т.е. является ли он активным или скрытым, поле is_online позволяет определить используется ли данный планировщик, поле current_workers_count позволяет определить, сколько исполнителей обслуживается этим планировщиком. Более подробную информацию об этом динамическом системном представлении можно получить в комплекте электронных материалов SQL Server 2008 Books Online, поставляемых с дистрибутивом. Ознакомьтесь со статьёй “sys.dm_os_schedulers (Transact-SQL)“.
      Для того чтобы проверить, обеспечена ли аппаратная или программная поддержка архитектуры NUMA (Hard-NUMA или Soft-NUMA) можно воспользоваться сценарием из блога Славы Окс (blogs.msdn.com/b/slavao), одного из разработчиков подсистем SQLOS:

        SELECT CASE COUNT(DISTINCT parent_node_id)
        WHEN 1 THEN 'Поддержка NUMA отключена'
        ELSE 'Поддержка NUMA включена'
        END
        FROM   sys.dm_os_schedulers
        WHERE  arent_node_id <> 32

      Существует ряд ограничений на количество и состав входящих в Soft-NUMA узел процессоров. Эти ограничения зависят от архитектуры сервера и числа процессоров, входящих в аппаратный NUMA – узел. Так, для SMP архитектуры, нельзя допускать, чтобы один и тот же физический процессор входил в состав более одного Soft-NUMA узла. В архитектуре NUMA нельзя включать в один Soft-NUMA узел процессоры из разных NUMA узлов.
      Описание Soft-NUMA узла создаётся вручную в системном реестре операционной системы. Для размещения конфигураций узлов необходимо создать специальный раздел:

        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration]

      В этом разделе создаются по одному подразделу для каждого Soft-NUMA узла, и эти подразделы должны называться Node0, Node1, Node2 и т.д. Например:

        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node0]

      В каждом разделе создаётся ключ-параметр с названием CPUMask, например:

        "CPUMask"=dword:00000002

      Последний пример задаёт шестнадцатеричное значение маски второго физического процессора. Значения маски процессоров устанавливается точно так же, как это делалось для глобального параметра конфигурации SQL Server, известного как: Affinity Mask. Значение этого параметра является целым числом размером в 4 байта и может быть установлено в окне редактирования параметров системного реестра в режиме десятичных или шестнадцатеричных значений.
      Дополнительную информацию о том, как настраивать Soft-NUMA узлы, можно получить в электронной документации Microsoft SQL Server Books Online: “Как настроить сервер SQL Server на использование программной архитектуры NUMA“.
      После определения Soft-NUMA узлов, соответственно должен измениться и порядок закрепления планировщиков непривилегированного режима за этими узлами. Новый порядок закрепления планировщиков повлияет на порядок обслуживания этими планировщиками реальных, физических NUMA – узлов. Это может быть полезно, когда системное окружение SQL Server не позволяет равномерно распределить ресурсы узлам памяти и требуется внести коррективы, чтобы сделать такое распределение более равномерным. Администратор, определяя Soft-NUMA узлы, может постараться так перегруппировать процессорные узлы, чтобы сгладить возможные неравномерности распределения системой ресурсов между NUMA узлами.
      Для того чтобы было легче понять, какими средствами обладает администратор в случае необходимости переопределения процессорных узлов, давайте рассмотрим жизненный пример, который можно найти в отчётах по эталонному тесту TPC-C. Информацию об этом тесте можно почерпнуть на сайте tpc.org. Речь идёт о результате в некластерной группе, показанном на сервере HP Integrity Superdome. Результат был опубликован 7 июня 2005г. На этом сервере удалось получить 1082203 tpmC.
      Изучая полную версию отчёта, которую можно прочитать на странице краткого описания используемой в эталонном тесте аппаратно – программной конфигурации, можно понять как настраивалась Soft-NUMA. В отчёте легко обнаружить следующие дополнения, которые были внесены в системный реестр операционной системы тестируемого сервера, и которые показаны ниже:

        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node0]
        "CpuMask"=hex:0F,00,00,00,00,00,00,00
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node1]
        "CpuMask"=hex:F0,00,00,00,00,00,00,00
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node2]
        "CpuMask"=hex:00,0F,00,00,00,00,00,00
        * * *
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node13]
        "CpuMask"=hex:00,00,00,00,00,00,F0,00
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node14]
        "CpuMask"=hex:00,00,00,00,00,00,00,0F
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node15]
        "CpuMask"=hex:00,00,00,00,00,00,00,70
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node16]
        "CpuMask"=hex:00,00,00,00,00,00,00,80

      Звёздочками в представленном здесь фрагменте ключей системного реестра заменены ключи нескольких программных узлов, алгоритм создания которых можно легко понять, анализируя представленные в отрывке значения CpuMask.
      Суть этого решения сводится к тому, что операционная система в процессе загрузки, следуя внутреннему алгоритму очередности использования процессоров, планирует задачи начиная с первого процессора. Если для SQL Server поменять порядок очерёдности выбора процессоров на обратный, тогда SQL Server не будет нагружать во время своего запуска те же процессоры, которые нагружаются операционной системой. Следовательно, после запуска всех служб, процессорные узлы будут более сбалансированно распределять между собой ресурсы, и система быстрее придёт к равновесному их распределению. Для этого, Soft-NUMA узлы переопределяют в представленном выше примере реальные NUMA – узлы таким образом, чтобы последняя четвёрка процессоров последнего NUMA – узла стала первым Soft-NUMA узлом. Следуя этой логике, предпоследний реальный NUMA – узел переопределяется во второй Soft-NUMA узел и так далее, плоть до пятнадцатого узла.
      Определение пятнадцатого и шестнадцатого Soft-NUMA узлов немного отличается. Суть этих отличий в том, что первый процессор второго реального NUMA – узла выделен в отдельный программный узел и на этот узел средствами специального скрипта посылается задача исполнения контрольной точки для тестовой базы данных. Это требование определяется спецификой организации тестирования и реализацией, которая была избрана компанией Hewlett-Packard.
      Продемонстрированный Вам пример наглядно показывает, как с помощью абстракций процессорных узлов можно повлиять на распределение ресурсов между процессорами и выделить отдельные процессоры или их группы для решения отдельных задач или для обслуживания отдельных процессов, например, процесса контрольной точки.
      29 октября 2005 года компания HP представила ещё лучший результат, который был получен путём изменения схемы разбивки и перераспределения физических процессоров на узлы Soft-NUMA. Использовался сервер HP Integrity Superdome 64P c/s, на котором удалось получить 1231433 tpmC. Ниже представлены в сокращённом виде ключи системного реестра, определяющие конфигурацию программных узлов NUMA:

        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node0]
        "CpuMask"=hex:01
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node1]
        "CpuMask"=hex:02
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node2]
        "CpuMask"=hex:0c
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node3]
        "CpuMask"=hex:30
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node4]
        "CpuMask"=hex:c0
        * * *
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node32]
        "CpuMask"=hex:00,00,00,00,00,00,00,c0

      Как видно, за исключением первых двух узлов, один из которых был оставлен для контрольной точки, все остальные программные узлы включают в себя по два процессора, чему соответствуют маски 0с и 30. И, как и раньше, избрана реверсивная схема распределения процессоров по узлам. Т.е. SQL Server получает процессоры для своих задач в обратном порядке. Этот подход основан на дроблении NUMA узлов на узлы Soft-NUMA, которые содержат в два раза меньше логических процессоров, чем в начале. Это позволяет сделать распределение ресурсов узлам ещё более равномерным, чем в предыдущем примере, и не нарушает при этом доменов близости аппаратного уровня. Кроме того, такое решение позволяет удвоить число потоков завершения ввода-вывода.

      К оглавлению

      Soft-NUMA для Non-NUMA

      Кроме NUMA, сегодня существует ещё несколько архитектур, которые направлены на реализацию масштабируемых многопроцессорных решений. Большое распространение получают многоядерные процессоры и платформы, с числом процессорных сокетов более четырёх. Часто, многоядерный процессор содержит общий кэш для своих ядер, или на кристалле процессора размещаются другие, общие для всех ядер элементы, например, контроллеры памяти. Такая компоновка сокета тоже вносит неоднородности в доступе к ресурсам, но это не представляется системе, как NUMA архитектура. Т.е. система не получает таблицу SRAT. По сути, Soft-NUMA становится единственным инструментом администратора, позволяющим указать SQL Server на присутствующую неоднородность. Давайте посмотрим, как это делается, на примерах.
      22 ноября 2005г. сервер IBM eServer xSeries 460 16P c/s показал результат TPC-C равный 492307 tpmC. Сервер был оснащён двуядерными процессорами Intel Xeon Processor 7040 3.00GHz/2x2MB L2, каждое ядро которых использовало технологию гипертрейдинг. Таким образом, каждый физический процессор в операционной системе представлялся четырьмя логическими процессорами. Для того чтобы обозначить домены близости ресурсов каждого физического процессора, специалисты в IBM объединили четвёрки логических процессоров в Soft-NUMA узлы. Это позволяет учитывать реальное секционирование процессорных кэшей и оптимизировать число потоков завершения ввода-вывода.

        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node0]
        "CpuMask"=hex:00,00,00,00,00,00,00,0f
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node1]
        "CpuMask"=hex:00,00,00,00,00,00,00,f0
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node2]
        "CpuMask"=hex:00,00,00,00,00,00,0f,00
        * * *
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node13]
        "CpuMask"=hex:00,f0,00,00,00,00,00,00
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node14]
        "CpuMask"=hex:0f,00,00,00,00,00,00,00
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node15]
        "CpuMask"= hex:f0,00,00,00,00,00,00,00

      Когда SQL Server запущен на многопроцессорной конфигурации без NUMA, это практически единственный способ включить оптимизацию работы с неоднородными ресурсами, без которой работа сервера баз данных в подобной конфигурации могла бы быть неоптимальной и не учитывала бы аппаратные особенности сервера.
      Другой пример, это сервер Unisys ES7000 Enterprise Server (8P), на котором была установлена операционная система Microsoft Windows Server 2003, Datacenter x64 Edition и Microsoft SQL Server 2005 Enterprise x64 Edition. 22 февраля 2006г. На этом сервере был представлен результат TPC-C равный: 347854 tpmC. Сервер был оснащён восемью процессорами Intel® Dual-Core Xeon® Processor 7041 3.0GHz, 2x2MB Lvl 2 Cache. Каждый процессор, как и в предыдущем примере, имел по два ядра на кристалл, и каждое ядро работало в режиме гипертрейдинга. Таким образом, на восьми кристаллах было размещено шестнадцать процессоров, которые из-за включения режима гипертрейдинга были представлены в операционной системе, как тридцать два логических процессора.
      Для того чтобы сервер баз данных мог учитывать реальное секционирование процессорных кэшей, специалисты из Unisys создали представленную ниже топологию Soft-NUMA узлов, объединив в каждый узел по два процессорных кристалла, т.е. по четыре физических процессора или по восемь логических процессоров. Поскольку они посчитали достаточным число узлов равное четырём, можно привести полный набор соответствующих ключей реестра, которые были представлены в отчёте по тесту:

        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node0]
        "CPUMask"=dword:0xff
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node1]
        "CPUMask"=dword:0xff00
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node2]
        "CPUMask"=dword:0xff0000
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\90\NodeConfiguration\Node3]
        "CPUMask"=dword:0xff000000

      К оглавлению

      NUMA для большого числа процессоров

      До сих пор мы рассматривали примеры, в которых задействовалось сравнительно небольшое количество процессорных ядер. Однако с выходом Windows Server 2008 R2, возможности операционной системы по обслуживанию большого количества процессорных ядер и, соответственно, программных узлов значительно выросли. Есть некоторые особенности настройки Soft-NUMA для систем, число ядер которых превышает 32. С этими особенностями можно ознакомиться в статье блога “SQL Server SQLOS team“: How to configure Soft-NUMA on a system with > 32 processors?
      Следуя этим рекомендациям, например, для создания восьми soft-NUMA узлов на 48-ми процессорном сервере потребуется:

      1. Привязать процессоры:
          EXEC sp_configure 'show advanced options', 1
          RECONFIGURE
          GO
          EXEC sys.sp_configure N'affinity mask', N'-1'
          GO
          EXEC sys.sp_configure N'affinity64 mask', N'65535'
          GO
          RECONFIGURE WITH OVERRIDE
          GO
          EXEC sp_configure
          GO
          EXEC sp_configure 'show advanced options', 0
          RECONFIGURE
          GO
      2. Выполнить необходимые изменения в системном реестре:
          Windows Registry Editor Version 5.00
          [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration]
          [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node0]
          "CPUMask"=hex:00,00,00,00,00,fc,00,00
          [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node1]
          "CPUMask"=hex:00,00,00,00,f0,03,00,00
          [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node2]
          "CPUMask"=hex:00,00,00,c0,0f,00,00,00
          [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node3]
          "CPUMask"=hex:00,00,00,3f,00,00,00,00
          [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node4]
          "CPUMask"=hex:00,00,fc,00,00,00,00,00
          [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node5]
          "CPUMask"=hex:00,f0,03,00,00,00,00,00
          [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node6]
          "CPUMask"=hex:c0,0f,00,00,00,00,00,00
          [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\100\NodeConfiguration\Node7]
          "CPUMask"=hex:3f,00,00,00,00,00,00,00

      В этом примере выбрана реверсивная схема определения программных узлов, т.е. порядок логических узлов – обратный физическому порядку объединения ядер в процессорных сокетах. Есть одно отличие от рекомендаций в указанной только что статье. В статье рекомендуется использовать для ключей реестра тип QWORD, однако, мне удавалось добиться правильной работы узлов Soft-NUMA только при типе ключа: DWORD. Использование именно такого типа подтверждается и той информацией, которая следует далее, а также представлена в статье: “Как настроить сервер SQL Server на использование программной архитектуры NUMA“. Более подробный пример можно по настройке Soft-NUMA можно найти в статье: “Пример настройки Soft-NUMA“.
      В SQL Server 2008 R2 появились возможность работать с числом процессоров больше шестидесяти четырёх. Для этого в этой версии СУБД добавлено понятие группы soft-NUMA узлов. Вот как это выглядит в опубликованном 2 ноября 2009г. компанией UNISYS результате теста TPC-E, выдавшем с помощью сервера Unisys ES7000 Model 7600R Enterprise Server (16s) результат: 2012.77 tpsE. В этой конфигурации использовалось 16 шестиядерных процессоров Intel Hex-core Xeon X7460. 96 ядер были распределены по узлам и сгруппированы следующим образом:

        Windows Registry Editor Version 5.00
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration]
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node0]
        "CPUMask"=hex:3f,00,00,00,00,00,00,00
        "Group"=dword:00000000
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node1]
        "CPUMask"=hex:c0,0f,00,00,00,00,00,00
        "Group"=dword:00000000
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node2]
        "CPUMask"=hex:00,f0,03,00,00,00,00,00
        "Group"=dword:00000000
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node3]
        "CPUMask"=hex:00,00,fc,00,00,00,00,00
        "Group"=dword:00000000
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node4]
        "CPUMask"=hex:00,00,00,3f,00,00,00,00
        "Group"=dword:00000000
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node5]
        "CPUMask"=hex:00,00,00,c0,0f,00,00,00
        "Group"=dword:00000000
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node6]
        "CPUMask"=hex:00,00,00,00,f0,03,00,00
        "Group"=dword:00000000
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node7]
        "CPUMask"=hex:00,00,00,00,00,fc,00,00
        "Group"=dword:00000000
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node8]
        "CPUMask"=hex:3f,00,00,00,00,00,00,00
        "Group"=dword:00000001
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node9]
        "CPUMask"=hex:c0,0f,00,00,00,00,00,00
        "Group"=dword:00000001
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node10]
        "CPUMask"=hex:00,f0,03,00,00,00,00,00
        "Group"=dword:00000001
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node11]
        "CPUMask"=hex:00,00,fc,00,00,00,00,00
        "Group"=dword:00000001
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node12]
        "CPUMask"=hex:00,00,00,3f,00,00,00,00
        "Group"=dword:00000001
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node13]
        "CPUMask"=hex:00,00,00,c0,0f,00,00,00
        "Group"=dword:00000001
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node14]
        "CPUMask"=hex:00,00,00,00,f0,03,00,00
        "Group"=dword:00000001
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\105\NodeConfiguration\Node15]
        "CPUMask"=hex:00,00,00,00,00,fc,00,00
        "Group"=dword:00000001

      Тут мы видим две группы, в которых топология Soft-NUMA узлов повторяется.
      Есть некоторые особенности привязки процессоров, если число ядер сервера больше 64-х. Для настройки SQL Server становятся неприменимы такие параметры глобальной конфигурации, как: affinity mask и affinity mask 64, поскольку с их помощью можно привязать не больше 64-х логических процессоров. Вместо них в SQL Server 2008 R2 появилась новая опция команды настройки сервера: ALTER SERVER CONFIGURATION SET PROCESS AFFINITY. Она даёт возможность привязать потоки процесса SQL Server к заданным NUMA-узлам или процессорам. Это позволяет управлять тем, какие процессорные группы будут доступны для обслуживания потоков процесса SQL Server 2008 R2. Например, вот так можно ограничить работу только первыми 64-мя процессорами:

        ALTER SERVER CONFIGURATION SET PROCESS AFFINITY CPU=0 TO 63;

      В электронной документации к SQL Server рекомендуется включать автоматическую привязку, как это показано ниже:

        ALTER SERVER CONFIGURATION SET PROCESS AFFINITY AUTO

      Вместо логических процессоров можно привязывать сразу NUMA-узлы:

        ALTER SERVER CONFIGURATION SET PROCESS AFFINITY NUMANODE=8, 12

      Стоит отметить, что в SQL Server 2008 R2 Management Studio изменился интерфейс мастера свойств сервера. На закладке привязки процессоров и ввода-вывода процессоры теперь сгруппированы по NUMA-узлам. Причём, если сервер Non-NUMA, все процессоры группируются в одном NUMA-узле.
      Более подробную информацию о привязке большого числа процессоров можно получить в статье: “Рекомендации по использованию SQL Server на компьютерах, которые имеют более 64 ЦП“. О поддержке большого числа процессоров операционной системой написано в статье: “Supporting Systems That Have More Than 64 Processors“.

      К оглавлению

      Привязка портов сетевых интерфейсов к процессорам

      Для обслуживания клиентских сетевых запросов в SQL Server 2000 существовала возможность использования нескольких портов сетевых протоколов TCP/IP или VIA. Эти порты могли открываться на одной или нескольких сетевых платах, а также, транслироваться для прослушивания на прокси-сервере. По умолчанию, использовались порт TCP 1433 и порт UDP 1434. Также, существовала возможность динамического выделения портов экземплярам SQL Server.
      Начиная с SQL Server 2005, предлагается более гибкая система закрепления портов сетевых интерфейсов. Порты теперь можно закреплять за процессорами, выделенными для работы экземпляру SQL Server. Порты TCP/IP или VIA можно закрепить за Soft-NUMA узлами. Такая привязка процессорных узлов портам сетевых интерфейсов получила название NUMA affinity. Появление этой возможности позволяет административно балансировать сетевые запросы не только между процессорами разных экземпляров SQL Server, но и между процессорами одного экземпляра. Например, можно предоставить доступ к разным портам клиентам с разными типами запросов (отделить аналитические запросы от коротких транзакций). Этим можно снизить влияние продолжительных, тяжёлых запросов на запросы OLTP приложений.
      Можно привязать один порт сетевого интерфейса ко всем узлам Soft-NUMA. Такая привязка используется по умолчанию и подразумевает, что SQL Server будет сам балансировать сетевые запросы между программными узлами. При этом, если запрос принят для обслуживания каким-либо узлом и для его исполнения достаточно процессоров одного узла, он будет обслуживаться на нём до своего завершения, а процессоры других узлов задействованы не будут.
      Можно привязать каждому процессорному узлу свой, уникальный порт. Такая привязка позволяет обслуживать получаемые портом узла запросы рабочими потоками этого узла, что позволяет задействовать пары процессорный узел / порт для разных клиентских приложений. Это позволяет развести по разным узлам их рабочую нагрузку. В случае такой привязки портов к узлам, приложения получат возможность частично ограждать локальную память физических NUMA узлов и буферы доступа от использования другими приложениями, которые подключаются к серверу через другие порты. Кроме того, сбои в работе приложения или чрезмерная утилизация приложением процессоров не будет влиять на работу других приложений, которые работают с другими процессорами. Однако привязка портов подобным образом может породить перекосы в утилизации процессоров, входящих в разные Soft-NUMA узлы, а также, если какой-нибудь из узлов захватит большую часть физической памяти, другие узлы могут испытывать её нехватку. Это может привести к существенному падению производительности приложений, обслуживаемых через закреплённые за ним порты сетевых интерфейсов.
      Можно комбинировать оба представленных выше способа привязки портов к процессорным узлам (один порт ко всем узлам и индивидуальные порты узлов), а также можно привязать к одному программному узлу несколько портов. Разработчик приложения, зная какие порты к каким программным узлам привязаны, теперь может осмысленно выбирать место подключения для решения разных задач. Важным в этом выборе является то, что программные узлы, привязанные к выбираемому для каждой задачи порту, будут иметь горячий кэш именно для нужной приложению задачи, что может способствовать повышению производительности приложений.
      Для создания программной абстракции процессора или нескольких процессоров необходимо в системном реестре операционной системы создать специальный раздел, внутри которого определить ключи для каждой абстракции процессора или группы процессоров. Именно это было продемонстрировано в предыдущем разделе.
      Давайте рассмотрим на примере образец использования привязки портов к процессорным узлам. Этот вариант настройки можно было увидеть в подробном описание теста TPC-C, опубликованного компанией Hewlett-Packard 22 мая 2006г. Тест выполнялся на сервере HP ProLiant ML370 G5 SAS 3.0 GHz Dual Core, использовались Microsoft SQL Server 2005 Enterprise x64 Edition SP1 и Windows Server 2003 Enterprise x64 Edition SP1. У сервера было всего два процессорных сокета, и в каждом был двуядерный процессор. Компания HP решила определить два NUMA-узла и привязать к каждому из них по одному порту сетевого интерфейса.
      Давайте рассмотрим, как это выглядело в виде ключей системного реестра, подробное описание которого компания предоставила в отчёте. Первый, сокращённый пример ключа показывает, как к сетевому интерфейсу с адресом 130.168.211.101 привязывается порт 2000:

        HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IP1

        Value 2
        Name: TcpPort
        Type: REG_SZ
        Data: 2002

        Value 5
        Name: IpAddress
        Type: REG_SZ
        Data: 130.168.211.101

      Ко второму интерфейсу с адресом 130.120.211.100 был привязан порт 2001:

        HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IP2

        Value 2
        Name: TcpPort
        Type: REG_SZ
        Data: 2001

        Value 5
        Name: IpAddress
        Type: REG_SZ
        Data: 130.120.211.100

      Стандартный порт общения с SQL Server привязывался к адресу-заглушке 127.1:

        HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IP3

        Value 2
        Name: TcpPort
        Type: REG_SZ
        Data: 1433

        Value 5
        Name: IpAddress
        Type: REG_SZ
        Data: 127.0.0.1

      Следующий ключ системного реестра указывает привязку портов к существующим NUMA-узлам:

        HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IPAll

        Value 0
        Name: TcpPort
        Type: REG_SZ
        Data: 2001[0x1],2002[0x2]

      Такая привязка портов к процессорным узлам позволила очень простыми средствами балансировать нагрузку внешних клиентов между процессорами системы. Она позволяет более равномерно нагружать процессоры запросами от большого числа клиентов. В этом тесте, компания очень близко следовала рекомендациям из блога одного из разработчиков SQLOS Славы Окс, которые он изложил в статье: Тюнинг SQL Server 2005 для программной поддержки NUMA.
      Ещё один интересный пример можно найти в описании теста TPC компании IBM, который был опубликован 12 июня 2006г., и для которого использовались сервера IBM System x3950. Для восьми узлов в системном реестре было определено девять разных портов, а один порт – 1433 был привязан ко всем NUMA-узлам:

        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer\SuperSocketNetLib\Tcp\IPAll]

        "TcpPort"="1433,1434[4],1436[2],1438[1],1440[8],1442[16],1444[32],1446[64],1448[128],1450[256]"

      29 августа 2008г. компаний INSPUR Group был опубликован результат теста TPC-E, в котором использовалась система с сервером INSPUR NF520D2, использовавшая Microsoft SQL Server 2008 Enterprise x64 Edition на платформе Microsoft Windows Server 2008 Enterprise x64 Edition. В описании конфигурации можно обнаружить использование для указанных выше ключей системного реестра следующей привязки портов к четырём NUMA-узлам: 1433,2001[0x1],2002[0x2],2003[0x4],2004[0x8].
      И напоследок, давайте вернёмся к описанному в предыдущей главе результату UNISYS от 2 ноября 2009г. Вот какую привязку узлов к портам использовали они в TPC-E для SQL Server 2008 R2.

        Windows Registry Editor Version 5.00
        [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQLServer\SuperSocketNetLib\Tcp\IPAll]
        "TcpPort"="1401[0x1],1402[0x2],1403[0x4],1404[0x8],1405[0x10],1406[0x20],1407[0x40],1408[0x80],1409[0x100],1410[0x200],1411[0x400],1412[0x800],1413[0x1000],1414[0x2000],1415[0x4000],1416[0x8000],1433"
        "TcpDynamicPorts"=""
        "DisplayName"="Any IP Address"

      Чтобы убедиться, что порты сетевого интерфейса были успешно привязаны к процессорным узлам, можно открыть журнал ошибок SQL Server, в котором должны появиться строки, подобные этим:

        2010-03-23 16:37:16.57 Server Server is listening on [ 'any' <ipv4> 1433].
        2010-03-23 16:37:16.62 Server Server is listening on [ 'any' <ipv4> 2433].
        2010-03-23 16:37:16.62 Server SQL Network Interfaces initialized listeners on node 0 of a multi-node (NUMA) server configuration with node affinity mask 0x0000000000000001.
        This is an informational message only. No user action is required.
        2010-03-23 16:37:16.59 Server Server is listening on [ 'any' <ipv4> 3433].
        2010-03-23 16:37:16.59 Server SQL Network Interfaces initialized listeners on node 1of a multi-node (NUMA) server configuration with node affinity mask 0x0000000000000002.
        This is an informational message only. No user action is required.

      Привязка портов применима и для Non-NUMA серверов. При этом, правила, по которым нужно настраивать параметры глобальной конфигурации для SMP сервера с Soft-NUMA узлами фактически такие же, как в случае с неадаптированными к NUMA приложениями. Если целью является исключение передачи части рабочей нагрузки одного Soft-NUMA узла на другие узлы, то SQL Server должен иметь такую конфигурацию, которая не позволяла бы создавать больше потоков, чем количество процессоров, которое пределено для одного программного узла.
      Одним из полезных свойств описанного способа управления планированием нагрузки является возможность разнести на разные процессоры одного экземпляра SQL Server запросы от разных клиентов в сети. Это может дать заметный выигрыш в производительности экземпляра, если из-за негативного влияния нагрузок клиентов друг на друга нежелательно обслуживать их на одних и тех же ресурсах. Негативное влияние может проявляться в виде очень долгого использования процессора одним из потоков или конкуренцией исполняемых на одном узле потоков за локальные ресурсы узла. SQL Server предоставляет в распоряжение администратора средства управления планированием потоков. С помощью этих средств администратор может существенно снизить подобное негативное влияние потоков друг на друга.
      Кроме того, можно рекомендовать подобное управление планированием потоков для приложений, код которых недоступен для модификации собственными силами. Этот подход применим, если требуется балансировка порождаемой приложениями нагрузки в рамках одного экземпляра SQL Server, а возможности реализовать это на стороне клиента нет. Все изменения, которые потребуется внести администратору – это определить в системном реестре Soft-NUMA узлы. Потом нужно будет привязать к ним порты сетевых интерфейсов, создать необходимые псевдонимы, и прописать соответствующие строки подключения в конфигурации приложения. В итоге, используя новые возможности планирования потоков, можно выделить разные группы процессоров для разных клиентов. В разные группы попадут клиенты, которые посылают серверу “тяжёлые” аналитические запросы, и клиенты, которые посылают серверу короткие транзакции или выборки. Выполнив необходимые для этого настройки, можно минимизировать возможное негативное влияние таких разнотипных запросов к одной и той же базе данных.
      Сама возможность балансировки нагрузки между процессорами одного экземпляра SQL Server позволяет экономить лицензии. Отпадает необходимость в приобретении дополнительных серверных лицензий только для того, чтобы балансировать нагрузку между процессорами одного сервера. Теперь, в рамках одного экземпляра, можно выделять и закреплять ресурсы за разными группами приложений. В предыдущих версиях, до SQL Server 2005, это достигалось только за счёт установки дополнительных именованных экземпляров сервера баз данных, а потом, процессоры распределялись между установленными экземплярами (что можно было делать динамически или можно было задать в глобальной конфигурации экземпляров жёсткую привязку процессоров экземплярам). Впрочем, с появлением в SQL Server регулятора ресурсов такую возможность стоит использовать только применительно к версии SQL Server 2005.
      Дополнительную информацию о привязке портов сетевого интерфейса к узлам Soft-NUMA также можно получить в электронной документации Microsoft SQL Server Books Online: “Как сопоставить порты TCP/IP порт с узлами NUMA“. Другие сценарии привязки портов к процессорным узлам можно найти в статье: “Сценарии NUMA“.

      К оглавлению

      Максимальный уровень параллелизма

      Само по себе разделение ресурсов по узлам NUMA ещё не гарантирует, что каждый отдельный запрос будет ограничиваться ресурсами только одного узла. Вполне возможна ситуация, когда в силу хороших возможностей для распараллеливания запроса, он может исполняться на процессорах нескольких NUMA узлов. Т.е. если для сервера будет существовать возможность создания такого числа потоков, которое превышает число ядер выбранного для запроса узла, то нагрузка будет размещена и на процессоры, которые не входят в число процессоров выбранного процессорного узла. Механизмы планирования задач операционной системы и SQL Server устроены так, что планирование потоков не привязывается жёстко к схеме процессорных узлов. Если в системе есть свободные процессоры, и не наложено никаких ограничений на число обслуживающих запрос потоков, то нет препятствий задействовать столько процессоров, сколько доступно для экземпляра SQL Server. Это поведение одинаково относительно Soft-NUMA или NUMA-узлов.
      Если запрос распараллеливается на число ядер, превышающие число ядер в одном узле NUMA, это может стать причиной обращений к ресурсам из домена близости соседних узлов. Чтобы исключить такие проявления, можно ограничить уровень параллелизма на уровне запроса (используя подсказку оптимизатору) или на уровне сервера, задав отличное от нуля значение параметру глобальной конфигурации сервера: max degree of parallelism.
      Пример использования ограничений параллелизма для локализации запроса в рамках одного узла представлен в статье: “Пример настройки Soft-NUMA“.
      В большинстве случаев, особенности реализации архитектур NUMA-like заставляют искусственно ограничивать параллелизм до числа потоков, не превышающего числа ядер одного шасси, или даже одного сокета. Однако некоторые нагрузки, характерные для задач обслуживания SQL Server, потенциально получают большой выигрыш от распараллеливания. Очень часто, хорошо распараллеливаемые задачи обслуживаются сервером одновременно с задачами, которым выгодна меньшая степень параллелизма. Если максимальная степень параллелизма не ограничена, может оказаться, что такие задачи, как например построение индексов, могут исполняться на процессорах из нескольких шасси. В таком случае, за счёт потерь на межсоединениях, подобные задачи могут работать на большом числе процессоров хуже, чем, если бы они исполнялись на меньшем числе процессоров одного шасси.
      Есть уловка, позволяющая временно ограничить число выделенных экземпляру SQL Server процессоров на время выполнения операций обслуживания данных. Для этого можно с помощью системной хранимой процедуры sp_configure изменить маску привязки процессоров (affinity mask), оставив привязку экземпляра только к процессорам одного шасси. Изменение привязки не требует перезапуска службы. После завершения операций обслуживания, можно вернуть исходное состояние привязки.
      Высокие показатели производительности и масштабируемости достигаются не только путём использования предоставляемых NUMA возможностей. В приложении баз данных необходимо уделять внимание секционированию кэшей данных и управляющих структур, чтобы их было легче распределять из локальных ресурсов NUMA-узла. Кроме того, необходимо учитывать негативное влияние блокировок больших областей данных, т.к. эти запрашиваемые приложением данные могут обслуживаться несколькими потоками, исполнение которых возможно на разных узлах.

      К оглавлению

      Выводы

      В SQL Server 2005 был добавлен новый, усовершенствованный и более приспособленный для работы на современных серверных платформах механизм планирования потоков и распределения ресурсов. В последующих версиях SQL Server 2008 и SQL Server 2008 R2 эти новшества получили дальнейшее развитие. Также, наиболее выигрышны по уровню поддержки NUMA версии операционных систем: Windows 2008 и Windows 2008 R2 Datacenter Edition. Последние версии СУБД и ОС позволяют использовать до 256 процессорных ядер. Всё это делает выбор этих версий более предпочтительным, чем их предшественники. Сегодня, разработчикам и администраторам приложений SQL Server для многопроцессорных архитектур предоставляются следующие выгоды:

      1. Обеспечен учет аппаратных особенностей современных многопроцессорных архитектур. Внутренняя оптимизация SQL Server позволяет в большинстве случаев обойтись без дополнительных настроек сервера и операционной системы для работы на многопроцессорных системах.
      2. Обеспечена возможность перераспределения нагрузки и процессорных ресурсов для достижения более высоких показателей производительности или для изоляции ресурсов разных приложений. Для этого не требуется программирования.
      3. Разработчики баз данных и приложений баз данных могут использовать программные интерфейсы операционной системы и сервера баз данных для исполнения операций манипуляции данными или операций модификации данных на заданных процессорах или процессорных узлах. Это могут быть реальные Soft-NUMA или NUMA-узлы.
      4. Секционирование памяти по NUMA узлам позволяет управлять актуальностью данных в кэше, причём, приложение может выбирать такой NUMA узел, кэш которого наиболее оптимален для текущего запроса.
      5. Привязка к узлам Soft-NUMA портов сетевых интерфейсов позволяет балансировать сетевую нагрузку и трафик в сегментах сети. Увеличение числа потоков завершения ввода-вывода за счёт увеличения числа узлов Soft-NUMA для многих типов рабочей нагрузки также позволяет поднять производительность исполнения запросов.
      6. Богатая коллекция административных динамических представлений позволяет организовать оперативную диагностику работы планировщиков непривилегированного режима, менеджеров памяти и других внутренних сущностей и объектов ядра сервера баз данных. Результаты этой диагностики могут использоваться для выбора наиболее удачной схемы утилизации процессорных ресурсов, чтобы наиболее равномерно распределять нагрузку между процессорами и добиться максимально равномерного распределения памяти.
      7. Абстракции процессорных узлов или групп процессоров, позволяют оптимизировать распределение задач по процессорам и балансировать сетевые запросы не только на серверах со специализированной процессорной архитектурой, такой, как NUMA, но и на массовых, бюджетных серверах с SMP архитектурой.

      Ваши отзывы, пожелания и замечания направляйте, пожалуйста автору на адрес mssqlhelp@rambler.ru

      К оглавлению

      Благодарности

      В первую очередь, хочу сказать спасибо Ирине Наумовой, критические замечания и рекомендации которой помогли сделать материал понятней, а текст более “читабельным”. Хочу поблагодарить сотрудников Майкрософт, Славу Окс – за то что вдохновил меня и помог с написанием первых вариантов этой статьи в 2006 году. Алексея Халяко – за экспертизу и продуктивную критику, а также за мудрые советы при написании этого варианта статьи. Владислава Щербинина – за то что он как крот искал в тексте плагиат и непростительные ошибки.

      Александр Гладченко 2010г.

       [print_link]

    • Главная SQL, Без рубрики, Новое SQL, SQL 2008 R2, Конкурс
      • SQL Server 2008 R2. Data-tier Application. Разработка, внедрение, модернизация.

        texas california lemon database Создание клиент-серверных приложений, даже в их простейшем двухуровневом варианте, где в качестве сервера выступает компьютер обеспечивающий доступ к общим для всех клиентов данным и к которому, собственно, и подключаются все клиенты с запросами этих самых данных, никогда не было сверхлегкой задачей. Одна из глобальных проблем стоящая перед командой берущейся за такой проект заключается в следующем. Код создающий базу данных необходимой структуры и конфигурации и наполняющий ее функционалом для удобного взаимодействия с клиентом (прежде всего хранимые процедуры и функции) пишется одним человеком, обычно называемым разработчиком баз данных (БД). И работает он, как правило, в своем окружении, со своими инструментами вроде Visual Studio. А после того как такой код написан и готов к внедрению, непосредственно внедрять и поддерживать его приходится совсем другому человеку, обычно называемому администратором БД. Помимо того что у разработчика было свое окружение (тестовое), а у администратора свое, «боевое» (production), так еще первому нечего было передать второму в качестве единого инсталляционного пакета.

      • Главная SQL, Без рубрики, Новое Reporting Services, SQL, SQL 2008 R2, Конкурс
        • Интеграция сервера отчетов Reporting Services 2008 R2 в клиентское приложении Visual FoxPro 9.0

          08092517255439973_f0_0 Первоначально я решил интегрировать отчеты сервера отчетов Microsoft Reporting Services 2005 в свои клиентские приложения, написанные на Visual FoxPro 9.0. Когда эта задача была решена, подоспела версия сервера отчетов Reporting Services 2008. Пришлось переводить свое решение в эту новую редакцию сервера отчетов. Это потребовало некоторых усилий (небольших), т.к. реализация самого Web сервиса в версии Reporting Services 2008 существенно поменялась по сравнению с прошлой (2005) версией сервера отчетов. А вот переход от версии Reporting Services 2008 к версии Reporting Services 2008 R2 практически не потребовал никаких изменений. Да, в версии Reporting Services 2008 R2 появилась новая  конечная точка Web сервиса ReportService2010, но при этом конечная точка ReportService2005 также осталась. Поскольку для интеграции сервера отчетов в клиентское приложение Visual FoxPro 9.0 я использую именно конечную точку ReportService2005, то переход от версии Reporting Services 2008 к версии Reporting Services 2008 R2 не потребовал от меня никаких изменения в коде реализации интерфейсов IAuthenticationExtension и IAuthorizationExtension. В дальнейшем, в статье я буду для сокращения текста статьи упоминать версию Reporting Services 2008, но при этом надо понимать, что все это также будет работать и в версии  Reporting Services 2008 R2.

          Причины переноса отчетной системы приложения в отдельную отчетную подсистему

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

          • Включение отчетов в клиентское приложение существенно уменьшает гибкость системы при ее эксплуатации у клиента;
          • Выделение отчетной системы в отдельную подсистему дает возможность подразделению Help Desk заказчика в случае необходимости самим создавать требуемые отчеты без моего вмешательства. Это дает дополнительные конкурентные преимущества моей системе;
          • Microsoft Reporting Services 2008 R2 представляет из себя HTTP сервер, и службам Reporting Services больше не нужны службы IIS для доступа к ASP.NET, диспетчеру отчетов или конечной точке веб-службы сервера отчетов. В SQL Server 2008 службы Reporting Services выполняют следующие задачи:
            • Поддерживают размещение технологий ASP.NET и Microsoft .NET Framework, которые построены на основе среды SQL Server CLR.
            • Используют возможности компонента HTTP.SYS операционной системы.
            • Серверные приложения служб Reporting Services 2008 объединены в единую службу. В рамках единой службы запускаются следующие серверные приложения: веб-служба сервера отчетов (для интерактивной обработки отчетов), диспетчер отчетов (обслуживает запросы от клиентов) и обработчик планирования и доставки (фоновое приложение для обработки заданий по расписанию).



          Другими словами, для просмотра отчетов Reporting Services 2008 не нужно никакого иного клиентского приложения, кроме Internet Explorer.

          • Возможности среды разработки отчетов Microsoft Reporting Services 2008 R2 (SQL Server Business Intelligence Development Studio 2008, Report Builder 2.0 или Report Builder 3.0 ) существенно выше по функциональности, чем возможности построителя отчетов Microsoft Visual FoxPro 9.0. Отметим несколько основных преимуществ Reporting Services 2008 как среды разработки отчетной системы:
            • Большое число источников данных. Можно создавать отчеты, использующие реляционные и многомерные данные из SQL Server и служб Analysis Services. Можно также с помощью поставщиков данных .NET Framework обрабатывать данные из баз данных Oracle и других производителей. Поддерживаются также поставщики данных ODBC и OLE DB. Чтобы получить данные из любого источника XML-данных, можно воспользоваться модулем обработки XML-данных.
            • Табличное, матричное, графическое и произвольное представление макетов отчетов. Особо отмечу матричное представление данных (кол-во и строк и колонок данных может меняться). Аналога этой области данных в Visual FoxPro 9.0 просто нет. Также интересны области данных сервера ответов «Датчик» и «Табликс»;
            • Можно добавить к отчету интерактивные возможности, предоставив ссылки на связанные отчеты и отчеты, содержащие подробные данные. К отчету также можно добавить сценарии на языке Microsoft Visual Basic Script.NET;
            • Можно добавить параметры для уточнения запроса или фильтрации данных. Динамическим параметрам числовые значения присваиваются во время выполнения в соответствии с пользовательским выбором;
            • Различные форматы вывода отчета. Доступны следующие форматы: HTML, MHTML, PDF, XML, CSV, TIFF, Excel и Word;
            • Можно внедрить пользовательские элементы управления и элементы отчетов, созданные самостоятельно или приобретенные у сторонних поставщиков. Для пользовательского элемента управления необходим модуль обработки пользовательских отчетов;
            • Чтобы облегчить перемещение внутри большого отчета, можно добавлять закладки и схемы документов;
            • Статистическая обработка и анализ данных могут выполняться с помощью элементов управления и выражений. Статистические (агрегатные) функции позволяют выполнить суммирование, найти среднее, минимальное или максимальное значения, подсчитать количество элементов, вычислить промежуточные итоги;
            • Можно внедрить в отчет рисунки и другие ресурсы, содержащие внешние данные;
            • Отчет может содержать ссылки на другие отчеты с передачей им параметров, что позволяет использовать один отчет многократно. Такие отчеты можно пометить как “невидимые” для вызова их ТОЛЬКО из “главного” отчета, но не из списка отчетов. Ах, как жаль что ничего подобного нет в отчетах Visual FoxPro 9.0!
            • Подписки для доставки по электронной почте или доставки в общую папку Windows. Применяются для автоматической доставки отчетов с помощью стандартной подписки и для задания пользовательских настроек представления отчета. В подписке указывается предпочтительный для пользователя формат доставляемого отчета, например формат Microsoft Excel или Word. Готовый для просмотра отчет доставляется в ящик электронной почты. Можно задать параметры доставки, определяющие форму доставки отчета: в виде ссылки или вложения. Готовый для просмотра отчет может быть доставлен в общую папку. Также можно выбрать способ сохранения отчета в папке: добавление или перезапись;
            • Автоматизированное распространение отчетов с помощью управляемых данными подписок, формирующее список получателей и команды доставки во время выполнения из внешнего источника данных. Для настройки отчета для большого числа пользователей используйте сведения о запросе и сопоставлении столбцов. Т.е. вы создаете таблицу и в ней добавляете по одной строке для каждого подписчика. В этой строке присутствует информация об адресе и о способе доставки отчета, параметрах выполнения отчета (если они есть) и пр. Саму таблицу вы можете легко заполнять из своего клиентского приложения Visual FoxPro 9.0;
            • Доступ по URL-адресу. Можно получать доступ к элементам сервера отчетов с помощью параметризованных строк URL-адреса. Пространство имен сервера отчетов может быть использовано для доступа к отчетам и элементам, хранящимся на сервере отчетов. Именно этот способ я использую для обращения к отчетам Reporting Services 2008 из своего клиентского приложения, написанного на Visual FoxPro 9.0;
            • Чтобы направить отчеты в общие папки, внутреннее хранилище архивов или во внутренние приложения, можно создать пользовательские модули доставки. Можно расширить обработку данных, запрашивая и преобразовывая данные из новых типов источников данных. Можно создать пользовательские модули подготовки отчетов для поддержки представления отчета в формате приложения или в
              веб-ориентированном формате, которые не поддерживаются базовой версией продукта. Также можно создать или встроить модуль безопасности, обеспечивающий проверку подлинности, отличную от Windows. Далее я подробно покажу, как заменить стандартный способ проверки подлинности, основанную на Windows, на свой собственный, основанный на проверки пользователей из моей базы данных;
          • Увеличение скорости работы при большой нагрузке на реляционную базу данных за счет использование механизма кэширования. Кэширование отчетов в собственной базе данных Reporting Services 2008 позволяет ему повторно использовать уже считанные ранее из реляционной базы данные. Есть возможность управлять временем сохранения в кэше считанных данных;
          • Просмотр “исторических” данных. Т.е. тех данных, которых уже нет в реляционной базе данных, но были в ней на момент генерации отчета. Это обеспечивается хранением данных отчетов Reporting Services в своей базе данных. Очень полезная функция!

          Структура использования отчетов Reporting Services 2008 в клиентском приложении Visual FoxPro 9.0

          Для организации программного доступа к отчетам Microsoft Reporting Services 2008 существует несколько технологий:

          • API Simple Object Access Protocol (SOAP);
          • Управляющий элемент ReportViewer;
          • URL Access.

          SOAP

          Веб-служба сервера отчетов использует протокол SOAP по протоколу HTTP и выступает в роли интерфейса связи между клиентскими программами и сервером отчетов. Веб-служба предоставляет две конечные точки — одну для выполнения отчетов и другую для управления отчетами. Веб-служба состоит из методов и набора объектов сложного типа, которые можно использовать для доступа ко всем функциональным возможностям служб Reporting Services 2008. Для вызова службы следует создать ссылку на язык описания веб-служб (WSDL) служб Reporting Services.

          Для успешного вызова веб-службы следует знать метод доступа к данной службе, поддерживаемые ей операции, параметры, ожидаемые этой службой, а также возвращаемые ей данные. Язык WSDL предоставляет эти данные в XML-документе, который может быть считан или обработан компьютером.

          Веб-служба сервера отчетов доступна в двух различных конечных точках. У каждой конечной точки существует разное имя WSDL-файла. Конечная точка ReportService2005 содержит методы управления объектами на сервере отчетов. Доступ к WSDL файлу данной конечной точки осуществляется посредством ReportService2005.asmx?wsdl.

          • Конечная точка ReportExecution2005 позволяет разработчикам программным образом обрабатывать и подготавливать к просмотру отчеты на сервере отчетов. Доступ к WSDL файлу данной конечной точки осуществляется посредством ReportExecution2005.asmx?wsdl
          • В Reporting Services 2008 R2 добавилась новая конечная точка ReportService2010, которая объединяет функции конечных точек ReportExecution2005 и ReportExecution2006. Эта конечная точка также включает новые возможности, появившиеся в SQL Server 2008 R2, такие как общие наборы данных и обновление кэша.

          WSDL-файл может быть использован средствами разработки, поддерживающими SOAP и веб-службы, например пакетом Microsoft .NET Framework SDK.

          В следующем примере показывается формат URL-адреса управляющего WSDL-файла служб Reporting Services:

          http://server/reportserver/ReportService2005.asmx?wsdl

          Дополнительные сведения о формате WSDL см. в спецификации языка WSDL консорциума World Wide Web (W3C) по адресу http://www.w3.org/TR/wsdl.

          Для разработки приложений с помощью веб-службы сервера отчетов Reporting Services 2008 необходимо:

          • обозреватель Microsoft Internet Explorer 5.5 или более поздней версии, установленный на компьютере, который соединен с Интернетом и имеет доступ к серверу отчетов;
          • Microsoft среда Visual Studio или пакет SDK для Microsoft .NET Framework, установленные на компьютере, если необходимо разрабатывать и развертывать приложения служб Reporting Services с помощью Microsoft .NET Framework;
          • полное представление о функциях и возможностях служб Microsoft SQL Server Reporting Services 2008;
          • уверенное владение протоколом SOAP и службами XML Web Services;
          • опыт разработки на языке, совместимом с платформой .NET Framework, например Microsoft Visual C# или Microsoft Visual Basic, если планируется использовать .NET Framework в качестве платформы разработки

          Как видно из этого списка, среда разработки клиентского приложения Visual FoxPro 9.0 не удовлетворяет этим требованиям. Так, что SOAP, как технология доступа к отчетом Reporting Services 2008 нам, увы, не подходит.

          Управляющий элемент ReportViewer

          Если вы пишите клиентскую программу в среде .NET Framework, то в Visual Studio  вам доступен управляющий элемент ReportViewer. Достаточно разместить на своей форме этот элемент и настроить его соответствующим образом для работы с вашим Reporting Services 2008. Данный управляющий элемент есть и для Windiows Forms и для Web Forms. Выглядит эта красота в режиме редактирования формы следующим образом:


          Но это не ActiveX, а control для .NET Framework приложения. При разработке клиентского приложения на Visual FoxPro он, увы, он не годится.

          URL Access

          В своих клиентских приложениях на Visual FoxPro 9.0 для доступа к отчетам Reporting Services 2008 я использую технологию, основанную на передаче параметров Web сервису Reporting Services в строке URL. Подробнее о параметрах, которые вы можете передать через URL, можно почитать в MSDN. В этом случае, я, на форме Visual FoxPro размещаю ActiveX элемент Web Browser и вызываю его метод Navigate с передачей ему в качестве параметра URL требуемого отчета с необходимыми параметрами. Выглядит эта технология в работе следующим образом:


          Теперь разберемся с аутентификацией и авторизацией пользователей в Reporting Services.

          Аутентификация пользователя в Microsoft Reporting Services 2008

          Аутентификация – это проверка регистрационной информации пользователя на предмет ее соответствия информации в некой базе данных. Обычно, этой информацией являются:

          1.       Уникальный регистрационный номер пользователя (Логин);

          2.       Пароль пользователя.

          Логин, обычно, хранится и передается в открытом виде, а пароль в шифрованном. Microsoft Reporting Services 2008 для аутентификации использует базу данных операционной системы (локального компьютера или домена), т.е. он использует Windows authentication. При интеграции отчетов Reporting Services 2008 в клиентское приложение Visual FoxPro 9.0, этот способ аутентификации показался мне не очень удобным по следующим причинам:

          • Пользователь должен вводить разные логины и пароли при старте моего приложения и при выполнении отчетов;
          • Права на выполнения отчетов Reporting Services придется “раздавать” на уровне Windows пользователей, а не на уровне пользователей моего приложения.

          Что делать?
          К счастью, разработчики Microsoft Reporting Services 2008 предусмотрели расширение функциональности своего продукта в том числе и в плане безопасности. Это расширение реализуется с помощью аутентификацией, основанной на Forms authentication технологии ASP.NET. Эта функциональность реализована во всех версиях Reporting Services 2008, кроме Express и Express with Tools.

          Выглядит эта технология следующим образом:


          Для реализации такого способа аутентификации мне пришлось написать свой модуль Security Extension (он выделен желтым цветом на рисунке) для Reporting Services 2008 и подключить его соответствующим образом (об этом будет рассказано далее). Модуль должен реализовывать интерфейс IAuthenticationExtension через перегрузку нескольких методов. Подробно об этом вы можете почитать в MSDN. Свой Security Extension я написал на C#. При его разработке я внимательно изучил два примера:

          1.       MSDN Microsoft Security Extension Sample

          2.       Harden MS Reporting Services Using Custom Extensions

          Учтите, что в первом примере в разделе “To debug the Forms Authentication sample code” есть ошибка в описании процесса отладки. Правильную процедуру отладки кода сборки я опишу в разделе, посвященному процессу инсталляции моего примера.

          Авторизация пользователя в Microsoft Reporting Services 2008

          Авторизация (authorization) контролирует права на использования объектов Reporting Services 2008 пользователем, уже прошедшего в нем аутентификацию.

          В Reporting Services 2008 есть возможность также расширить и эту функциональность с помощью Authorization Extension.
          Выглядит это следующим образом:


          Желтым цветом на рисунке показан модуль, который должен быть написан разработчиком для внедрения своей модели авторизации. Он должен реализовывать интерфейс IAuthorizationExtension с перегрузкой методов CheckAccess, GetUserInfo и др. Свой модуль расширения я написан на C#. Подробнее о своих модулях расширения я расскажу далее.

          В результате, работа с Report Services выглядит следующим образом:


          Желтым цветом на рисунке выделен модуль расширения, написанный мною на C# и подключенный к Reporting Services 2008, путем изменения его XML-файлов конфигурации. Для аутентификации пользователей, модуль обращается к таблице Users моей базы данных через представление dbo.VUsers  и хранимую процедуру dbo.Admin_TestPassword (на рисунке – Custom security authority). При внедрении данного метода интеграции отчетов Reporting Services 2008 в свое клиентское приложение Visual FoxPro 9.0, вы можете легко поменять данный метод аутентификации на свой собственный метод.

          Теперь что касается клиентского приложения на Visual FoxPro 9.0.
          Собственно говоря, все это расширение Reporting Services 2008 и было задумано для того, чтобы пользователь моего приложения, введя один раз пароль и логин при входе в него, далее пользовался разрешенными ему отчетами, не выходя из приложения Visual FoxPro 9.0 и не запуская явно Internet Explorer.
          При интеграции отчетов Reporting Services 2008 в мое клиентское приложение, написанное на Visual FoxPro 9.0 было учтено следующее:

          • Из моего приложения, написанного на Visual FoxPro 9.0, пользователи могут только просматривать отчеты Reporting Services 2008. Разработка отчетов и их развертывание на сервере отчетов выполняется штатными средствами самого Reporting Services 2008: SQL Server Business Intelligence Development Studio 2008, Report Builder 3.0, Report Manager (через Internet Explorer);
          • Права на использования отчетами Reporting Services 2008 определяются не его средствами администрирования, а через редактирование таблицы dbo.Reports_Permissions в моей базе данных SQL Server. Таблица заполняется через специальную форму клиентского приложения и связывает пользователей моей системы и отчеты Reporting Services 2008 по их ItemID, что и определяет права пользователей на просмотр выбранного отчета;
          • Модуль расширения авторизации для Reporting Services 2008 написан мною таким образом, что предоставляются ВСЕ права в Reporting Services 2008 администраторам моей системы (права Content Manager) и виртуальному администратору Reporting Services 2008, имя и пароль которого описаны в секции <Authentication> файла конфигурации RSReportServer.config. Там же определена строка подключения к моей базе данных для доступа к двум объектам:
            • Представление dbo.VUsers – список всех пользователей моей системы;
            • Хранимая процедура dbo.Admin_TestPassword – возвращает строку из dbo.VUsers, если пользователь опознан, или User_ID = 0 – если пользователь не опознан.
          • В данном тестовом примере параметры данного виртуального администратора Reporting Services 2008 следующие:
            • Логин – ReportAdmin;
            • Пароль – Pa$$w0rd.
          • При доступе к отчетам Reporting Services 2008 из клиентского приложения  Visual FoxPro 9.0, я использую механизм олицетворения (impersonation). Это означает, что подключение к Reporting Services 2008 осуществляется не от имени пользователя, который запустил клиентское приложение Visual FoxPro 9.0 и вошел в мою систему, а от имени пользователя, имеющего права просматривать любые отчеты – от имени, упомянутого выше, вирутального адимнистратора. В этом случае все права на просмотр отчетов определяются не на уровне методанных Reporting Services 2008 и с помощью Диспетчера Отчетов (Report Manager), а на уровне моего приложения. Главная проблема, которую мне пришлось решить при внедрении этой технологии, связана с передачей Логина и Пароля пользователя в Reporting Services 2008, использую URL выбранного отчета. Об этом будет подробно рассказано далее.
          • Если такой механизм доступа к отчетам вас не устраивает, то можно передавать в модуль аутентификации пользователя Reporting Services 2008 логин и пароль пользователя, который вошел в систему. В программный код сборки на C# никаких изменений вам вносить не потребуется, но в этом случае вам придеться давать этому пользователю права на просмотр (Browse)  на требуемые отчеты также и через Диспетчера Отчетов  (Report Manager).

          Структура интеграции отчетов Microsoft Reporting Services 2008 в клиентское приложениt Visual FoxPro 9.0

          Взаимодействие всех компонентов расширения Reporting Services 2008 и клиентского приложения Visual FoxPro показано на следующем рисунке:


          После внедрения данной системы аутентификации и авторизации, любой администратор моей системы имеет все права в Reporting Services 2008. Требуемые права на выбранный отчет, папку, источник данных и другие объекты Reporting Services 2008, можно назначить ТОЛЬКО пользователям моей системы (а не Windows).

          Реализация интерфейса IAuthenticationExtension (методы GetUserInfo, LogonUser, IsValidPrincipalName и SetConfiguration)

          Для реализации интерфейса IAuthenticationExtension необходимо переписать несколько методов класса AuthenticationExtension.

          AuthenticationExtension.SetConfiguration:

          public void SetConfiguration(String configuration)

          {

          // Ищем в файле configuration элемент ADMIN_CONFIG

          // и из его дочерних элементов извлекаем элементы:

          // CONNECTION_STRING

          // ADMIN_USER_NAME

          // ADMIN_USER_PASSWORD

          XmlDocument doc = new XmlDocument();

          doc.LoadXml(configuration);

          if (doc.DocumentElement.Name == ADMIN_CONFIG)

          {

          foreach (XmlNode child in doc.DocumentElement.ChildNodes)

          {

          switch (child.Name)

          {

          case SQL_CONNECTION_STRING: m_connectionstring = child.InnerText; break;

          case ADMIN_USER_NAME: m_adminUserName = child.InnerText; break;

          case ADMIN_USER_PASSWORD: m_adminPassword = child.InnerText; break;

          default: throw new Exception(“Не распознанный элемент: ” + child.Name.Trim() +

          ” в файле конфигурации: ” + configuration.Trim());

          }

          }

          }

          else

          throw new Exception(“В файле конфигурации: ” + configuration.Trim() +

          ” нет элемента: AdminConfiguration”);

          }

          Метод вызывается при инициализации сервиса и принимает в качестве параметра имя секции конфигурации конфигурационного файла Reporting Services 2008 RSReportServer.config (элемент <Authentication>). Я использую данную секцию для хранения следующих элементов:

          • Строка подключения к моей базе данных;
          • Имя виртуального пользователя – главного администратора Reporting Services 2008 – по умолчанию это ReportAdmin;
          • Пароль виртуального пользователя – главного администратора Reporting Services – по умолчани он равен Pa$$w0rd.

          Последние два параметра определяют виртуального пользователя – администратора Reporting Services 2008. При входе в Reporting Services 2008 данным пользователем можно администрировать сервер, даже если нет ни одного администратора в моей базе данных. Если моя система построена таким образом, что в ней всегда есть хотя бы один администратор, то данного пользователя можно и не использовать.

          AuthenticationExtension.LogonUser:

          public bool LogonUser(string userName, string password, string EncryptMode)

          {

          bool UserIsAuthentication = false;

          l_AdminKIS = false;

          if (EncryptMode == “Encrypt”)

          {

          // Пароль зашифрован, расшифруем его

          string passwordDecrypt = AuthenticationUtilities.Decrypt(password, m_connectionstring);

          if ((userName == m_adminUserName) && (passwordDecrypt == m_adminPassword))

          {

          l_AdminKIS = true;

          UserIsAuthentication = true;

          }

          else

          {

          UserIsAuthentication = AuthenticationUtilities.VerifyPassword(userName, password, m_connectionstring, true);

          }

          }

          else

          {

          // Проверяем, не админ ли!

          if ((userName == m_adminUserName) && (password == m_adminPassword))

          {

          l_AdminKIS = true;

          UserIsAuthentication = true;

          }

          else

          {

          UserIsAuthentication = AuthenticationUtilities.VerifyPassword(userName, password, m_connectionstring, false);

          }

          }

          if (UserIsAuthentication == true && l_AdminKIS != true)

          {

          // Если пользователь опознан и он не администратор сервера отчетов,

          // то надо проверить, а не админ ли он КИС

          l_AdminKIS = AuthenticationUtilities.IsKISAdmin(userName, m_connectionstring);

          }

          return UserIsAuthentication;

          }

          Метод вызывается при аутентификации пользователя. Он принимает три параметра: логин и пароль пользователя (userName и password), а также режим шифрования пароля (EncryptMode). Первые два параметра идентифицируют пользователя, а третий показывает, зашифрован ли пароль. Дело в том, что если данный метод вызывается из форм аутентификации (Logon.aspx или UILogon.aspx), то пароль не зашифрован и его расшифровка не требуется (EncryptMode <> “Encrypt”). Но данный метод, как будет показано далее, может вызываться также из формы Logon.aspx при обнаружении в параметрах логина и пароля, переданного через URL отчета. В этом случае я передаю пароль в URL в шифрованном виде, который необходимо будет расшифровать при его проверке. Для расшифровке пароля используется метод AuthenticationUtilities.Decrypt(). В данном примере метод содержит только код перевода из Hex – формата в символьный и не содержит никакого  кода расшифровки пароля. Это означает, что в ознакомительном примере я НЕ использую шифрование пароля. В реальной системе, конечно, шифрование необходимо, т.к. пароль передается в URL и может быть перехвачен злоумышленником. Альтернативным методом защиты может служить включение протокола SSL между клиентом и Web-сервером. Данный метод защиты очень надежный, но его реализация выходит за пределы данной статьи.  При передаче пароля через URL я на всякий случай кодирую пароль в Hex формат, т.е. передаю каждый символ пароля в виде двух символов (от 0 до 9 и буквы A, B, C, D, E и F). Это не шифрование пароля, а просто страховка от того, что среди символов пароля может встретиться символ, который нельзя передать через URL. Кодировка пароля  в Hex формат на клиенте производиться с помощью следующего кода Visual FoxPro 9.0:

          m.lcOutHex = STRCONV(m.lcInStr,15)

          Проверка пароля происходит в методе AuthenticationUtilities.VerifyPassword().

          AuthenticationUtilities.VerifyPassword:

          // Проверка пользователя и пароля

          // Для этого используется хранимая процедура сервера – Admin_TestPassword

          internal static bool VerifyPassword(string suppliedUserName, string suppliedPassword, string connectionString, bool PasswordIsEncrypt)

          {

          bool passwordMatch = false;

          SqlDataReader reader;

          SqlConnection conn = new SqlConnection(connectionString);

          // Читаем имя сервера и его дату, время

          SqlCommand cmd = new SqlCommand(“Admin_TestPassword”, conn);

          cmd.CommandType = CommandType.Text;

          try

          {

          conn.Open();

          cmd.CommandType = CommandType.StoredProcedure;

          cmd.Parameters.Add(“@USERLOGIN”, SqlDbType.VarChar, 40);

          cmd.Parameters[“@USERLOGIN”].Value = suppliedUserName.Trim();

          cmd.Parameters.Add(“@PASSWORD”, SqlDbType.VarChar, 16);

          cmd.Parameters[“@PASSWORD”].Value = suppliedPassword.Trim();

          reader = cmd.ExecuteReader();

          reader.Read();

          int User_ID = (int)reader[“User_ID”];

          if (User_ID > 0)

          {

          passwordMatch = true;

          }

          }

          catch (Exception ex)

          {

          throw new Exception(string.Format(CultureInfo.InvariantCulture,

          CustomSecurity.VerifyUserException + ex.Message));

          }

          finally

          {

          conn.Close();

          }

          return passwordMatch;

          }

          Проверка пользователя моей системы происходит в хранимой процедуре dbo.Admin_TestPassword. Для этого в нее передается логин пользователя и его пароль.

          Внимание! Пароль не шифруется!

          Такой способ аутентификации пользователя выбран только для примера. В вашем приложение вы можете поменять данный метод на свой собственный. Достаточно поменять код метода AuthenticationUtilities.VerifyPassword().

          Для проверки пользователя вызывается метод AuthenticationUtilities.IsValidPrincipalName() с передачей ему логина проверяемого пользователя и строку подключения.

          AuthenticationUtilities.IsValidPrincipalName:

          internal static bool IsValidPrincipalName(string suppliedUserName, string connectionString)

          {

          bool isValid = false;

          if (suppliedUserName.Trim() == String.Empty)

          return false;

          SqlConnection conn = new SqlConnection(connectionString);

          SqlCommand cmd = new SqlCommand(“SELECT * FROM dbo.VUsers WHERE Login = @Login_Name”, conn);

          cmd.CommandType = CommandType.Text;

          SqlParameter sqlParam = cmd.Parameters.Add(“@Login_Name”, SqlDbType.Char, 8);

          sqlParam.Value = suppliedUserName;

          try

          {

          conn.Open();

          SqlDataReader reader = cmd.ExecuteReader();

          if (reader.HasRows)

          {

          isValid = true;

          }

          }

          catch (Exception ex)

          {

          throw new Exception(“Ошибка идентификации пользователя: ” + suppliedUserName.Trim() + ex.Message);

          }

          finally

          {

          conn.Close();

          }

          return isValid;

          }

          Метод осуществляет поиск в представлении dbo.VUsers логина suppliedUserName. Если логин найден (объект reader содержит запись), то метод возвращает тrue. Иначе, метод возвращает false. Для соединения с сервером метод использует переданную строку подключения (connectionString).

          AuthenticationExtension.GetUserInfo:

          public void GetUserInfo(out IIdentity userIdentity, out IntPtr userId)

          {

          // Если текущий пользователь не null, то устанавливаем

          // userIdentity в текущего пользователя

          if (HttpContext.Current != null

          && HttpContext.Current.User != null)

          {

          userIdentity = HttpContext.Current.User.Identity;

          }

          else

          userIdentity = null;

          // initialize a pointer to the current user id to zero

          userId = IntPtr.Zero;

          }

          Метод вызывается сервером отчетов каждый раз, когда необходимо аутентифицировать пользователя. Если пользователь уже прошел аутентификацию, то именно он и возвращается. Иначе, возвращается пустой пользователь, что заставит Reporting Service провести повторную аутентификацию пользователя.

          Все методы интерфейса IAuthenticationExtension реализованы в классе AuthenticationExtension. Необходимая для работы данного класса дополнительная функциональность реализована в виде статических методов класса AuthenticationUtilities.

          Реализация интерфейса IAuthorizationExtension (методы CheckAccess, CreateSecurityDescriptor, GetPermissions и SetConfiguration)

          Интерфейс IAuthorizationExtension реализован с помощью класса Authorization. Рассмотрим некоторые методы этого класса.

          Authorization.CheckOperations:

          private bool CheckOperations(string principalName, AceCollection acl, object requiredOperation)

          {

          if (principalName.Trim() == String.Empty)

          return false;

          // Сначала надо определить параметры отчета

          // Если это администратор Reporting Server, то права не проверяются. Они даны и так

          if (0 == String.Compare(principalName, m_adminUserName, true, CultureInfo.CurrentCulture))

          return true;

          // Если это админ КИС ВиртуалСофт, то его права тоже не проверяем.

          // Если он прошел аутентификацию (т.е. смог подключиться к системе),

          // то он должнен обладать и всеми правами админа Report Server

          if (AuthenticationExtension.AdminKIS == true)

          return true;

          // Иначе, проверяем права в методе IsUserAuthorized

          if (IsUserAuthorized(principalName, acl, requiredOperation))

          {

          return true;

          }

          return false;

          }

          Метод используется для проверки возможности пользователем principalName выполнения операции requiredOperation. Сначала я проверяю, что пользователь является виртуальным пользователем – администратором Report Services (0 == String.Compare(principalName, m_adminUserName, true, CultureInfo.CurrentCulture)). Если это так, то метод возвращает true без проверки его прав с помощью метода IsUserAuthorized. Затем я проверяю роль пользователя в моей базе данных. Для этого используется свойства AdminKIS класса AuthenticationExtension. Это свойство устанавливатся в методе AuthenticationExtension.LogonUser() и будет равно true, если пользователь является администратором моей системы. В этом случае в методе CheckOperations() я также не проверяю права пользователя на требуемые операции, а из метода просто возвращаю значение true.

          Разработка клиентского приложения Visual FoxPro для просмотра отчетов Reporting Services 2008

          Сформулируем требования к функциональным возможностям клиентской части приложения Visual FoxPro для работы с отчетами Reporting Services 2008:

          • Просмотр отчетов из формы Visual FoxPro;
          • Управление правами на просмотр отчетов для выбранного пользователя (только для администратора моей системы);
          • Просмотр истории выполнения отчетов на сервере отчетов.

          Reporting Services 2008 поддерживает несколько форматов вывода отчета. Наиболее универсальным является формат HTML. В этом случае для  отображения выбранного отчета можно использовать Web обозреватель. В качестве Web обозревателя я использую ActiveX компонент Web-Browser, а точнее, класс _webbrowser4, построенный на его основе и размещенный в библиотеке _webview.vcx. Класс является копией класса Web Browser Control, взятого из Componet Gallery, входящего в поставку Visual FoxPro 9.0. и позволяющего использовать Microsoft Internet Explorer Browser для просмотра HTML страниц. Дополнительная функциональность, которая добавлена в _webbrowser4, в основном касается расширения управлением навигации по страницам и ведение истории выбранных URL.

          Вся функциональность, обеспечивающая работу моего клиентского приложения Visual FoxPro реализована в виде нескольких классов, размещенных в библиотеке reportservice.vcx


          Центром работы с отчетами Reporting Services 2008 является класс ViewReportService_Main. В дизайнере он выглядит следующим образом:


          Рассмотрим наиболее важные методы данного класса.

          Init:

          LPARAMETERS m.lnIDObject, m.lnNumber, m.lnBar, m.lcNameMenu, m.lnDK_ID, m.lnStr_ID

          *– Читаем параметр – URL Report Server

          WITH THIS

          .cmdSetPermissions.Visible = (oApp.User_Role = ‘A’)

          .cmdViewLog.Visible = (oApp.User_Role = ‘A’)

          .ReportServerDB = ‘ReportServer’

          IF EMPTY(.ReportServer)

          .ReportServer = ALLTRIM(oApp.SQL_FullName)

          ENDIF

          *– Если параметра нет, то имя Report Server устанавливаем по имени SQL Server

          IF EMPTY(.ReportServerURLAccess)

          .ReportServerURLAccess = ‘http://’ +.ReportServer + ‘/reportserver’

          ENDIF

          IF VARTYPE(m.lnNumber) == “N” AND m.lnNumber > 0

          .Caption = .Caption + ;

          ” Окно # ” + ALLTRIM(STR(m.lnNumber))

          .Name = ALLTRIM(.Name) + ALLTRIM(STR(m.lnNumber))

          ENDIF

          .IDObject = m.lnIDObject

          DODEFAULT(m.lnBar, m.lcNameMenu)

          *– Читаем список отчетов

          IF !.GetListReports()

          .Destroy()

          RETURN .F.

          ENDIF

          ENDWITH

          В этом методе я сначала определяю необходимые параматеры сервера отчетов и запоминаю их в свойствах класса:

          • ReportServerDB – имя базы данных сервера отчетов;
          • ReportServer – имя сервера Reporting Services. Если свойство не установлено, то оно установливается равным имени компьютера, где находится серер базы данных;
          • ReportServerURLAcces – URL к Web-сервису сервера отчетов;

          Эти свойства можно передавать в класс как параметры, можно загружать с сервера из конфигурационной таблицы моей базы данных (в своих приложениях я так и делаю) или читать из конфигурационного файла (INI-файла, XML и т.п.). Если URL сервера отчетов не задано, то я считаю, что Reporting Services 2008 находится на компьютере, где находится и моя база данных. Затем я читаю с сервера в локальный курсор SReports список отчетов Reporting Services 2008, путем вызова метода класса GetListReports() и копирую этот список в локальный курсор ListReport, который и предъявляю пользователю посредством объекта cboListReports класса ComboBox.

          GetListReports:

          *– Чтение списка отчетов

          LOCAL m.lcDSNLess, m.lnConnect, loCAD AS CursorAdapter

          WITH THIS

          .cboListReports.RowSource = “”

          ZAP IN ListReport

          *– Создаем новое соединение под логином админа и читаем список пользователей

          TEXT TO lcDSNLess TEXTMERGE NOSHOW PRETEXT 15

          Driver={<<ALLTRIM(oApp.Driver)>>};Server=<<ALLTRIM(oApp.SQLServer)>>;

          Database=<<ALLTRIM(oApp.SQLDatabase)>>;

          Uid=AppAdmin;Pwd=Pa$$w0rd;

          APP=Интерграция RS 2008 и Visual FoxPro, Чтение списка отчетов

          ENDTEXT

          m.lnConnect = SQLSTRINGCONNECT(m.lcDSNLess)

          IF m.lnConnect <= 0

          RETURN .F.

          ENDIF

          loCAD = CREATEOBJECT(“sql.sqlca”)

          WITH m.loCAD

          .DataSource = m.lnConnect

          .Alias = “SReports”

          .CursorSchema = ‘PolicyRoot I, Type I, CreationDate T, ModifiedDate T, ItemID C(36), ParentID C(36), Path M, Name M’

          ENDWITH

          TEXT TO m.loCAD.SelectCmd TEXTMERGE NOSHOW PRETEXT 15

          EXEC EXEC dbo.RS_GetListReports @DBReportServer='<<.ReportServerDB>>’,@USER_ID=<<oApp.User_ID>>,

          @ReportServer='<<.ReportServer>>’

          ENDTEXT

          IF m.loCAD.CursorFill(.T., .F.)

          INSERT INTO ListReport (ItemID, Path, Name) ;

          SELECT ItemID, Path, LEFT(Name, 120) ;

          FROM SReports WHERE Type = 2

          ENDIF

          m.loCAD.CursorDetach()

          SELECT ListReport

          GOTO TOP

          WITH .cboListReports

          .RowSourceType = 2

          .RowSource = ‘ListReport.Name’

          .Value = ListReport.Name

          ENDWITH

          ENDWITH

          Для формирования строки подключения к моему SQL Server, используются следующие свойства PUBLIC класса oApp:

          • Driver – имя драйвера для подключения к SQL серверу. Для версии сервера SQL 2008 драйвер называется – SQL Server Native Client 10.0;
          • SQLServer – имя SQL сервера с которым работает приложение;
          • SQLDatabase – имя моей базы данных на SQL сервере.

          Для чтения списка отчетов служит хранимая процедуры dbo.RS_GetListReports. Она использует функцию OPENROWSET для чтения таблиц dbo.Catalog и dbo.ExecutionLog базы данных Reporting Services 2008. Для доступа к этим таблицам у пользователя, который используется  в строке подключения функции OPENROWSET, должны быть необходимые права на чтения из этих таблиц. Для разрешения использования функции OPENROWSET необходимо открыть Faset сервера Surface Area Сonfiguration и установить его параметр AdHocRemoteQueriesEnabled = true.

          dbo.RS_GetListReports:

          CREATE PROCEDURE dbo.RS_GetListReports

          @DBReportServer SYSNAME = NULL,

          @USER_ID INT = NULL,

          @ReportServer SYSNAME = NULL

          AS

          BEGIN TRY

          — Хранимая процедура должна получить список отчетов из Reportig Services

          — Находим базу данных, которая обслущивает Reportig Services

          DECLARE @COMMAND NVARCHAR(1000),

          @ROLE CHAR(1)

          IF NOT EXISTS(SELECT * FROM dbo.Users WHERE User_ID = @USER_ID)

          RAISERROR(‘Не найден пользователь User_ID=%d!’, 16, 127, @USER_ID)

          SELECT @ROLE = RoleUser FROM dbo.Users WHERE User_ID = @USER_ID

          CREATE TABLE #ListReport (PolicyRoot int, Type int, CreationDate datetime, ModifiedDate datetime

          , ItemID char(36)

          , ParentID char(36), Path varchar(425) COLLATE SQL_Latin1_General_CP1251_CI_AS

          , Name varchar(425) COLLATE SQL_Latin1_General_CP1251_CI_AS )

          IF @DBReportServer IS NULL

          BEGIN

          SET @DBReportServer = dbo._Constans(‘ReportServerDB’)

          IF @DBReportServer = ”

          SET @DBReportServer = ‘ReportServer’

          END

          IF @ReportServer IS NULL

          BEGIN

          SET @ReportServer = dbo._Constans(‘ReportServer’)

          IF @ReportServer = ”

          SET @ReportServer = ‘ReportServer’

          END

          — Удаляем из таблицы Reports.Permissions те записи, которых уже нет в Catalog (Уборка мусора)

          SET @COMMAND = N’DELETE FROM dbo.Reports_Permissions WHERE ItemID NOT IN

          (SELECT a.ItemID FROM OPENROWSET(”SQLNCLI”, ”Server=’ +

          @ReportServer + N’;Uid=AppAdmini;Pwd=Pa$$w0rd;Database=’ + @DBReportServer + ”’,”’ +

          N’SELECT ItemID FROM dbo.Catalog”) a)’

          EXECUTE(@COMMAND)

          SET @COMMAND =

          N’INSERT INTO #ListReport (PolicyRoot, Type, CreationDate, ModifiedDate, ItemID, ParentID, Path, Name)

          SELECT PolicyRoot, Type, CreationDate, ModifiedDate, CAST(ItemID AS char(36)),

          cast(ParentID AS char(36)), Path, Name

          FROM OPENROWSET(”SQLNCLI”, ”Server=’ + @ReportServer + N’;Uid=AppAdmin;

          Pwd=Pa$$w0rd;Database=’ + @DBReportServer + ”’,”’ +

          ‘SELECT * FROM dbo.Catalog WHERE ISNULL(Hidden, 0) = 0”) AS a’ +

          CASE WHEN @ROLE <> ‘A’ THEN N’ WHERE (a.ItemID IN (SELECT ItemID

          FROM dbo.Reports_Permissions) OR (a.Type = 1))’ ELSE ” END

          EXECUTE(@COMMAND)

          SELECT * FROM #ListReport

          ORDER BY Name

          END TRY

          BEGIN CATCH

          IF @@NESTLEVEL = 1

          BEGIN

          IF (XACT_STATE()) <> 0

          ROLLBACK TRAN

          EXEC dbo.ErrorProcess

          END

          ELSE

          EXEC dbo.ErrorProcess 0

          END CATCH

          GO

          GRANT EXECUTE ON dbo.RS_GetListReports TO ASU

          Вместо AppAdmin и Pa$$w0rd необходимо подставить логин и пароль учетной записи (Login – Server-Level Principal), имеющей права на чтение из таблиц dbo.Catalog и dbo.ExecutionLog базы данных сервера отчетов.

          oApp.User_ID – ID пользователя, который вошел в мое клиентское приложение Visual FoxPro. Список пользователей хранится в таблице dbo.Users моей базы данных. Список  доступен через представление (View) dbo.VUsers.

          Использование предложения COLLATE обусловлено различием параметров COLLATE моей базы данных и сервера (а значит, и базы данных сервера отчетов). Это наследие “проклятого прошлого”, т.к. моя база данных была разработана еще во времена SQL сервера версии 6.5!  Если у вас COLLATE сервера и вашей базы данных не отличаются, то предложения COLLATE необходимо исключить.

          Если база данных сервера отчетов находится на другом сервере, то для доступа к таблицам dbo.Catalog и dbo.ExecutionLog базы данных сервера отчетов вместо Remote Query (OPENROWSET), можно использовать расширение олицетворения (EXECUTE AS LOGIN и свойство базы данных TRUSTWORTHY) или механизм доверительных отношений, устанавливаемых с помощью сертификатов. В последнем случае  я должен создать сертификат (CREATE CERTIFICATE…) в своей базе данных, подписать им хранимую процедуру, которая из моей базы данных обращается к ресурсам (таблице) другой базы данных (ADD SIGNATURE TO … BY CERTIFICATE …), сделать BACKUP сертификата в файл (BACKUP CERTIFICATE…), восстановить из этого BACKUP-па сертификат в базе данных Reporting Services 2008 (CREATE CERTIFICATE .. FROM FILE = …) и создать в ней пользователя на основе данного сертификата (CREATE USER … FROM CERTIFICATE …). Затем этому пользователю необходимо дать права на чтение из таблиц базы данных сервера отчетов dbo.Catalog и dbo.ExecutionLog. Подробнее об использовании сертификатов MS SQL Server 2008 для обеспечения доступа из одной базы данных к ресурсам другой, можно прочитать в BOL к SQL Server 2008.

          Метод ViewReport:

          LOCAL m.lcURL

          IF EOF(“ListReport”) OR EMPTY(ListReport.Path)

          RETURN .F.

          ENDIF

          TEXT TO lcURL TEXTMERGE NOSHOW PRETEXT 15

          <<ALLTRIM(THIS.ReportServerURLAccess)>>?<<THISFORM.Url1.AddressToURL(ALLTRIM(ListReport.Path))>>

          &rs:Command=Render&rs:format=HTML4.0&rs:Login=ReportAdmin&rs:Password=

          <<THIS.Encrypt(‘Pa$$w0rd’)>>

          ENDTEXT

          THISFORM.ViewWeb.Navigate(m.lcURL)

          Метод вызывается из события Click() кнопки cmdReport и предназначен для отображения в объекте ViewWeb (ActiveX Web Browser) выбранного отчета. Выбранный отчет находится в текущей записи поля Path курсора ListReport. Для формирования URL отчета я должен к URL Web сервиса сервера отчетов (он хранится в свойстве класса ReportServerURLAccess) через символ знака вопроса’? ‘ добавить необходимые параметры с использование синтаксиса URL Report Services. Синтаксис очень прост:

          http://server/virtualroot?[/pathinfo]&prefix:param=value[&prefix:param=value]…n], где:
          server – Имя компьютера, где запущен Report Services;
          vitualroot – Имя виртуальной директории Report Services. По умолчанию имя этой виртуальной директории равно reportserver;
          ? – символ – разделитель адреса сервера и параметров в полном URL;
          [/pathinfo] – полный путь к выбранному отчету;
          & – разделитель пар “параметр = значение” друг от друга;
          prefix – Опция. Указатель на тип параметра. Если префикс отсутствует, то параметр воспринимается как параметр выбранного отчета;
          param – Имя параметра;
          value – текст, соответствующий значению параметра.

          Пример:

          http://servername/reportserver?/SampleReports/Employee Sales Summary&rs:Command=Render&rs:format=HTML4.0

          Для передачи серверу отчетов логина и пароля я использую префикс rs. Если пользователь еще не прошел аутентификацию, то Reporting Services 2008 вызовет форму Logon.aspx. В методе Page_Load() формы Logon.aspx проверяется наличие переданных параметров (логин и пароль) и в случае их нахождения, делается попытка аутентифицикации пользователя с переданными логином и паролем. В случае успешной аутентификации пользователя, происходит переход по URL требуемого отчета без предъявления формы Logon.aspx для ввода логина и пароля. Вот код события Page_Load() этой формы:

          private void Page_Load(object sender, System.EventArgs e)

          {

          // Получаем параметры, переданные через URL, которые идентифицируют пользователя:

          // 1. in_login – логин пользователя

          // 2. in_password – закодированный пароль пользователя

          if (!this.IsPostBack)

          {

          // Страницу загружаем первый раз, надо проверять информацию в URL

          encPassword = false;

          if (Request.QueryString[“OpType”] == “Export”)

          {

          // Если передан в URL OpType=Export, то это экспорт отчета и подключение

          // также необходимо производить от имени ReportProxyLogin и пароля ReportProxyPassword

          TxtUser.Text = ConfigurationManager.AppSettings[“ReportProxyLogin”];

          TxtPwd.Text = ConfigurationManager.AppSettings[“ReportProxyPassword”];

          BtnLogon_Click(this, null);

          }

          else

          {

          if (Request.QueryString[“rs:Login”] != null)

          {

          TxtUser.Text = Request.QueryString[“rs:Login”];

          }

          if (Request.QueryString[“rs:Password”] != null)

          {

          TxtPwd.Text = Request.QueryString[“rs:Password”];

          }

          if ((string.IsNullOrEmpty(TxtPwd.Text) != true) &&

          (string.IsNullOrEmpty(TxtPwd.Text) != true))

          {

          encPassword = true;

          BtnLogon_Click(this, null);

          }

          }

          }

          }

          В этом методе я пытаюсь найти в списке переданных в URL параметров два параметра: rs:Login и rs:Password. Если параметры переданы, то я сохраняю их в свойствах Text объектов TxtUser и  TxtPwd класса TextBox, устанавливаю свойство класса  encPassword = true и вызываю метод BtnLogon_Click(), который является реакцией на нажатие кнопки “Вход” формы Logon.aspx. Если в URL обнаруживается команда OpType и ее значение Export, то это означает, что пользоваетель из отчета пытается выполнить экспорт данных в один из поддерживаемых экпортируемых форматов Reporting Services 2008. В данном примере в этом случае я также осуществляю подключение к серверу отчетов от имени виртуального администратора, параметры которого (логин и пароль) читаются из раздела AppSettings файла Web.config, находящегося в папке ReportServer. Можно это код заблокировать и тогда при попытке экспорта отчета пользователю предеться вводить свои логин и пароль с которыми он входил в приложение Visual FoxPro 9.0. Разумеется, необходимо данному пользователя через Диспетчер Отчетов (Report Manager) предоставить права “Обозреватель” (Browser) на данный отчет. Если пользователю такое право не дать, то он сможет через клиента Visual FoxPro 9.0 просматривать отчет, но не выполнять его экспорт во внешний файл. В данном реализации метода Page_Load() такое ограничение отсутствует.
          Код метода BtnLogon_Click() осуществляет проверку введенных логина и пароля (свойства Text объектов TxtUser и  TxtPwd соответственно) путем вызова метода LogonUser() прокси объекта моего Reporting Services 2008:

          private void BtnLogon_Click(object sender, System.EventArgs e)

          {

          // Получаем имя сервера отчетов и имя экземпляра сервера отчетов из его файла конфигурации

          string reportServer = ConfigurationManager.AppSettings[“ReportServer”];

          string instanceName = ConfigurationManager.AppSettings[“ReportServerInstance”];

          string redirectUrl = “”;

          try

          {

          ReportServerProxy server = new ReportServerProxy();

          // Получаем URL сервера из файла конфигурации Report Manager

          server.Url = AuthenticationUtilities.GetReportServerUrl(reportServer, instanceName);

          // Вызываю функция сервера LogonUser

          if (encPassword == true)

          {

          server.LogonUser(TxtUser.Text, TxtPwd.Text, “Encrypt”);

          }

          else

          {

          server.LogonUser(TxtUser.Text, TxtPwd.Text, “Empty”);

          }

          encPassword = false;

          redirectUrl = Request.QueryString[“ReturnUrl”];

          if (redirectUrl != null)

          HttpContext.Current.Response.Redirect(redirectUrl, false);

          else

          HttpContext.Current.Response.Redirect(“logon.aspx”, false);

          }

          catch (Exception ex)

          {

          Response.Redirect(“logon.aspx”);

          }

          }

          Передача пароля в форму Logon.aspx должна происходить с его шифрованием. Т.е. значение параметр rs:Password в случае его передачи, должно быть расшифровано перед сравнением с учетными данными пользователя. Для передачи информации о шифровании пароля, метод LogonUser() вызывается с третьим параметром равным “Encrypt”. В случае успешной аутентификации пользователя в методе LogonUser(), я перехожу на требуемый URL ( HttpContext.Current.Response.Redirect(redirectUrl, false)). При этом Reporting Services 2008 просто игнорирует мои параметры rs:Login и rs:Password и отображает требуемый мне отчет. При передачи моих параметров аутентификации через URL без прификса rs, они воспринимаются в сервере отчетов как параметры отчета и передаются ему. Разумеется, в отчете нет таких параметров и возникает ошибка о недопустимых параметров отчета. Поэтому наличие префикса rs для логина и пароля ОБЯЗАТЕЛЬНО!

          Если вызов формы Logon.aspx произошел НЕ из моего клиентского приложения Visual FoxPro 9.0, в просто вводом URL Web сервиса или Диспетчера отчетов Reporting Services 2008, то параметры rs:Login и rs:Password в URL отсутствуют и автоаутентификация не происходит, а форма работает в “штатном режиме”. Это означает, что пользователь должен ввести логин и пароль и нажать на кнопку “Вход”.


          Вернемся к методу ViewReport классу ViewReportService_Main. Полный путь к требуемому отчету может содержать символы, запрещенные для использования в URL. В этом случае их необходимо закодировать в правильном формате в два этапа:

          1. Каждый русский символ переводится в формат UTF-8;
          2. Каждый байт UTF-8 переводится в шестнадцатеричное представление и перед ним ставится символ процента ‘%’.

          Также специальном образом кодируются символы типа ‘<‘, ‘>’, ‘$’, ‘&’ и пр.

          Подробнее об этом можно почитать, например, тут или тут. У меня в приложении за перекодировку отвечает класс URL, который также размещен в библиотеке reportservice.vcx. Для перекодировки URL необходимо вызвать его метод AddressToURL(). Он содержит следующий код:

          LPARAMETERS m.lcAddress

          LOCAL m.i, m.lcChar, m.lcURL, m.lcAddChar

          m.lcAddress = ALLTRIM(m.lcAddress)

          m.lcURL = ”

          m.lcAddChar = ”

          FOR m.i = 1 TO LEN(m.lcAddress)

          m.lcChar = SUBSTR(m.lcAddress, m.i, 1)

          DO CASE

          CASE m.lcChar == ‘ ‘

          m.lcAddChar = ‘+’

          CASE m.lcChar == ‘”‘

          m.lcAddChar = ‘%22’

          CASE m.lcChar == ‘#’

          m.lcAddChar = ‘%23’

          CASE m.lcChar == ‘%’

          m.lcAddChar = ‘%25’

          CASE m.lcChar == ‘&’

          m.lcAddChar = ‘%26’

          CASE m.lcChar == [‘]

          m.lcAddChar = ‘%27’

          CASE m.lcChar == ‘*’

          m.lcAddChar = ‘%2a’

          CASE m.lcChar == ‘,’

          m.lcAddChar = ‘%2c’

          CASE m.lcChar == ‘:’

          m.lcAddChar = ‘%3a’

          CASE m.lcChar == ‘;’

          m.lcAddChar = ‘%3b’

          CASE m.lcChar == ‘<‘

          m.lcAddChar = ‘%3c’

          CASE m.lcChar == ‘>’

          m.lcAddChar = ‘%3e’

          CASE m.lcChar == ‘?’

          m.lcAddChar = ‘%3f’

          CASE m.lcChar == ‘[‘

          m.lcAddChar = ‘%5b’

          CASE m.lcChar == ‘^’

          m.lcAddChar = ‘%5e’

          CASE m.lcChar == ‘`’

          m.lcAddChar = ‘%60’

          CASE m.lcChar == ‘{‘

          m.lcAddChar = ‘%7b’

          CASE m.lcChar == ‘|’

          m.lcAddChar = ‘%7c’

          CASE m.lcChar == ‘}’

          m.lcAddChar = ‘%7d’

          CASE m.lcChar == ‘/’

          m.lcAddChar = ‘%2f’

          CASE m.lcChar $ ;

          “яюьыъщшчцхфутсрпонмлкйизжедгвбаёЯЮЭЬЫЪЩШЧЦХФУТСРПОНМЛКЙИЗЕДГВБАЁ”

          *– Русский символ

          m.lcAddChar = THIS.CharToURL(m.lcChar)

          OTHERWISE

          m.lcAddChar = m.lcChar

          ENDCASE

          m.lcURL = m.lcURL + m.lcAddChar

          ENDFOR

          RETURN m.lcURL

          Метод AddressToURL() с целью перекодировки русского символа вызывает метод CharToURL(). Вот его код:

          LPARAMETERS m.lcChar

          LOCAL m.lcStr

          m.lcStr = STRCONV(m.lcChar,9)

          RETURN LOWER(‘%’ + RIGHT(TRANSFORM(ASC(LEFT(m.lcStr,1)), “@0”), 2) ;

          + ‘%’ + RIGHT(TRANSFORM(ASC(RIGHT(m.lcStr,1)), “@0”), 2))

          Сначала я перевожу символ в формат UTF-8 (STRCONV(m.lcChar,9)) , а затем каждый байт преобразую в шестнадцатеричную форму с добавлением перед каждым символом знак процента ‘%’.

          Управления правами на просмотр отчетов происходит в методе SetPermissions() класса ViewReportService_Main, который вызывается из события Click() кнопки cmdSetPermissions. Вот его код:

          *– Установка прав просмотра данного отчета

          LOCAL m.loForm

          WITH THIS

          m.loForm = CREATEOBJECT(‘ReportService.SetPermission’, ;

          THISFORM, ListReport.ItemID)

          IF VARTYPE(m.loForm) = ‘O’

          m.loForm.lblCaption.Caption = ‘Установка прав на просмотр отчета: ‘ + ;

          ALLTRIM(ListReport.Name)

          m.loForm.Show(1)

          ENDIF

          ENDWITH

          Как видно из приведенного кода, вся функциональность по управлению правами пользователей на просмотр отчета ListReport.ItemID находится в классе ReportService.SetPermission. Класс создан на основе класса Edit_Form из моей библиотеки классов MyClass.vcx. В дизайнере классов он выглядит следующим образом:


          Список прав для выбранного отчета я читаю с помощью хранимой процедуры dbo.RS_GetPermissions, которой передается в качестве параметра уникальный идентификатор отчета. Вот код этой хранимой процедуры:

          CREATE PROCEDURE dbo.RS_GetPermissions

          @ItemID UNIQUEIDENTIFIER = NULL

          — Список всех пользователей и права на заданный отчета

          AS

          BEGIN TRY

          SELECT u.Login, u.User_ID, u.Podr_Name, u.FIO AS User_Name

          , ISNULL(u.EMail, ”) AS EMail

          , IsGrant =

          CASE

          WHEN p.User_ID IS NULL THEN 0

          ELSE 1

          END

          FROM dbo.VUsers u LEFT JOIN dbo.Reports_Permissions p

          ON u.User_ID = p.User_ID AND p.ItemID = @ItemID

          WHERE u.Role <> ‘A’

          END TRY

          BEGIN CATCH

          IF @@NESTLEVEL = 1

          BEGIN

          IF (XACT_STATE()) <> 0

          ROLLBACK TRAN

          EXEC ErrorProcess

          END

          ELSE

          EXEC ErrorProcess 0

          END CATCH

          Хранимая процедура dbo.RS_GetPermissions читает список всех пользователей моей системы и в вычисляемом поле IsGrant находится признак наличия права просмотра на данный отчет данного пользователя.

          Список пользователей выводится в объекте класса SMART_GRID. А в колонке SColumn5 выводится картинка, показывающая доступен ли выбранный отчет данному пользователю. При событии DblClick() на картинке, вызывается метод SetResGrant() класса SetPermission. Вот его код:

          WITH THIS

          SELECT ListUsersPerm

          IF ListUsersPerm.IsGrant = 0

          TEXT TO lcCommand TEXTMERGE NOSHOW PRETEXT 7

          INSERT INTO dbo.Reports_Permissions (User_ID, ItemID)

          VALUES (<<ListUsersPerm.User_ID>>, ‘<<.RSItemID>>’)

          ENDTEXT

          IF SQL(lcCommand) = 0

          SELECT ListUsersPerm

          REPLACE IsGrant WITH 1

          ENDIF

          ELSE

          TEXT TO lcCommand TEXTMERGE NOSHOW PRETEXT 7

          DELETE FROM dbo.Reports_Permissions

          WHERE User_ID = <<ListUsersPerm.User_ID>>

          AND ItemID = ‘<<.RSItemID>>’

          ENDTEXT

          IF SQL(lcCommand) = 0

          SELECT ListUsersPerm

          REPLACE IsGrant WITH 0

          ENDIF

          ENDIF

          .Refresh()

          ENDWITH

          Как видно из приведенного кода, я удаляю (убрать права у выбранного пользователя на просмотр данного отчета) или добавляю запись (дать права выбранному пользователю на просмотр данного отчета).

          Для просмотра истории выполнения отчетов использутся класс rs_viewhistory, который выполняется в методе ViewLog():

          *– Просмотр и редактирование журнала Report Server

          LOCAL loForm

          WITH THIS

          loForm = CREATEOBJECT(‘ReportService.RS_ViewHistory’, THISFORM)

          IF VARTYPE(m.loForm) = ‘O’

          m.loForm.Show(1)

          ENDIF

          ENDWITH

          Данный метод вызывается из события Click() объекта cmdViewLog.

          В редакторе класса форма выглядит следующим образом:


          Для чтения истории выполнений отчетов в Report Services я вызываю в событии Init() данного класса хранимую процедуру dbo.RS_GetLog. Вот ее код:

          CREATE PROCEDURE dbo.RS_GetLog

          @DBReportServer SYSNAME = NULL,

          @ReportServer SYSNAME = NULL

          AS

          BEGIN TRY

          — Хранимая процедура должна получить список отчетов из ReportService

          — Находим базу данных, которая обслущивает ReportServer

          DECLARE @COMMAND NVARCHAR(1000)

          CREATE TABLE #Log (ReportID char(36),UserName VARCHAR(50) COLLATE SQL_Latin1_General_CP1251_CI_AS

          , Format VARCHAR(50), Parameters Text COLLATE SQL_Latin1_General_CP1251_CI_AS

          , TimeStart DATETIME, TimeEnd DATETIME, Status VARCHAR(50)

          , Name varchar(425) COLLATE SQL_Latin1_General_CP1251_CI_AS

          , Path varchar(425) COLLATE SQL_Latin1_General_CP1251_CI_AS)

          IF @DBReportServer IS NULL

          BEGIN

          SET @DBReportServer = dbo._Constans(‘ReportServerDB’)

          IF @DBReportServer = ”

          SET @DBReportServer = ‘ReportServer’

          END

          IF @ReportServer IS NULL

          BEGIN

          SET @ReportServer = dbo._Constans(‘ReportServer’)

          IF @ReportServer = ”

          SET @ReportServer = ‘ReportServer’

          END

          SET @COMMAND =

          N’INSERT INTO #Log (ReportID, UserName, Format, Parameters, TimeStart, TimeEnd, Status, Name, Path)

          SELECT ReportID, UserName, Format, Parameters, TimeStart, TimeEnd, Status, Name, Path

          FROM OPENROWSET(”SQLNCLI”, ”Server=’ + @ReportServer + N’;Uid=AppAdmin;Pwd=Pa$$w0rd;Database=’

          + @DBReportServer + ”’,”’ +

          ‘SELECT e.ReportID, e.UserName, e.Format, e.Parameters, e.TimeStart, e.TimeEnd, e.Status

          , ISNULL(c.Name, ””ОТЧЕТ УДАЛЕН””) AS Name, ISNULL(c.Path, ””””) AS Path

          FROM dbo.ExecutionLog e LEFT JOIN dbo.Catalog c ON e.ReportID = c.ItemID”) a’

          EXECUTE(@COMMAND)

          SELECT * FROM #Log

          ORDER BY TimeStart

          END TRY

          BEGIN CATCH

          IF @@NESTLEVEL = 1

          BEGIN

          IF (XACT_STATE()) <> 0

          ROLLBACK TRAN

          EXEC dbo.ErrorProcess

          END

          ELSE

          EXEC dbo.ErrorProcess 0

          END CATCH

          Историю выполнения отчетов я читаю из таблиц dbo.ExecutionLog и dbo.Catalog базы данных сервера отчетов.

          После чтения данных они отображаются на форме с помощью объекта класса SMART_GRID. Имя отчета, полный путь к нему и список параметров при его выполнении также отображаются и в соответствующих объектах класса Editbox.

          При большом кол-ве отчетов, доступных пользователю, или сложной иерархической структуры папок размещения отчетов на сервере отчетов, становится не очень удобно использовать объект cboListReports класса Combobox для поиска требуемого отчета. Помощь пользователю в этом случае может оказать класс viewreportservice_find, экземпляр которого вызывается из события Click() объекта cmdFindReport. В данном классе отчеты и папки, доступные пользователю выводятся в объекте моего класса aTreeView, который является наследником класса ActiveX TreeView. По клавише F2 можно выполнить поиск в “дереве”, что позволит быстро найти требуемый объект. В режиме работы класс выглядит следующим образом:


          Внедрение интеграции сервера отчетов Reporting Services 2008 R2 в клиентское приложение Visial FoxPro 9.0

          Инсталляция на серверной стороне

          ВАЖНО:

          Перед внесением изменений в конфигурационные файлы Report Server и Report Manager, сделайте их резервную копию. Режим “Forms Authentication security” НЕ ПОДДЕРЖИВАЕТСЯ в Reporting Services 2008 R2 Express.

          По умолчанию, Reporting Services установлен в папку <install>=C:\Program Files\Microsoft SQL Server\MSRS10.MSSQLSERVER\Reporting Services

          Процесс инсталляции для SQL Server 2008 и для SQL Server 2008 R2 не отличаются друг друг от друга.

          Процесс интеграции сервера отчетов Reporting Services 2008 R2 в клиентское приложене Visial FoxPro 9.0 выполняется с помощью следующих шагов:

          • Скопируйте сборку VFox.RS2008.CustomSecurity.dll в папку <install>\ReportServer\bin;
          • Cкопируйте сборку VFox.RS2008.CustomSecurity.dll в папку <install>\ReportManager\bin;
          • Cкопируйте страницу Logon.aspx в папку <install>\ReportServer;
          • Cкопируйте страницу UILogon.aspx в папку <install>\ReportManager\Pages;
          • Если вы собираетесь отлаживать код своей сборки в Visual Studio 2005, то скопируете вместе с файлом VFox.RS2008.CustomSecurity.dll также и файл VFox.RS2008.CustomSecurity.pdb.

          Учтите, что для такой операций вам необходимы администраторские привилегии при работе в операционных системах Vista, Windows 2008 и Windows 7.

          Изменение файла RSReportServer.config

          Откройте файл RSReportServer.config в среде Visual Studio 2005 или при помощи обычного текстового редактора (например в Блокноте). Файл RSReportServer.config расположен в каталоге <установка>\ReportServer.

          Отключите обязательное использование SSL изменив ключ SecureConnectionLevel с 2 на 0:

          <Add Key=”SecureConnectionLevel” Value=”0″/>

          • Найдите в нем элемент <AuthenticationTypes> и измените параметры следующим образом:

          <Authentication>

          <AuthenticationTypes>

          <Custom/>

          </AuthenticationTypes>

          <EnableAuthPersistence>true</EnableAuthPersistence>

          </Authentication>

          • Найдите элементы <Security> и <Authentication> внутри элемента <Extensions> и измените их следующим образом:

          <Security>

          <Extension Name=”Forms”

          Type=”VFox.RS2008.CustomSecurity.Authorization,VFox.RS2008.CustomSecurity.CustomSecurity”>

          <Configuration>

          </Configuration>

          </Extension>

          </Security>

          <Authentication>

          <Extension Name=”Forms”

          Type=”VFox.RS2008.CustomSecurity.AuthenticationExtension,VFox.RS2008.CustomSecurity”>

          <Configuration>

          <AdminConfiguration>

          <ConnectionString>Server=<ИМЯ ВАШЕГО СЕРВЕРА>;Database=TEST;User ID=LoginForAll;

          Password=Pa$$w0rd;Trusted_Connection=False

          </ConnectionString>

          <AdminLogin>ReportAdmin</AdminLogin>

          <AdminPassword>Pa$$w0rd/AdminPassword>

          </AdminConfiguration>

          </Configuration>

          </Extension>

          </Authentication>

          Значения элементов <AdminLogin> и <AdminPassword> можно установить как вам удобно. Пользователь <AdminLogin> используется для первого входа в Reporting Services. После внедрения данной системы и добавления пользователя в Reporting Services с назначением ему прав Content Manager, этого пользователя можно в дальнейшем не использовать. Если у вас в таблице Users есть хоть один пользователь со значением поля RoleUser = ‘A’ (администратор), то AdminLogin вам может и не потребоваться, т.к. метод CheckOperations в классе Authorization всегда возвращает true если у пользователя RoleUser = ‘A’ в не зависимости от набора прав, выданному данному пользователю на объекты Reporting Services. Если вы поменяете значения элементов <AdminLogin> и <AdminPassword>, то не забудьте также их заменить в методе ViewReport класса ViewreportService_Main.

          Замените в <ConnectionString> имя сервера, имя базы данных и параметры пользователя, имеющего  права в вашей базе читать из представления dbo.VUsers и выполнять хранимую процедуру Admin_TestPassword,  на используемые у вас.

          Найдите элемент <UI> и измените его следующим образом:

          <UI>

          <CustomAuthenticationUI>

          <loginUrl>/Pages/UILogon.aspx</loginUrl>

          <UseSSL>False</UseSSL>

          </CustomAuthenticationUI>

          <ReportServerUrl>http://<Имя Вашего сервера очтетов>/ReportServer</ReportServerUrl>

          </UI>

          Учтите, что вместо <Имя Вашего сервера отчетов> использовать  localhost нельзя. Используйте имя компьютера вашего Reporting Services 2008.

          Изменение файла RSSrvPolicy.config

          • Откройте файл RSSrvPolicy.config, расположенный в каталоге <установка>\ReportServer.
          • Добавьте в файл политики безопасности RSSrvPolicy.config следующий элемент <CodeGroup> непосредственно ПЕРЕД существующей группы кода, имеющей URL-членство $CodeGen:

          <CodeGroup

          class=”UnionCodeGroup”

          version=”1″

          Name=”SecurityExtensionCodeGroup”

          Description=”Code group for integration RS 2008 R2 and Visual FoxPro 9.0 client””

          PermissionSetName=”FullTrust”>

          <IMembershipCondition

          class=”UrlMembershipCondition”

          version=”1″

          Url=”C:\Program Files\Microsoft SQL Server\MSRS10.MSSQLSERVER\Reporting Services\

          ReportServer\bin\VFox.RS2008.CustomSecurity.dll” />

          </CodeGroup>

          Изменение файла RSMgrPolicy.config

          • Откройте файл политики диспетчера отчетов RSMgrPolicy.config, расположенный в каталоге <установка>\ReportManager.
          • Найдите в файле RSMgrPolicy.config следующую группу кода и измените атрибут PermissionSetName с Execution на FullTrust, как показано ниже:

          <CodeGroup

          class=”FirstMatchCodeGroup”

          version=”1″

          PermissionSetName=”FullTrust”

          Description=”This code group grants MyComputer code Execution permission.”>

          <IMembershipCondition

          class=”ZoneMembershipCondition”

          version=”1″

          Zone=”MyComputer” />

          Изменение файла Web.config для сервера отчетов

          • Откройте файл Web.config в текстовом редакторе. По умолчанию сборка расположена в каталоге <установка>\ReportServer.
          • Найдите элемент <identity> и присвойте атрибуту Impersonate значение false.

          <identity impersonate=”false” />

          • Найдите элемент <authentication> и присвойте атрибуту Mode значение Forms.
          • Добавьте следующий элемент <forms> в качестве дочернего элемента для элемента <authentication> и присвойте атрибутам loginUrl, name, timeout и path следующие значения:

          <authentication mode=”Forms”>

          <forms loginUrl=”logon.aspx” name=”sqlAuthCookie” timeout=”60″

          slidingExpiration=”true” path=”/”></forms>

          </authentication>

          • Добавьте следующий элемент <authorization> непосредственно после элемента <authentication>.

          <authorization>

          <deny users=”?” />

          </authorization>

          Это запретит доступ к серверу отчетов не прошедшим проверку   пользователям.
          Ранее установленный атрибут loginUrl элемента   <authentication> будет перенаправлять не прошедшие проверку запросы на страницу Logon.aspx.

          • Добавьте элемент <appSettings> между элементами <system.web> и <runtime>:

          <appSettings>

          <add key=”ReportServer” value=”ИМЯ ВАШЕГО СЕРВЕРА ОТЧЕТОВ”/>

          <add key=”ReportServerInstance” value=”ИМЯ ВАШЕГО ЭКЗЕМПЛЯРА СЕРВЕРА ОТЧЕТОВ”/>

          <add key=”ReportProxyLogin” value=”ReportAdmin”/>

          <add key=”ReportProxyPassword” value=”Pa$$w0rd”/>

          </appSettings>

          Подставьте ваши значения имени сервера отчетов и имени экземпляра сервера отчетов. Ковычки вокруг имен обязательны. По желанию, можете поменять логин и пароль для виртуального пользователя – адимнистратора сервера отчетов.

          Имя экземпляра Reporting Services проще всего выяснить, выполнив следующую PowerShell команду:

          get-wmiobject -namespace “root\Microsoft\SqlServer\ReportServer” -class  “__Namespace”

          Напоминаю, что PowerShell можно запустить из командной строки операционной системы, набрав в ней: powershell.

          Изменение файла Web.config для диспетчера отчетов

          • Откройте файл Web.config диспетчера отчетов. Файл Web.config расположен в каталоге <установка>\ReportManager.
          • Отключите олицетворение, найдя раздел <identity impersonate= “true” /> и изменив его следующим образом:

          <identity impersonate=”false” />

          • Добавьте следующие ключи в элемент <appSettings>:

          <add key=”ReportServer” value=”ИМЯ ВАШЕГО СЕРВЕРА ОТЧЕТОВ”/>

          <add key=”ReportServerInstance” value=”ИМЯ ВАШЕГО ЭКЗЕМПЛЯРА СЕРВЕРА ОТЧЕТОВ”/>

          Подставьте ваши значения имени сервера отчетов и имени экземпляра сервера отчетов. Кавычки вокруг имен обязательны.

          Имя экземпляра Reporting Services проще всего выяснить, выполнив следующую PowerShell команду:

          get-wmiobject -namespace “root\Microsoft\SqlServer\ReportServer” -class  “__Namespace”

          В заключении необходимо перезапустить Reporting Services 2008 с помщью SQL Server Configuration Manager, Reporting Services Configuration Manager или из командной строки с помощью команд:

          net stop “SQL Server Reporting Services (<Instance Name>)”

          net start “SQL Server Reporting Services (<Instance Name>)”

          Отладка кода сборки

          Для отладки кода сборки VFox.RS2008.CustomSecurity.dll необходимо выполнить следующее:

          1. В Visual Studio 2005 откомпилируйте ваш проект с выбранной конфигурацией Debug;
          2. Скопируйте  вместе с самой сборкой также файл VFox.RS2008.CustomSecurity.pdb;
          3. Запустите через утилиту Reporting Services Configuration Manager ваш Report Server;
          4. В Visual Studio 2005 из меню Debug выберете пункт Attach to Process.
          5. Найдите в списке процессов процесс с именем ReportingServicesService.exe и щелкните кнопку Attach;
          6. В Visual Studio 2005 установите точки останова, требуемые для  вашей отладки;
          7. Откройте Internet Explorer и перейдите к URL Web сервиса отчетов или URL диспетчера отчетов (в зависимости от того, что вы отлаживаете). Очень просто это выполнить через Reporting Services Configuration Manager;
          8. Выполните необходимые действия для достижения заданой точки остановки и по ее достижению вы будет переключены в Visual Studio 2005;
          9. Продолжайте отладку кода с использованием окон Local, Watch, Call Stack и пр.

          Инсталляция на клиентской стороне

          • Включите в проект библиотеки классов reportservice.vcx и _webview:
            SET CLASSLIB TO ReportService, _webview ADDITIVE;
          • Учтите, что классы из библиотеки reportservice.vcx наследованы от классов библиотек myclass.vcx и mycontrols.vcx;
          • Для доступа к отчетам Reporting Services достаточно при генерации главного меню приложения (метод DoMenu класса csfw) добавить пункт:
            DEFINE BAR 5 OF p_Test PROMPT “Просмотр отчетов Reporting Services”
            ON SELECTION BAR 5 OF p_Test oApp.ExecObject(“viewreportservice”);
          • Не забудьте отредактировать свойства класса
            ReportServerDB – имя базы данных Reporting Services 2008. По умолчанию оно равно значению ReportServer;
            ReportServer – имя сервера с  Reporting Services 2008. По умолчанию оно равно имени компьютера, где находися ваша база данных;
            ReportServerURLAccess – URL к Web сервису сервера отчетов. По умолчанию оно пусто. Это приводит к тому, что в методе Init класса это свойстов вычисляется как ‘http://’ + имя_компьютера_сервера_отчетов + ‘/reportserver’.

          Для установки вам потребуется скачать:

          • Проект VFox.ReportServer.CustomSecurity2008. Из него вам понадобятся файлы: VFox.RS2008.CustomSecurity.dll, UILogon.aspx, Logon.aspx и VFox.RS2008.CustomSecurity.pdb (только для отладки);
        • Библиотеки классов reportservice и _webview;
        • Обновить картинки и иконки.
        • Скачать скрипты SQL Server, которые создают необходимые серверные объекты (хранимые процедуры, view и пр.).
          Самое удобное – скачать весь демонстрационный проект и backup базы данных TEST. Тогда вы точно ничего не упустите. Только не забудьте после восстановления базы данных создать логины на своем сервере и восстановить их связь с пользователями тестовой базы данных.
        • Также скачать файлы можно со страницы скачивания моего сайта.

          Вот и все! Удачи и пишите если что не получится!

          Алексей Климов

Главная SQL, Без рубрики, Новое SQL, SQL 2008 R2, Конкурс