SQL Server 2008: How crash-safe is a CLR Stored Procedure that loads unmanaged libraries

坚强是说给别人听的谎言 提交于 2019-12-17 20:39:04

问题


We've got a regular (i.e. not extended) stored procedure in SQL Server 2000 that calls an external exe. That exe, in turn, loads a .dll that came from an SDK and calls some procedures from it (i.e. Init, DoStuff, Shutdown).

The only reason we have this external exe thing is because we didn't want to create an extended stored procedure that would call the .dll. We believed that if the dll crashes (an unlikely event but still) then the SQL Server process will crash as well which is not what we wanted. With an external exe, only that exe would crash.

Now, we're upgrading to SQL Server 2008 and considering creating a CLR stored procedure that calls the thing and therefore getting rid of the exe. This SP would be marked as UNSAFE, of course. The question therefor is, is it safe (safer, safe enough etc.) to do it that way as compared to the extended SP approach?

The only relevant thing I've hunted down on BOL is:

Specifying UNSAFE allows the code in the assembly to perform illegal operations against the SQL Server process space, and hence can potentially compromise the robustness and scalability of SQL Server

, but I'm not sure whether it answers my question as I'm not after 'robustness and scalability', rather after stability and keeping the thing up and running.

PS: We want to get rid of the exe because it causes inconviniences when managing SP permissions (you know, that stuff that suddenly applies to you if you call a SP that contains xp_cmdshell).


回答1:


Since this code was originally used with extended stored procedures, it sounds like it is unmanaged code. Bugs in unmanaged code can easily crash your process.

CLR integration is much more robust than extended stored procedures, but the code still runs in-process, so errors can take down or corrupt SQL Server. (For comparison, in theory, a SAFE CLR routine won't be able to corrupt SQL Server although even it could cause problems that reduce your server's availability without totally taking down the SQL Server.)

Basically, the only ways to not crash SQL Server in this scenario are:

  1. Avoid using the functionality that crashes.
  2. Fix the buggy code.
  3. Run the code in a separate process (launch an executable, call a Windows service, call a web service, etc.). You can write a managed .NET DLL to perform this interaction. Most likely, you will still need to load it UNSAFE, but--if it is written properly--in reality it can be quite safe.



回答2:


The question therefor is, is it safe (safer, safe enough etc.) to do it that way as compared to the extended SP approach?

Generally yes. I mean, if you are shelling out to an OS process, then you are shelling out to an OS process. I don't see how using the Extended Stored Procedure API to do that would necessarily be safer than the SQLCLR API, especially when the thing that might crash is an OS process, sitting outside of the database.

Of course, I am not certain about the XP API since I have not used it, but I do know the following:

  • The XP API is deprecated and the recommendation is that all new projects that could be done in either of those technologies should be done in SQLCLR.
  • The SQLCLR does allow for more granular permissions than those other two, including the ability to do Impersonation (if the Login executing the SQLCLR objects is a Windows Login).
  • The SQLCLR API is separated process/memory-wise by both Database and Assembly Owner (i.e. the User specified by the AUTHORIZATION clause). Hence you can have a problem with an Assembly in one DB without it affecting SQLCLR objects in other DBs (or even in the same DB if there are Assemblies owned by another User, though in practice this probably rarely is ever the case as most people just use the default which is dbo).

I'm not sure whether it answers my question as I'm not after 'robustness and scalability', rather after stability and keeping the thing up and running.

Well, there are certainly things you can do within SQLCLR when the Assembly is set to UNSAFE:

  • potentially write to the Registry (depending on the access granted to the Log On As account running the SQL Server process, or the Login executing the SQLCLR function IF Impersonation is enabled and it is a Windows Login).
  • potentially write to the file system
  • potentially interact with processes running on the system
  • share memory with other SQL Server SPIDs (i.e. Sessions) executing functions from the same Assembly (meaning that specific Assembly, in that DB, owned by that User). This probably eludes people the most as it is unexpected when you are used to Console apps and Windows apps having their own individual memory spaces, yet here, because it is a single AppDomain per Assembly per DB per Owner, all sessions executing that code do share all static variables. A lot of code is written with the assumption that the AppDomain is private and so storing values in static variables is efficient as it caches the value, but in SQLCLR, you can get unexpected behavior if two processes are overwriting each other's values and reading the other session's value.
  • potential memory leaks. The Host Protection Attributes attempt to prevent you from using built-in .NET functionality that could do this, such as using TimeZoneInfo to convert times between TimeZoneIDs, but Host Protection Attributes are not enforced on UNSAFE Assemblies.
  • It is possible that the thread running the SQLCLR method is handled differently when executing UNSAFE / FullTrust code (Cooperative Multitasking vs Preemptive). I thought I had read that UNSAFE threads are managed differently, but am not sure where I read it and am looking for the source.

But all of the above being said, if you are calling an external EXE, it has its own AppDomain.

So, what you can do is either:

  1. continue to call the EXE using a SQLCLR wrapper to Process.Start(). This gives you both the process/memory separation and the ability to more easily control permissions to a single Stored Procedure that will only ever call this EXE and nobody can change it (at least not without changing that SQLCLR code and reinstalling the Assembly).

  2. install an instance of SQL Server Express on the same machine, load the SQLCLR objects there, and create Linked Servers in both directions (from current SQL Server instance to and from the new SQL Server Express instance) so you can communicate easily between them. This will allow you to quarantine the SQLCLR execution and keep it away from the main SQL Server process.

Of course, that all being said, how much of a concern is this really? Meaning, how likely is it that a process fully crashes and takes down everything with it? Sure, it's not impossible, but usually a crash would take down just the AppDomain and not the CLR host itself. I would think it far more likely that code that doesn't crash but is written poorly and consumes too much memory and/or CPU would be the problem people run into.



来源:https://stackoverflow.com/questions/752357/sql-server-2008-how-crash-safe-is-a-clr-stored-procedure-that-loads-unmanaged-l

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!