Considération sur les listeners associées aux groupes de disponibilités avec SQL Server 2012 AlwaysOn

Mis en avant

Lorsqu’on crée un groupe de disponibilité avec SQL Server et AlwaysOn on l’associe par la suite à un listener. Lorsque ce dernier est créé plusieurs objets lui sont associées :

  • Un objet d’ordinateur dans l’annuaire active directory
  • Une entrée DNS de type A
  • Une ressource cluster associée à au groupe de ressource créé et qui représente le groupe de disponibilité

 

Dans l’exemple suivante un groupe de disponibilité nommé AdventureWorks2 a été créé. Le listener associé s’appelle LST_ADVW2

 

alwayson_aag_lst

 

icon_arrow Les différents objets associés

 

L’objet d’ordinateur dans l’annuaire :

alwayson_ad_object

 

… l’enregistrement DNS :

alwayson_dns_record

 

… Le groupe de ressource lié au groupe de disponibilité :

alwayson_cluster_resource

 

… et les ressources qui le composent :

alwayson_cluster_resource2

 

Jetons un coup d’Å“il aux dépendances existantes entre les ressources du groupe de ressource AdventureWorksGrp2 :

alwayson_cluster_dependencies

 

Ici on vient bien les dépendances existantes : le groupe de disponibilité AdventureWorksGrp2 dépend de la ressource "nom réseau" qui représente notre listener (LST_ADVW2) qui elle même dépend de la ressource "Adresse IP" qui vous l’aurez devinez, correspond à l’adresse IP de notre listener.

 

icon_arrow Port d’écoute du listener

Est-ce qu’un listener doit écouter sur le même port que les réplicas du groupe disponibilité ?  Est-ce possible ? C’est une question qui s’est posé rapidement dans mon cas lorsqu’il a fallu installer des réplicas n’écoutant pas sur le port qui n’écoutaient pas sur le port par défaut (1433). On peut même aller à l’extrême et prendre le cas où chaque réplica écoute sur un port différent. Dans ce cas quel port dois-je paramétrer pour mon listener ? Un listener peut tout à fait écouter sur un port différent que les réplicas. Le choix du numéro de port dépend évidement de vos besoins, contraintes de sécurité etc …  Prenons un exemple avec 2 réplicas qui écoutent sur 2 ports différents (1499 et 1500) et un listener qui écoute sur le port 1433.

 

[AlwaysOn Instance]

Cette configuration fonctionne parfaitement. Par curiosité on peut voir ce que cela donne sur une trace réseau via NetMon par exemple.

alwayson_netmon0

On peut voir ici une connexion depuis SQL Server Management Studio vers le listener lst_advw.insentia.lab (IP virtuelle : 192.168.0.61)

 

Dans notre cas le listener écoute sur le port 1433 et la connexion est automatiquement redirigée vers le réplica concerné en toute transparence. Au niveau de la chaine de connexion l’impact est minime : le nom du listener remplace tout simple le nom de l’instance SQL Server. Cependant que se passe-t-il maintenant si nous changeons le port d’écoute du listener vers un port non standard ? En réalité les choses se compliquent un peu et il existe plusieurs cas :

  • On spécifie le numéro de port directement dans la chaine de connexion
  • On a la possibilité d’utiliser le format suivant : [nom listener]\[nom instance] sous certaines conditions :
    • On utilise des instances nommées qui portent le même nom pour l’ensemble des réplicas
    • Le service SQL Browser est démarré et opérationnel sur l’ensemble des réplicas pour effectuer la résolution de nom de l’instance vers le numéro de port adéquat.

icon_arrow Cas de la redirection vers un réplica secondaire en lecture seule

AlwaysOn nous fournit la possibilité d’être redirigé vers un réplica secondaire en lecture seule en se connectant via le listener à condition que les règles de redirection  aient été définies (routes et priorités). Dans ce cas une trace NetMon nous révèle la chose suivante :

alwayson_netmon1

 

On peut constater ici qu’après la phase d’authentification la connexion de SQL Server Management Studio initialement effectuée vers le listener lst_advw.insentia.lab (port 1433) est redirigé vers le réplica secondaire en lecture seule REPLICA2 (port 1498)

 

icon_arrow Kerberos, SPN et redirection vers un réplica secondaire en lecture seule

La documentation en ligne Microsoft stipule que pour utiliser Kerberos dans une architecture AlwaysOn il faut ajouter les SPN correspondants à nos listeners. Cependant je n’ai pas trouvé dans la documentation le cas où le listener effectuait une redirection d’une connexion en lecture seule vers un réplica secondaire en lecture seule. Dans ce cas ajouter les SPN pour les listeners ne suffit pas et l’on doit également ajouter les réplicas secondaires en lecture seule.

Voici une trace netmon d’une tentative de connexion en erreur à un réplica secondaire avec Kerberos :

alwayson_spn_netmon

 

On peut voir ici 2 requêtes TGS depuis ma station cliente (192.168.0.100) vers mon contrôleur de domaine (192.168.0.1) :

  • TGS request vers le service MSSQLSvc/lst_advw.insentia.lab (port 1433) : listener
  • TGS request vers le service MSSQLSvc/replica2.insentia.lab (port 1498) : réplica secondaire en lecture seule

Le contrôleur de domaine répond avec une erreur pour la deuxième demande car il n’y a pas de SPN paramétré pour REPLICA2 dans mon cas (KDC_ERR_S_PRINCIPAL_UNKNOW)

 

icon_arrow Listeners vs alias (DNS / SQL) ?

Une question intéressante surtout lorsqu’on a l’habitude de lier le point de connexion des applications via un alias DNS ou SQL par exemple. Ainsi lorsqu’on change de serveur de bases de données avec un nouveau nom, il suffit d’utiliser de modifier l’alias en conséquence. Le changement est donc relativement transparent pour les applications. Avec SQL Server AlwaysOn, lorsqu’un un listener est créé nous avons vu qu’une entrée DNS est également effectuée. De plus on a la possibilité d’associer plusieurs listeners à un seul groupe de disponibilité ce qui peut tout à fait remplacer les alias. Bien entendu chaque méthode présente des avantages mais aussi des inconvénients. Goden Yao (Program Manager , SQL Server Engine High Availability)  a écrit un billet intéressant à ce sujet.

 

Bon paramétrage de listeners !!

 

David BARBARIN (Mikedavem)
MVP SQL Server

SQL Server 14 : c’est parti enfin presque …

Mis en avant

Pour ceux qui ont suivi un peu l’actualité, Microsoft a annoncé le 6 Avril la sortie de SQL Server 2014 à l’occasion du TechEd North America. Il est vrai que cette annonce peut surprendre d’autant plus que le 02 avril 2012 SQL Server 2012 sortait. Le planning des sorties des versions s’est en effet réduit. Mais qu’est-ce que nous réserve cette nouvelle version (et pas une R2 cette fois)  ?

Parmi les fonctionnalités les plus attendus et les plus prometteuses :

  • Hekaton : le nom de code du moteur de base de données entièrement in-memory avec un contrôle de concurrence multi-version sans mécanisme de verrouillage (locks et latchs).  On pourra également compiler les procédures stockées directement en code machine pour obtenir des gains de performance supplémentaires. Très prometteur !!!
  • L’extension du cache mémoire aux supports non volatiles avec l’utilisation de disques SSD
  • L’utilisation des index columnstores  avec possibilité de mises à jour, ce qui va étendre les scénarios d’utilisations de ces types d’index
  • L’extension du gouverneur de ressources aux IO. On a maintenant le scope complet de gestion des ressources CPU, RAM et IO
  • L’estimation des cardinalités par l’optimiseur de requêtes améliorée
  • Gestion des statistiques des colonnes et index possibles au niveau partition d’une table
  • Amélioration apportée pour SQL Server AlwaysOn (utilisation possible jusqu’à 8 réplicas, plus de downtime pendant les reconstructions d’index en ligne …)
  • Possibilité de scaling des ressources augmentée avec l’utilisation de Windows Server 2012 R2
  • Plateforme Hybrid-Cloud ready
  • ….

 

Pour plus de détails c’est par ici : SQL Server Blog

Vous avez la possibilité de vous inscrire pour l’obtention de SQL Server 2014 en CTP1 !

 

David BARBARIN (Mikedavem)
MVP SQL Server

SQL Server 2012 AlwaysOn et plans de maintenance par défaut

Mis en avant

Lors de ma session GUSS du 23 avril 2013 à propos de AlwaysOn on m’a demandé si les plans de maintenance SQL Server pouvaient être utilisés dans ce contexte. J’ai répondu négativement à cette réponse sans pour autant être vraiment explicite. Pourtant lorsqu’on créé un plan de maintenance avec SQL Server 2012 et qu’on utilise une tâche de sauvegarde des bases on peut s’apercevoir que si une base de données est concernée par un groupe de disponibilité une option apparait automatiquement "For availability databases, ignore Replica Priority for Backup and Backup on Primary  Settings". L’apparition de cette option implique que par défaut les plans de maintenance SQL Server ou du mois les tâches de sauvegarde sont en théorie capables de s’aligner sur la politique de sauvegarde dictée par le groupe de disponibilité en question mais malgré ce je persiste à dire que les plans de maintenance par défaut ne sont pas adaptés (du moins encore) aux environnements AlwaysOn et c’est ce que je vais tenter d’expliquer dans ce billet.

 

icon_arrow Des tâches de sauvegardes qui gèrent et prennent en compte les préférences de sauvegarde d’un groupe de disponibilité

Commençons par le début. Effectivement les tâches de sauvegardes des plans de maintenance par défaut détectent l’appartenance ou non d’une base de données à un groupe de disponibilité.

J’ai créé une base de données DUMMY faisait parti du groupe de disponibilité

image

 

J’ai paramétré mes préférences de sauvegarde de la manière suivante :

image

 

Dans un plan de maintenance par défaut je glisse une tâche de sauvegarde de type FULL en choisissant la base de données DUMMY …

image

 

… et on s’aperçoit qu’une option supplémentaire apparait

image

 

Cette option permet de ne pas tenir compte des préférences de sauvegarde configurés dans les groupes de disponibilités pour un réplica. Par défaut cette option n’est pas activée et la tâche de sauvegarde prendra en compte les préférences de sauvegardes des groupes de disponibilités (de préférence sur les secondaires, uniquement sur les secondaires, uniquement sur le primaire, sur n’importe quel réplica).

On peut voir que la commande T-SQL générée utilise la fonction sys.fn_hadr_backup_is_preferred_replica() pour la base de données DUMMY

image

 

Notez également que j’ai activé l’option COPY_ONLY pour les sauvegardes. En effet comme ma politique de sauvegarde stipule que les réplicas secondaires seront utilisés en priorité, seules les sauvegardes avec l’option COPY_ONLY fonctionneront si le réplica concerné sera secondaire au moment de la sauvegarde. Mon plan de maintenance fonctionne parfaitement même après test de failover d’un réplica vers un autre. Cependant comme vous le savez certainement un plan de maintenance n’est jamais aussi simple.

Restons sur notre tâche de sauvegarde et ajoutons-y quelques bases de données utilisateurs en mode de récupération FULL et qui ne font pas parti d’un groupe de disponibilité et c’est la que le premier problème arrive. Ma politique de sauvegarde de type full se fait toujours avec l’option COPY_ONLY dans mon cas puisque mes sauvegardes se feront en priorité sur le secondaire et que ceux-ci ne supportent que les sauvegardes avec l’option COPY_ONLY. Le problème est qu’ici la création d’une base de données utilisateur en mode de récupération FULL fera planté la tâche de sauvegarde des journaux de transactions. Pourquoi ? Tout simplement parce qu’une sauvegarde FULL avec l’option COPY_ONLY ne va pas initialiser la séquence des LSN utiles pour nos sauvegardes des journaux de transactions. Alors bien entendu je peux créer 2 plans de maintenance par exemple :

  • Un plan de maintenance qui concernera uniquement les bases de données en mode de récupération FULL associées à un groupe de disponibilité
  • Un plan de maintenance qui concernera les autres bases de données

Il faudra dans ce cas répartir manuellement les bases de données dans les différents plans de maintenance. On perd ici toute notion de gestion dynamique des plans de maintenance selon moi. Si j’ajoute une base de données par exemple, je n’ai pas forcément envie de modifier ensuite mon plan de maintenance … Bien entendu ce raisonnement ici ne tient que pour les cas où les sauvegardes sont déportés sur le secondaire. Si les sauvegardes sont effectuées uniquement sur le primaire, l’utilisation de l’option COPY_ONLY n’a plus lieu d’être.

Une autre chose à noter ici est le manque de support de l’option CHECKSUM qui permet pour rappel d’une part de vérifier le checksum de chaque page de données sauvegardée d’une base de données (si l’option est bien entendu activée au niveau de celle-ci) et de générer un checksum global pour le média de sauvegarde.

 

icon_arrow La tâche de vérification d’intégrité

Vérifier l’intégrité de ses bases de données avant de les sauvegarder est plutôt une opération recommandée. Mais dans une architecture AlwaysOn on peut se poser la question de savoir où est-ce que je dois lancer cette tâche. Si dans d’autres environnements le choix est plutôt évident car les sauvegardes ne peuvent se faire que sur le serveur "principal" , le raisonnement n’est pas tout à fait le même quand on parle de déplacement des sauvegardes sur un réplica secondaire. En effet, vu que ma politique de sauvegarde gère des préférences et des priorités de réplicas pour les sauvegardes ces dernières peuvent être lancés de n’importe où en fonction de la situation présente et des paramètres de configuration. En plus mes bases de données sont accessibles en lecture écriture depuis un réplica primaire et peuvent être inaccessible depuis mes les réplicas secondaires. Il faut également que je vérifie l’intégrité de ma base à ce niveau. Cela fait potentiellement 2 points de vérification d’intégrité des bases sur n réplicas (n pouvant aller jusqu’à 5 pour le moment mais avec SQL14 on pourra monter jusqu’à 8 !).

Si on regarde de plus près la tâche de vérification d’intégrité des plans de maintenance par défaut de SQL Server on s’aperçoit qu’il n’y a aucun paramètre de gestion des groupes de disponibilités :

image

 

Dans ce cas comment puis-je faire pour lancer ma tâche ? On peut prendre le cas extrême qui dit qu’il faut lancer cette tâche de vérification des bases sur tous les réplicas .. et pourquoi pas après tout ?

Je vois déjà 2 problèmes à cela :

  • Même si la vérification d’intégrité initiée par la commande DBCC CHECKDB ne génère pas de verrou par défaut (utilisation des snapshots de bases de données) celle-ci peut avoir un impact négatif sur les performances IO et sur l’augmentation de la REDO queue sur les réplicas secondaires. Une augmentation de cette file d’attente sur les secondaires peuvent avoir un impact sur le RPO et RTO en fonction du type de réplication choisi.
  • On peut tout à fait utiliser un réplica secondaire pour faire des sauvegardes et second réplica secondaire en standby uniquement pour effectuer du failover ou dans une procédure de disaster recovery. Dans ce cas la tâche de vérification d’intégrité des bases des plans de maintenance par défaut SQL Server étant incapable de savoir si la base de données concernée fait parti ou non d’un groupe de disponibilité et si la base de données en question est accessible en lecture seule ou non provoquera une erreur dans le plan de maintenance en fonction de la situation

 

icon_arrow Les tâches de mise à jour des statistiques et des indexes

On a exactement le même problème ici. En regardant les tâches du plan de maintenance associées aux statistiques et aux indexes il n’y a aucun paramètre de configuration lié aux groupes de disponibilité. Dans une architecture AlwaysOn on ne peut mettre à jour les indexes et les statistiques  d’une base que sur le réplica primaire. Je peux également avoir des bases de données qui ne sont pas concernées par un groupe de disponibilité. Dans ce cas il est tout à fait possible qu’un réplica secondaire d’un groupe de disponibilité soit l’instance principale d’une autre base de données. Je peux effectivement créer un plan de maintenance spécifique pour cela et activer / désactiver les jobs SQL Server associées en fonction du cas mais encore une fois cela m’oblige à gérer manuellement les bases de données à répartir dans les plans de maintenance …

De plus dans ce genre d’architecture l’utilisation des tâches par défaut de maintenance des indexes ne sont pas forcément conseillés car elles peuvent être excréments couteuse en écriture journalisée et de bande passante pour la réplication de ces écritures vers les autres réplicas. En effet, et beaucoup d’articles l’expliquent déjà, il n’y a pas la possibilité de définir des seuils de réorganisation ou de reconstruction d’indexes. La politique du tout ou rien ici n’est pas forcément très approprié.

 

Pas besoin d’aller plus loin je pense pour vous dire que les plans de maintenance SQL Server ne sont pas adaptés pour SQL Server 2012 AlwaysOn. Que fais-t-on dans ce cas là ? Pour le moment pour ma part j’ai créé un jeu de script de maintenance des bases de données pour des architectures AlwaysOn installées chez nos clients. Je n’ai pour le moment pas trouvé d’outil tiers permettant de gérer la maintenance des bases de données de A à Z pour ce type d’environnement mais je reste à l’écoute si jamais vous avez plus d’information là dessus Sourire

 

Bonne maintenance de vos architectures AlwaysOn !

 

David BARBARIN (Mikedavem)
MVP SQL Server

Webcast sur SQL Server 2012 AlwaysOn pour les fermes Sharepoint 2013 : les slides et la vidéo sont disponibles

Mis en avant

Un billet en retard pour dire que les slides et la vidéo de la session GUSS que j’ai eu l’occasion d’animer sur SQL Server 2012 AlwaysOn et SharePoint 2013 sont disponibles sur le site du GUSS

>> http://guss.fr/2013/06/01/webcast-guss-avril-2013-les-bases-alwayson/

 

guss

David BARBARIN (Mikedavem)
MVP SQL Server

Créer un serveur lié avec une connexion en lecture seule vers un réplica secondaire SQL Server 2012 AlwaysOn

Mis en avant

Petite question que je me posais aujourd’hui vu qu’en ce moment je travaille souvent sur des environnements haute disponibilité avec SQL Server 2012 et AlwaysOn. Est-il possible de créer un serveur lié qui se connecte sur un réplica secondaire en lecture et profiter du coup d’une redirection transparente en cas de changement de rôle de réplica lors d’un basculement automatique par exemple ?

Le meilleur moyen de le savoir est de faire un test.

Créons tout d’abord un serveur lié en utilisant le provider SQL Server Native Client 11.0 pour pouvoir utiliser le paramètre de connexion applicationintent=readonly. Le script de création du serveur lié est le suivant :

 

EXEC master.dbo.sp_addlinkedserver    
 @server = N'LST_APPLIX',
 @srvproduct=N'',    
 @provider=N'SQLNCLI', -- Provider SQL Native Client    
 @datasrc=N'LST_APPLIX', -- Availability group listener    
 @provstr=N'applicationintent=readonly',  -- Readonly intent parameter    
 @catalog=N'ApplixEnterprise' --Target database to connect

 

icon_arrow Mon groupe de disponibilité est composé de 3 réplicas avec :

  • REPLICA1 (réplica primaire)
  • REPLICA2 (réplica secondaire en lecture seule utilisé en priorité)
  • REPLICA3 (réplica secondaire en lecture seule utilisé si REPLICA2 n’est plus joignable)

 

icon_arrow Mon serveur lié est quant à lui configuré sur un serveur standalone à part.

 

La requête suivante illustre l’état de note scénario :

 

SELECT  
 g.name AS group_name,    
 r.replica_server_name,    
 rs.role_desc,    
 rs.operational_state_desc,    
 ro.replica_server_name AS replica_ro_server_name,    
 rol.routing_priority,    
 r.secondary_role_allow_connections_desc    
FROM sys.dm_hadr_availability_replica_states AS rs    
 JOIN sys.availability_groups AS g    
  ON rs.group_id = g.group_id    
 JOIN sys.availability_replicas AS r    
  ON r.replica_id = rs.replica_id    
   AND r.group_id = rs.group_id    
 JOIN sys.availability_read_only_routing_lists rol    
  ON rol.replica_id = r.replica_id    
 JOIN sys.availability_replicas AS ro    
  ON ro.replica_id = rol.read_only_replica_id    
WHERE g.name = 'ApplixGrp'    
 AND r.replica_server_name = 'REPLICA1'

 

image

 

Tentons de retrouver le serveur sur lequel le serveur lié pointe :

SELECT *    
FROM OPENQUERY(LST_APPLIX, 'SELECT @@SERVERNAME AS SERVER_NAME');

qui donne

image

 

Ok visiblement cela fonctionne. En utilisant le listener la requête est automatiquement redirigée vers le REPLICA2 comme le stipule notre configuration.

 

On lance maintenant un basculement manuel de groupe de disponibilité ApplixGrp de REPLICA1 vers REPLICA2. REPLICA2 devient donc le nouveau primaire.REPLICA1 et REPLICA3 deviennent les réplicas secondaires. On exécute à nouveau nos requêtes :

 

SELECT  
 g.name AS group_name,    
 r.replica_server_name,    
 rs.role_desc,    
 rs.operational_state_desc,    
 ro.replica_server_name AS replica_ro_server_name,    
 rol.routing_priority,    
 r.secondary_role_allow_connections_desc    
FROM sys.dm_hadr_availability_replica_states AS rs    
 JOIN sys.availability_groups AS g    
  ON rs.group_id = g.group_id    
 JOIN sys.availability_replicas AS r    
  ON r.replica_id = rs.replica_id    
   AND r.group_id = rs.group_id    
 JOIN sys.availability_read_only_routing_lists rol    
  ON rol.replica_id = r.replica_id    
 JOIN sys.availability_replicas AS ro    
  ON ro.replica_id = rol.read_only_replica_id    
WHERE g.name = 'ApplixGrp'    
 AND r.replica_server_name = 'REPLICA2'

 

image

 

et

SELECT *    
FROM OPENQUERY(LST_APPLIX, 'SELECT @@SERVERNAME AS SERVER_NAME');

qui donne

image

 

Comme on peut le voir l’utilisation d’un serveur lié vers une architecture SQL Server 2012 AlwaysOn avec une redirection des connexions en lecture seule vers les réplicas secondaires fonctionne très bien !

 

Bon paramétrage de serveurs liés

SET TRANSACTION ISOLATION LEVEL READ COMMITTED et NOLOCK = pas de verrous ?

Mis en avant

Chez un de mes clients on est venu me dire la chose suivante : visiblement lorsque j’utilise le hint NOLOCK ou un niveau de transaction READ UNCOMMITED lorsque j’exécute une requête je vois quand même des verrous posés sur mes tables alors que je croyais le contraire et du coup ma requête en lecture doit bloquer les mises à jour … A cela j’ai répondu : la vérité est ailleurs Sourire

Plus sérieusement, la bonne question à se poser est la suivante : est-ce que le fait d’utiliser un hint NOLOCK ou un niveau de transaction permettant la lecture sale veut dire que aucun verrou n’est posé ?

 

Pour répondre prenons un exemple simple avec une requête dans la base de données AdventureWorksDW2012 :

SELECT *  
FROM dbo.FactInternetSales AS f  
CROSS JOIN dbo.FactInternetSales AS f2

 

Voyons les verrous posées par cette requête à l’aide de la DMV sys.dm_tran_locks :

SELECT  
 resource_database_id,    
 resource_type,  
 resource_subtype,    
 request_mode,  
 request_type,    
 request_status,    
 request_owner_type    
FROM sys.dm_tran_locks    
WHERE request_session_id = "session"

 

icon_arrow Avec un niveau d’isolation de transaction en read committed (niveau d’isolation par défaut) :

image

 

icon_arrow  Avec un niveau d’isolation de transaction en read uncommitted :

image

 

On voit d’abord que le niveau d’isolation de transaction en mode read uncommitted ne veut pas dire qu’il n’existe plus de verrou. Le 1er verrou (de type SHARED_TRANSACTION_WORKSPACE) nous intéresse moins ici car c’est un verrou posé lorsqu’il existe une connexion sur une base de données (en l’occurence database_id = 6 ici). Cela permet de protéger la base de données contre les suppressions accidentelles par exemple lorsqu’il existe une connexion sur cette dernière.

Les verrous suivants sont plus intéressants dans notre cas. On voit que la différence notoire est qu’il existe des verrous de type IS et type S dans un cas (read committed) et plus de verrou de ce type dans l’autre cas  (read uncommitted). Le niveau d’isolation de transaction par défaut utilisé par SQL Server garantit une lecture propre des données c’est la raison pour laquelle il existe des verrous de type S et IS à différents niveaux (OBJECT et PAGE) . Avec le niveau d’isolation permettant de la lecture sale ces verrous n’existent évidemment plus mais d’autres verrous existent cependant comme celui que l’on voit dans la dernière image : verrou de type Sch-S. Ce verrou protège la table contre les modifications pendant qu’une lecture est effectuée même si celle-ci n’est pas propre.

 

Faisons le même test avec une table HEAP (sans index cluster) avec la requête suivante :

SELECT *  
FROM dbo.DatabaseLog AS f    
CROSS JOIN dbo.DatabaseLog AS f2

 

… et voyons les verrous posées :

icon_arrow Avec un niveau d’isolation de transaction en read committed (niveau d’isolation par défaut) :

image

 

icon_arrow  Avec un niveau d’isolation de transaction en read uncommitted :

image

 

La aussi on peut voir qu’avec les verrous de type S ne sont plus présents sur les objets de type PAGE ou OBJET avec un niveau d’isolation de transaction en read uncommitted.  On a néanmoins un type de verrou supplémentaire que l’on n’avait pas  avec une table possédant un index cluster à la ligne 2 (resource_type = HOBT et resource_subtype = BULK_OPERATION). Ce type de verrou n’est présent que sur les tables HEAP pour protéger les lectures contre les pages potentiellement mal formatés via des opérations BULK (merci à Paul Randal pour la précision).

 

On vient donc de voir que la lecture sale sur SQL Server engendrait certains types de verrous. Cependant on peut pousser le raisonnement plus loin. Qui dit verrou veut dire aussi latch pour accéder aux structures physiques en mémoire … on peut essayer de voir si une requête avec un niveau d’isolation en read uncommitted produit des latchs. Pour cela on peut utiliser la DMV sys.dm_os_waiting_tasks comme ceci :

-- Création à la volée d'une table temporaire pour les tâches en attente    
SELECT TOP 1 *  
INTO #waiting_tasks    
FROM sys.dm_os_waiting_tasks;    
GO

-- On vide la table avant le test  
TRUNCATE TABLE #waiting_tasks;    
GO

-- Récupération des tâches en attente générées par la requête de test    
WHILE 1 = 1    
BEGIN    
 INSERT #waiting_tasks    
 SELECT *    
 FROM sys.dm_os_waiting_tasks    
 WHERE SESSION = "session"  
END

 

En parallèle la requête suivante est lancée :

SELECT *  
FROM dbo.DatabaseLog AS f  
CROSS JOIN dbo.DatabaseLog AS f2

 

Après avoir lancé une des requêtes avec un niveau d’isolation de transaction en read uncommitted on peut constater que cette dernière a effectivement générée des latchs de type SH dans notre cas :

image

 

On peut regarder à quel objet appartient la page 154 par exemple :

DBCC TRACEON(3604);  
GO    

DBCC PAGE(6, 1, 154) WITH TABLERESULTS;    
GO

 

image

image

 

Pour conclure l’idée que l’utilisation de la lecture sale avec SQL Server ne génère pas de verrous est faussée. Certains les verrous de type S pouvant gêner les écritures sont absents mais  on a pu constater au cours de ce billet que d’autres types de verrous étaient et bien présents ainsi que des latchs pouvant même aboutir à une potentielle contention !!

Bonne utilisation de lecture sale Sourire 

David BARBARIN (Mikedavem)
MVP SQL Server

SQL Server 2012 : Installation et intégration des mises à jour

Mis en avant

Pour ceux qui ont eu à installer SQL Server 2012, vous avez sans doute remarqué que le processus d’installation incorporait maintenant des mises à jour avant même d’installer SQL Server. Cette petite nouveauté est en réalité très pratique lorsque l’on doit installer des binaires dans une certaine version et que l’on doit installer un service pack ou un cumulative update. On remplace les fameuses installations "slipstream" où l’incorporation d’un service pack dans des binaires d’installation était une opération plutôt laborieuse. De plus il existe 2 méthodes de mise à jour : l’une permet de récupérer les mises à jour via internet et l’autre permet de spécifier un dossier dans lequel il est possible de placer les mises à jour d’installation à incorporer durant l’installation d’une instance SQL Server. Par exemple il est tout à fait possible d’incorporer en même temps le service pack 1 de SQL Server 2012 et le cumulative update 3. Si plusieurs cumulative update sont présent l’installation ne prendra que le dernier en vigueur !

 

icon_arrow J’ai créé ici un dossier nommé SQL2012_SP1_CU3 où j’ai placé les fichiers d’installation du service pack1 de SQL Server 2012 et 2 cumulatives updates : CU1 et CU3

 

sp1_et_cu1_et_cu3

 

icon_arrow Il suffit ensuite d’utiliser les paramètres supplémentaires fournis avec SQL Server 2012 (/UpdateEnabled et /UpdateSource). J’effectue ici une installation en ligne de commande

 

image

 

icon_arrow Lorsque l’installation se lance on peut remarquer que l’installation détecte les mises à jour et ne prend que le service pack 1 et le dernier cumulative update (CU3)

 

install_gui_product_updates

 

Le cumulative update 3 correspond au KB 2812412 :

kb_cu3

 

icon_arrow Une fois l’installation terminée une petite vérification de la version :

 

result_after_install

 

Bonne installation !!

David BARBARIN (Mikedavem)
MVP SQL Server

A propos de l’erreur 33203 : SQL Server audit could not write to the security log

Mis en avant

Lors de la mise en place des audits de sécurité je me suis heurté à cette fameuse erreur 33203 sur une instance nommée qui indique explicitement que SQL Server ne peut pas écrire dan le journal de sécurité Windows.  Ma configuration est la suivante : SQL Server 2012 SP1  et Windows 2012 Server.

Je précise avant de commencer que les prérequis de fonctionnement des audits avec le journal de sécurité Windows sont respectés. La conséquence directe de l’erreur 33203 est qu’au évènement n’est enregistré dans le journal de sécurité Windows, ce qui est plutôt gênant pour des audits. De plus les journaux des erreurs Windows et SQL Server ne sont pas spécialement bavards quant à la cause de cette erreur.

 

image

 

Dans ce cas comment savoir ce qui empêche SQL Server d’écrire dans le journal ? Je dois dire que les outils sysinternals sont bien utiles dans ces moments et en particulier procmon.

Une capture procmon me donne ceci lorsque j’active un objet d’audit depuis SQL Server :

 

image

On peut remarquer ici que SQL Server tente un accès à la clé de registre HKLM\System\CurrentControlSet\Services\EventLog\Security et que cet accès lui est visiblement refusé. Un message est également inscrit dans le journal des erreurs SQL. Pas de souci, nous allons configurer les permissions adéquates sur cette clé de registre.

 

image

 

Le paramétrage des permissions a visiblement permis à l’instance SQL Server de créer une nouvelle clé de registre dans HKLM\System\CurrentControlSet\Services\EventLog\Security :

image

 

image

 

Me croyant sauvé, j’active mes audits mais je me heurte à une nouvelle erreur. Une nouvelle trace procmon me révèle le problème suivant :

 

image

 

SQL Server tente de lire le fichier C:\Windows\System32\LogFiles\Sum\Api.log mais encore un fois ce dernier se voit refuser l’accès. Le paramétrage en lecture seule du fichier Api.log me permet enfin d’activer mes audits et de valider que les évènements soient bien enregistrés dans le journal de sécurité Windows. Ce deuxième problème visiblement a été remonté chez Microsoft et est toujours d’actualité. A noter que je n’ai eu ce souci que pour mon instance nommé dans mon cas.

 

Quelques remarques supplémentaires :

  • Le fait d’enlever le compte de service SQL des permissions de la clé de registre HKLM\System\CurrentControlSet\Services\EventLog\Security ne semble plus être gênant à partir du moment où la nouvelle clé a été créé.
  • Il n’est pas possible cependant d’enlever les permissions sur le fichier C:\Windows\System32\LogFiles\Sum\Api.log sous peine d’avoir dans le journal des évènements Windows le type d’erreur suivant et plus d’évènement d’audit enregistré. A voir si le problème sera résolu plus tard par Microsoft (dans un CU4 peut être ?) avec Windows Server 2012. L’ensemble des problèmes répertoriés concerneraient Windows Server 2012.
  • Je ne pense pas que le problème soit lié à la version de SQL Server. Si j’ai le temps je testerai sur une version SQL Server 2008 R2 et mettrait à jour mon blog.

 

image

 

Bonne activation d’audit !! Sourire

 

David BARBARIN (Mikedavem)
MVP SQL Server

Problème d’utilisation de l’option WITH EXECUTE AS dans une procédure stockée avec les serveurs liés

Mis en avant

L’emprunt d’identité peut s’avérer nécessaire lorsque l’on commence à vouloir faire de la sécurité à un niveau granulaire relativement bas. Par exemple la politique de sécurité en vigueur peut nous contraindre à restreindre l’accès aux données via des procédures stockées. Cependant si ces données sont distantes et implique l’implémentation d’un serveur lié pour y avoir accès, cela peut donner matière à plus de réflexion. En effet, dans ce cas il va falloir donner les droits adéquates aux utilisateurs concernés sur le serveur distant pour accéder aux données, ce qui risque pour le coup d’augmenter la surface d’exposition. Un utilisateur A devra pouvoir exécuter une procédure stockée et sélectionner les données sur le serveur distant. L’utilisateur A peut par conséquent passer outre la procédure stockée et se connecter directement au serveur distant pour accéder aux données. Pour éviter cela on peut tout à fait utiliser le mécanisme d’emprunt d’identité dans une procédure stockée à l’aide de WITH EXECUTE AS et associer l’utilisateur dédié à cette tâche à un utilisateur sur le serveur distant. On bénéficie ainsi d’un contrôle d’accès beaucoup fort et maitrisé.

 

Le schéma ci-dessous illustre bien notre problématique :

 

icon_arrow Dans le 1er cas un mapping est nécessaire pour chaque utilisateur qui va vouloir accéder aux données du serveur distant Instance 2, ce qui signifie qu’il devra exister les mêmes logins sur le serveur distant Instance 2. Comme je l’ai évoqué au début cela implique également que les utilisateurs concernés pourront directement accéder aux données du serveur distant avec leurs informations de connexion.

 

image

 

icon_arrow Dans le 2ème cas nous mettons en place un mécanisme d’emprunt d’identité via l’option WITH EXECUTE AS USER dans la procédure stockée. L’idée ici est de n’autoriser que cet utilisateur à avoir accès aux données distantes.

 

image

 

La mise en place d’un tel mécanisme dans le contexte des serveurs liés nécessitent un certain paramétrage :

  • L’activation obligatoire de l’option de bases de données trustworthy. Malheureusement seule cette option est viable lorsqu’il s’agit d’accès inter instances. L’utilisation des certificats dans ce cas ne fonctionne pas.
  • Différer l’exécution de la procédure stockée concernée. Je n’ai pas trouvé d’article Microsoft sur le sujet mais simplement un item connect. C’est ce point que je vais détailler ici.

 

Si l’on utilise directement l’option WITH EXECUTE AS dans une procédure stockée de la manière suivante :

 

CREATE PROCEDURE dbo.GetRemoteData
WITH EXECUTE AS 'USER1'
AS

SELECT col1, col2
FROM [linked_server].[DATABASE].[schema].[TABLE]
GO

 

… avec l’appel suivant …

 

EXEC dbo.GetRemoteData

 

… il y a de grandes chances que cela ne fonctionne pas surtout si l’on a définit le contexte d’authentification de serveur lié suivant :

 

image

 

Dans ce cas seul le mapping défini pour l’utilisateur USER1 fonctionnera et aucun autre login ou aucun autre type d’authentification ne fonctionnera.

 

Si maintenant j’exécute ou je crée la procédure stockée dbo.GetRemoteData dans le contexte d’un utilisateur différent de l’utilisateur USER1 ayant les droits de création et d’exécution je peux me retrouver avec le message suivant :

 

image

 

Pourtant me direz-vous que nous avons bien défini l’emprunt d’identité dans la procédure stockée et qu’ici visiblement SQL Server n’est pas capable de trouver le mapping défini dans les options de sécurité du serveur lié. En réalité il faut bien comprendre ce qui se passe lorsqu’une procédure stockée est compilée et lorsque celle-ci est exécutée (run-time context). SQL Server compile une procédure stockée avec les credentials de l’appelant de la procédure et non ceux de l’utilisateur associée à l’emprunt d’identité. C’est pendant l’exécution de la procédure que le mécanisme d’emprunt d’identité jouera tout son rôle. Lorsqu’on accède aux données aux travers d’un serveur lié la compilation va générer l’erreur 7416 si l’appelant de la procédure n’a pas un mapping inter-instances configuré (SQL Server va vérifier lors de la compilation l’accès aux différents objets du serveur distant).

Pour contourner ce problème on peut user de 2 mécanismes qui permettent de différer l’exécution de la procédure stockée et de laisser le mécanisme d’emprunt d’identité opérer en premier lieu :

  • Créer une nouvelle procédure stockée qui va scinder l’exécution de notre procédure stockée initiale en 2 étapes
  • Encapsuler le code à exécuter de la procédure stockée avec EXEC( »), ce qui permettra au final de faire la même que dans la 1ère solution.

 

Par exemple :

CREATE PROCEDURE dbo.GetRemoteDataWithImpersonate
WITH EXECUTE AS 'USER1'  
AS

EXEC dbo.GetRemoteData
GO

ou encore :

CREATE PROCEDURE dbo.GetRemoteData    
WITH EXECUTE AS 'USER1'    
AS

EXEC('SELECT col1, col2 FROM [linked_server].[database].[schema].[table]')    
GO

 

Le choix de la méthode dépendra bien du contexte.

 

Bonne programmation !

David BARBARIN (Mikedavem)
MVP SQL Server

Prochain évènement GUSS le 24 avril – 19h00 : Webcast sur SQL Server 2012 AlwaysOn pour les fermes Sharepoint 2013

Mis en avant

J’aurai le plaisir d’animer le prochain évènement du GUSS sous un nouveau format. Le principe est simple : où que vous soyez, vous pouvez rejoindre le webcast en ligne avec le son, la vidéo et un chat pour poser des questions.

 

Ce webcast sera composé de 2 sujets de 30 minutes :

 

icon_arrow  Always-On : rappel des bases
La première session rappellera le fonctionnement et les bases de la Haute-Disponibilité avec AlwaysOn (avantages, architecture, groupes de disponibilités, type de réplications de données, etc.).

 

icon_arrow AlwaysOn dans les fermes sharepoint 2013
Mise en pratique avec une implémentation d’AlwaysOn avec SharePoint, produit très consommateur de SQL Server et avec des topologies souvent complexes. L’idée ici est d’avoir une vision beaucoup plus orientée base de données et analyser les avantages mais aussi les impacts à utiliser AlwaysOn avec Sharepoint (création / supression d’applications, authentification, utilisation des connexions readonly, maintenance des bases de données, monitoring …)

 

Les informations de connexion vous seront communiqués la veille sur le site du GUSS. En espérant vous voir nombreux !

 

David BARBARIN (Mikedavem)
MVP SQL Server