Mon application s'exĂ©cute sur .NET Framework 4.7.2 et exĂ©cutait une ancienne version 3.0.7 de Quartz depuis plus d'un an avec une faible utilisation du processeur, et il y a quelques semaines, nous avons mis Ă niveau Quartz vers 3.2.3 et nous avons remarquĂ© une augmentation immĂ©diate de 40 % du processeur. car cette requĂȘte est exĂ©cutĂ©e beaucoup plus souvent avec la nouvelle version.
SĂLECTIONNER *
DE QRTZ_LOCKS AVEC (UPDLOCK, ROWLOCK)
WHERE SCHED_NAME = @schedulerName
ET LOCK_NAME = @lockName
Version utilisée
Version : 3.2.3
Reproduire
Je n'ai pas de code à reproduire, mais mon application crée des tùches simples et à un moment donné, elle en a 10 exécutées sur 4 instances de VM différentes.
Comportement attendu
Le processeur doit rester tel qu'il Ă©tait avec l'ancienne version.
btw, il n'y a pas d'erreurs signalées par Quartz ou notre application, mais c'est le seul effet secondaire que nous voyons avec la version 3.2.3
Pouvez-vous publier la configuration d'usine de votre planificateur (suppression des informations d'identification, etc.)Â ?
Sûr.
==== processeurOrdonnanceur ====
<scheduler name="processorScheduler">
<quartz>
<property key="quartz.scheduler.instanceName" value="ProcessorScheduler" />
<property key="quartz.scheduler.instanceId" value="AUTO" />
<property key="quartz.scheduler.idleWaitTime" value="1000" />
<property key="quartz.scheduler.exporter.type" value="Quartz.Simpl.RemotingSchedulerExporter, Quartz" />
<property key="quartz.scheduler.exporter.port" value="1111" />
<property key="quartz.scheduler.exporter.bindName" value="ProcessorScheduler" />
<property key="quartz.scheduler.exporter.channelType" value="tcp" />
<property key="quartz.scheduler.exporter.channelName" value="httpQuartz" />
<property key="quartz.threadPool.type" value="Quartz.Simpl.DefaultThreadPool, Quartz" />
<property key="quartz.threadPool.threadCount" value="20" />
<property key="quartz.jobStore.type" value="Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" />
<property key="quartz.serializer.type" value="binary" />
<property key="quartz.jobStore.clustered" value="true" />
<property key="quartz.jobStore.clusterCheckinInterval" value="1000" />
<property key="quartz.jobStore.misfireThreshold" value="60000" />
<property key="quartz.jobStore.dataSource" value="default" />
<property key="quartz.jobStore.driverDelegateType" value="Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz" />
<property key="quartz.jobStore.tablePrefix" value="QRTZ_" />
<property key="quartz.jobStore.useProperties" value="true" />
<property key="quartz.dataSource.default.connectionString" value="Server=xxx;Database=quartz;user id=xxx;PWD=xxx;" />
<property key="quartz.dataSource.default.provider" value="SqlServer" />
</quartz>
</scheduler>
<scheduler name="notificationScheduler">
<quartz>
<property key="quartz.scheduler.instanceName" value="notificationScheduler" />
<property key="quartz.scheduler.instanceId" value="notificationSchedulerInstance" />
<property key="quartz.scheduler.proxy" value="true" />
<property key="quartz.scheduler.proxy.address" value="tcp://xxx:2222/notificationScheduler" />
<property key="quartz.threadPool.type" value="Quartz.Simpl.DefaultThreadPool, Quartz" />
<property key="quartz.jobStore.type" value="Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" />
<property key="quartz.jobStore.misfireThreshold" value="60000" />
<property key="quartz.jobStore.dataSource" value="default" />
<property key="quartz.jobStore.driverDelegateType" value="Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz" />
<property key="quartz.jobStore.lockHandler.type" value="Quartz.Impl.AdoJobStore.UpdateLockRowSemaphore, Quartz" />
<property key="quartz.jobStore.tablePrefix" value="QRTZ_" />
<property key="quartz.jobStore.useProperties" value="true" />
</quartz>
</scheduler>
==== planificateur de notifications ====
<scheduler name="notificationScheduler">
<quartz>
<property key="quartz.scheduler.instanceName" value="notificationScheduler" />
<property key="quartz.scheduler.instanceId" value="AUTO" />
<property key="quartz.scheduler.idleWaitTime" value="1000" />
<property key="quartz.scheduler.exporter.type" value="Quartz.Simpl.RemotingSchedulerExporter, Quartz" />
<property key="quartz.scheduler.exporter.port" value="2222" />
<property key="quartz.scheduler.exporter.bindName" value="notificationScheduler" />
<property key="quartz.scheduler.exporter.channelType" value="tcp" />
<property key="quartz.scheduler.exporter.channelName" value="httpQuartz" />
<property key="quartz.threadPool.type" value="Quartz.Simpl.DefaultThreadPool, Quartz" />
<property key="quartz.threadPool.threadCount" value="20" />
<property key="quartz.jobStore.type" value="Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" />
<property key="quartz.serializer.type" value="binary" />
<property key="quartz.jobStore.clustered" value="true" />
<property key="quartz.jobStore.clusterCheckinInterval" value="1000" />
<property key="quartz.jobStore.misfireThreshold" value="60000" />
<property key="quartz.jobStore.dataSource" value="default" />
<property key="quartz.jobStore.driverDelegateType" value="Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz" />
<property key="quartz.jobStore.tablePrefix" value="QRTZ_" />
<property key="quartz.jobStore.useProperties" value="true" />
<property key="quartz.dataSource.default.connectionString" value="Server=xxx;Database=quartz;user id=xxx;PWD=xxx;" />
<property key="quartz.dataSource.default.provider" value="SqlServer" />
</quartz>
</scheduler>
J'aurai besoin de temps pour enquĂȘter, mais je suppose que le plus grand changement a Ă©tĂ© que la requĂȘte a Ă©tĂ© paramĂ©trĂ©e, ce qui donne Ă©galement l'impression d'ĂȘtre exĂ©cutĂ©e deux fois plus frĂ©quemment si vous avez deux planificateurs distincts (auparavant, il y avait une chaĂźne SQL diffĂ©rente pour chacun de eux).
C'est exact, j'ai plusieurs planificateurs qui ont tous des configurations similaires Ă celles ci-dessus.
Merci de l'avoir examiné.
Salut Marko, touchant la base pour toute mise à jour ?
J'espĂšre avoir le temps de travailler avec ce week-end. Je n'ai rien trouvĂ© d'Ă©vident provoquant une telle rĂ©gression des performances, mais je pense qu'il y a quelque chose entre 2.x et 3.x qui peut ĂȘtre amĂ©liorĂ©.
Salut Marko, as-tu eu la monnaie de jeter un Ćil Ă ce pote ?
DĂ©solĂ©, pas de gros gains pour l'instant. J'en ai discutĂ© avec SQL Server DBA et il n'a trouvĂ© aucune raison Ă©vidente en testant, donc cela ne devrait pas ĂȘtre du cĂŽtĂ© de la base de donnĂ©es car il s'exĂ©cute sur la mĂȘme page de base de donnĂ©es qui devrait ĂȘtre super rapide (petit nombre de lignes, deux colonnes) . Si vous avez le temps de profiler pour identifier quelque chose d'Ă©vident qui me manque, ce serait super.
Malheureusement, nous ne pouvons pas établir de profil. Mais, j'ai une autre idée à partager avec vous.
Avant le jour oĂč nous avons publiĂ© notre application avec Quartz mis Ă jour, cette requĂȘte Ă©tait exĂ©cutĂ©e 250 000 fois par jour. Juste aprĂšs la sortie de Quartz v3.0.7, les temps d'exĂ©cution des requĂȘtes sont passĂ©s Ă 350 000 fois par jour (un saut de 125 000). Notre trafic de donnĂ©es d'application n'a pas changĂ© du tout.
De plus, nous avons remarquĂ© que votre requĂȘte fait UPDLOCK, ROWLOCK sur une instruction SELECT, une raison pour laquelle elle doit le faire lorsqu'elle n'est pas mise Ă jour ? Je pense que si vous changez cela en NOLOCK, ce serait mieux.
SĂLECTIONNER *
DE QRTZ_LOCKS AVEC (UPDLOCK, ROWLOCK)
WHERE SCHED_NAME = @schedulerName
ET LOCK_NAME = @lockName
Quelque chose dans la v3.0.7 fait que cette requĂȘte s'exĂ©cute plus souvent.
Je viens de parler Ă nouveau Ă mon administrateur de base de donnĂ©es et il a creusĂ© un peu plus et dĂ©couvert dans l'ancienne version que cette requĂȘte UPDATE Ă©tait utilisĂ©e pour ĂȘtre exĂ©cutĂ©e, et depuis la mise Ă niveau, cette requĂȘte a disparu et le nouveau SELECT ci-dessus est apparu.
Notez Ă©galement que Sched_name sortait sous forme de texte et non de paramĂštre.
( @lockName nvarchar(14))
METTRE Ă JOUR QRTZ_LOCKS
DĂFINIR LOCK_NAME = LOCK_NAME
WHERE SCHED_NAME = 'MaintenanceScheduler' AND LOCK_NAME = @lockName
Et l'ancienne instruction SELECT Ă©tait celle-ci par rapport Ă la nouvelle.
Avant le 27 janvier
( @lockName nvarchar(14))
SELECT * FROM QRTZ_LOCKS AVEC (UPDLOCK, ROWLOCK)
WHERE SCHED_NAME = 'Planificateur de maintenance'
ET LOCK_NAME = @lockName
J'espĂšre que cela t'aides.
Merci pour la mise Ă jour et les informations.
De plus, nous avons remarquĂ© que votre requĂȘte fait UPDLOCK, ROWLOCK sur une instruction SELECT, une raison pour laquelle elle doit le faire lorsqu'elle n'est pas mise Ă jour ? Je pense que si vous changez cela en NOLOCK, ce serait mieux.
Cela signifierait qu'il n'y aurait pas de verrous pour se protĂ©ger des accĂšs concurrents, donc je n'irais pas lĂ -bas đ
Notez Ă©galement que Sched_name sortait sous forme de texte et non de paramĂštre.
C'est le comportement exact qui Ă©tait prĂ©vu aprĂšs la fusion de #818. Vous devriez maintenant voir beaucoup plus de requĂȘtes avec ce SQL exact si vous avez plusieurs planificateurs, ils utilisent tous le mĂȘme plan de requĂȘte grĂące Ă l'utilisation du paramĂštre de requĂȘte au lieu de coder en dur le nom du planificateur dans la requĂȘte, ce qui entraĂźne des plans diffĂ©rents.
Relisez votre configuration notificationScheduler
 :
<property key="quartz.jobStore.lockHandler.type" value="Quartz.Impl.AdoJobStore.UpdateLockRowSemaphore, Quartz" />
Cela l'empĂȘchera d'utiliser l'instruction SQL optimisĂ©e destinĂ©e Ă SQL Server. Voir https://github.com/quartznet/quartznet/blob/f612e3f66ab27e221b5632269ef5c25c0fe8bcc5/src/Quartz/Impl/AdoJobStore/JobStoreSupport.cs#L492 -L521 pour la logique.
J'ai supprimé cette propriété et également mis à niveau vers la derniÚre version, vous permettra de savoir comment il se comporte.
Salut Marko, juste une mise Ă jour. Le processeur est revenu Ă un comportement normal aprĂšs les mises Ă jour ci-dessus.
Merci pour ton aide l'ami.
Super à entendre, merci d'avoir bouclé la boucle.