source

세션 잠금으로 인해 ASP가 발생합니다.웹 사이트 속도 저하

lovecheck 2023. 5. 7. 11:35
반응형

세션 잠금으로 인해 ASP가 발생합니다.웹 사이트 속도 저하

ASP의 모든 요청을 방금 발견했습니다.Net 웹 응용 프로그램은 요청을 시작할 때 세션 잠금을 받은 다음 요청이 끝날 때 해제합니다!

처음에 제가 그랬던 것처럼, 이것이 여러분에게 미치는 영향이 상실되는 경우, 이것은 기본적으로 다음을 의미합니다.

  • ASP라면 언제든지.인터넷 웹 페이지를 로드하는 데 시간이 오래 걸리고(데이터베이스 호출 속도가 느려서인지 몰라도), 사용자는 기다리는 것에 싫증이 나서 다른 페이지로 이동하기로 결정하지만 그럴 없습니다!ASP.Net session lock은 새 페이지 요청이 원본 요청이 고통스러울 정도로 느린 로드를 마칠 때까지 강제로 기다립니다.맞아요.

  • 언제든지 anUpdatePanel 속도가, 는 " ▁the" 앞의 다른 합니다.UpdatePanel업데이트 완료...그들은 할 수 없어요!ASP.Net session lock은 새 페이지 요청이 원본 요청이 고통스러울 정도로 느린 로드를 마칠 때까지 강제로 기다립니다.이중으로 으악!

그렇다면 선택지는 무엇일까요?지금까지 생각해 낸 것은 다음과 같습니다.

  • 정의 SessionStateDataStore어떤 ASP.은 지원합니다 있는 것이 것을 , 이 되기 .저는 복사할 수 있는 것이 너무 많은 것을 찾지 못했고, 그것은 위험이 높고 엉망이 되기 쉬운 것처럼 보입니다.
  • 진행 중인 모든 요청을 추적하고 동일한 사용자로부터 요청이 들어오면 원래 요청을 취소합니다.좀 극단적으로 보이지만, 효과가 있을 것 같습니다.
  • 세션 사용 안 함!사용자에게 어떤 상태가 필요할 때, 그냥 사용할 수 있습니다.Cache대신, 인증된 사용자 이름의 주요 항목 또는 기타 등등.다시 말하자면 좀 극단적인 것 같습니다.

저는 ASP를 정말 믿을 수 없습니다.넷 마이크로소프트 팀은 버전 4.0의 프레임워크에 엄청난 성능 병목 현상을 남겼을 것입니다. 제가 뭔가를 놓치고 있는 것일까요?사용하는 것이 얼마나 어려울까요?ThreadSafe세션을 위한 수집?

페이지에서 세션 변수를 수정하지 않으면 이 잠금을 대부분 해제할 수 있습니다.

<% @Page EnableSessionState="ReadOnly" %>

페이지가 세션 변수를 읽지 않으면 해당 페이지에 대해 이 잠금을 완전히 해제할 수 있습니다.

<% @Page EnableSessionState="False" %>

세션 변수를 사용하는 페이지가 없으면 web.config에서 세션 상태를 해제하십시오.

<sessionState mode="Off" />

궁금한 게 있는데, "ThreadSafe 컬렉션"이 잠금 장치를 사용하지 않는다면 스레드 세이프가 되기 위해 어떤 역할을 할 것이라고 생각하십니까?

편집: "이 자물쇠의 대부분에서 선택"이라는 의미로 설명해야 할 것 같습니다.지정된 세션에 대해 서로 차단하지 않고 동시에 임의의 수의 읽기 전용 세션 페이지 또는 세션 없음 페이지를 처리할 수 있습니다.그러나 읽기-쓰기-세션 페이지는 모든 읽기 전용 요청이 완료될 때까지 처리를 시작할 수 없으며, 페이지가 실행되는 동안 일관성을 유지하려면 해당 사용자의 세션에 대한 단독 액세스 권한이 있어야 합니다.개별 값을 잠그면 작동하지 않습니다. 한 페이지가 관련 값 집합을 그룹으로 변경하면 어떻게 됩니까?동시에 실행되는 다른 페이지에서 사용자의 세션 변수를 일관되게 볼 수 있도록 하려면 어떻게 해야 합니까?

가능하면 세션 변수를 설정한 후 수정을 최소화하는 것이 좋습니다.이렇게 하면 대부분의 페이지를 읽기 전용 세션 페이지로 만들 수 있으므로 동일한 사용자의 여러 동시 요청이 서로를 차단하지 않을 가능성이 높아집니다.

좋아요, 조엘 뮬러에게 그의 모든 의견에 대해 큰 제안을 했습니다.저의 궁극적인 해결책은 이 MSDN 문서 끝에 자세히 설명된 사용자 지정 세션 상태 모듈을 사용하는 것이었습니다.

http://msdn.microsoft.com/en-us/library/system.web.sessionstate.sessionstateutility.aspx

다음과 같습니다.

  • 구현 속도가 매우 빠름(실제로는 공급자 경로를 따라가는 것보다
  • 표준 ASP를 많이 사용했습니다.즉시 사용 가능한 Net 세션 처리(SessionStateUtility 클래스를 통해)

이로 인해 애플리케이션에 대한 "스냅니스" 느낌이 크게 달라졌습니다.ASP의 맞춤형 구현이 아직도 믿기지 않습니다.Net Session은 전체 요청에 대해 세션을 잠급니다.이것은 웹사이트에 엄청난 양의 부진을 더해줍니다.제가 해야 했던 온라인 조사의 양으로 판단하면 (그리고 정말 경험이 풍부한 여러 ASP와의 대화).넷 개발자), 많은 사람들이 이 문제를 경험했지만, 원인의 진상을 규명한 사람은 거의 없습니다.아마도 나는 Scott Gu에게 편지를 쓸 것입니다...

저는 Angies List를 사용하기 시작했습니다.Redis.RedisSessionStateModule은 저장을 위해 (매우 빠른) Redis 서버를 사용하는 것 외에 (Windows 포트를 사용하고 있지만) MSOpenTech 포트도 있습니다.

제 생각에, 당신의 애플리케이션이 합리적인 방식으로 구성되어 있다면, 이것은 문제가 되지 않습니다.세션의 일부로 잠금 상태의 일관된 데이터가 실제로 필요한 경우 잠금/동시성 검사를 직접 구현해야 합니다.

모든 ASP를 결정하는 MS.제 생각에, 나쁜 애플리케이션 설계를 처리하기 위해 NET 세션은 기본적으로 잠겨야 합니다.특히 대부분의 개발자가 세션이 잠겨 있다는 사실을 깨닫지 못한 것처럼 보이기 때문에 가능한 한 읽기 전용 세션 상태를 수행할 수 있도록 앱을 구성해야 합니다(가능한 경우).

저는 이 스레드에 게시된 링크를 기반으로 라이브러리를 준비했습니다.MSDN과 코드 프로젝트의 예를 사용합니다.제임스 덕분에.

Joel Mueller의 조언에 따라 수정도 했습니다.

코드는 다음과(와)

https://github.com/dermeister0/LockFreeSessionState

해시 테이블 모듈:

Install-Package Heavysoft.LockFreeSessionState.HashTable

ScaleOut StateServer 모듈:

Install-Package Heavysoft.LockFreeSessionState.Soss

사용자 지정 모듈:

Install-Package Heavysoft.LockFreeSessionState.Common

Memcached 또는 Redis 지원을 구현하려면 이 패키지를 설치합니다.그런 다음 LockFreeSessionStateModule 클래스를 상속하고 추상 메서드를 구현합니다.

코드는 아직 프로덕션에서 테스트되지 않았습니다.또한 오류 처리를 개선해야 합니다.현재 구현에서는 예외가 발견되지 않습니다.

Redis를 사용하는 일부 잠금 없는 세션 공급자:

  • https://github.com/angieslist/AL-Redis (이 스레드에서 gregmac에 의해 제안됨)
  • https://github.com/welegan/RedisSessionProvider (NuGet: RedisSessionProvider)
  • https://github.com/efaruk/playground/tree/master/UnlockedStateProvider (NuGet: UnlockedStateProvider.레디스)

된 업이트내사경용우는을 Microsoft.Web.RedisSessionStateProvider으로부터 시작)3.0.2) 이 정보를 에 추가할 수 있습니다.web.config동시 세션을 허용합니다.

<appSettings>
    <add key="aspnet:AllowConcurrentRequestsPerSession" value="true"/>
</appSettings>

원천

애플리케이션에 특별한 필요가 없는 한, 두 가지 접근 방식이 있다고 생각합니다.

  1. 세션을 전혀 사용하지 않음
  2. 세션을 그대로 사용하고 Joel이 언급한 대로 미세 조정을 수행합니다.

현재 요청이 완료될 때까지 모든 세션 변수가 다른 활성 요청에서 변경되지 않는다는 것을 알 수 있는 방식으로 세션은 스레드 세이프일 뿐만 아니라 상태 세이프입니다.이 작업을 수행하려면 현재 요청이 완료될 때까지 세션이 잠겨 있는지 확인해야 합니다.

여러 가지 방법으로 세션과 같은 동작을 만들 수 있지만 현재 세션을 잠그지 않으면 '세션'이 되지 않습니다.

당신이 언급한 특정 문제에 대해서는 HttpContext를 확인해야 한다고 생각합니다.현재.반응.클라이언트가 연결되어 있습니다.이것은 불필요한 실행을 방지하고 클라이언트에서 대기하는 데 유용할 수 있지만, 비동기식이 아닌 풀링 방식으로만 사용할 수 있기 때문에 이 문제를 완전히 해결할 수는 없습니다.

ASPNET MVC의 경우 다음을 수행했습니다.

  1. 를 설정합니다.SessionStateBehavior.ReadOnly재정의를 통해 모든 컨트롤러의 작업에 대해DefaultControllerFactory
  2. 에 기록해야 의 경우 하여 "" " " " " " 으로 설정합니다.SessionStateBehavior.Required

하고 재정의합니다.GetControllerSessionBehavior.

    protected override SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
    {
        var DefaultSessionStateBehaviour = SessionStateBehaviour.ReadOnly;

        if (controllerType == null)
            return DefaultSessionStateBehaviour;

        var isRequireSessionWrite =
            controllerType.GetCustomAttributes<AcquireSessionLock>(inherit: true).FirstOrDefault() != null;

        if (isRequireSessionWrite)
            return SessionStateBehavior.Required;

        var actionName = requestContext.RouteData.Values["action"].ToString();
        MethodInfo actionMethodInfo;

        try
        {
            actionMethodInfo = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
        }
        catch (AmbiguousMatchException)
        {
            var httpRequestTypeAttr = GetHttpRequestTypeAttr(requestContext.HttpContext.Request.HttpMethod);

            actionMethodInfo =
                controllerType.GetMethods().FirstOrDefault(
                    mi => mi.Name.Equals(actionName, StringComparison.CurrentCultureIgnoreCase) && mi.GetCustomAttributes(httpRequestTypeAttr, false).Length > 0);
        }

        if (actionMethodInfo == null)
            return DefaultSessionStateBehaviour;

        isRequireSessionWrite = actionMethodInfo.GetCustomAttributes<AcquireSessionLock>(inherit: false).FirstOrDefault() != null;

         return isRequireSessionWrite ? SessionStateBehavior.Required : DefaultSessionStateBehaviour;
    }

    private static Type GetHttpRequestTypeAttr(string httpMethod) 
    {
        switch (httpMethod)
        {
            case "GET":
                return typeof(HttpGetAttribute);
            case "POST":
                return typeof(HttpPostAttribute);
            case "PUT":
                return typeof(HttpPutAttribute);
            case "DELETE":
                return typeof(HttpDeleteAttribute);
            case "HEAD":
                return typeof(HttpHeadAttribute);
            case "PATCH":
                return typeof(HttpPatchAttribute);
            case "OPTIONS":
                return typeof(HttpOptionsAttribute);
        }

        throw new NotSupportedException("unable to determine http method");
    }

세션 잠금 특성 획득

[AttributeUsage(AttributeTargets.Method)]
public sealed class AcquireSessionLock : Attribute
{ }

를 생성컨연에 합니다.global.asax.cs

ControllerBuilder.Current.SetControllerFactory(typeof(DefaultReadOnlySessionStateControllerFactory));

이제, 우리는 둘 다 가질 수 있습니다.read-only그리고.read-write " " " "로 표시합니다.Controller.

public class TestController : Controller 
{
    [AcquireSessionLock]
    public ActionResult WriteSession()
    {
        var timeNow = DateTimeOffset.UtcNow.ToString();
        Session["key"] = timeNow;
        return Json(timeNow, JsonRequestBehavior.AllowGet);
    }

    public ActionResult ReadSession()
    {
        var timeNow = Session["key"];
        return Json(timeNow ?? "empty", JsonRequestBehavior.AllowGet);
    }
}

될 수 예외도 보장하기 ). 는 주의를 기울여야 합니다.AcquireSessionLock세션 상태를 기록해야 하는 컨트롤러의 작업입니다.

컨트롤러의 세션 상태를 읽기 전용 또는 사용 안 함으로 표시하면 문제가 해결됩니다.

컨트롤러를 다음 특성으로 장식하여 읽기 전용으로 표시할 수 있습니다.

[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]

제도웹.세션 상태.SessionStateBehavior 열거형의 값은 다음과 같습니다.

  • 체납
  • 사용 안 함
  • 읽기 전용
  • 필수의

세션당 동시 요청 허용에 대한 이 답변은 훌륭하지만 다음과 같은 몇 가지 중요한 세부 정보가 누락되어 있습니다.

  1. 세션당 동시 요청을 허용하는 설정은 최신 ASP에서 구현됩니다.유형의 NET 세션 상태 모듈Microsoft.AspNet.SessionState.SessionStateModuleAsync이 설정은 이 모듈로 작업할 수 있는 모든 공급자에 대해 지원됩니다.
  2. 모듈은 다음과 같습니다.System.Web.SessionState.SessionStateModule에서는 이 기능을 지원하지 않습니다.
  3. 세션 상태 사용이 스레드 안전한지 확인하거나 세션에서 동시성 문제가 발생할 수 있습니다.

이 기능을 활성화하기 위한 요약:

동시 요청 허용:

<appSettings>
    <add key="aspnet:AllowConcurrentRequestsPerSession" value="true"/>
</appSettings>

새로운 세션 상태 모듈이 사용되는지 확인합니다.

<system.webServer>
  <modules>
    <!-- remove the existing Session state module -->
    <remove name="Session" />
    <add name="Session" preCondition="integratedMode" type="Microsoft.AspNet.SessionState.SessionStateModuleAsync, Microsoft.AspNet.SessionState.SessionStateModule, Version=1.1.0.0, Culture=neutral" />
  </modules>
</system.webServer>

이 문제가 있는 모든 사용자를 돕기 위해(같은 세션에서 다른 요청을 실행할 때 요청 잠금)...

오늘 저는 이 문제를 해결하기 시작했고, 몇 시간의 연구 끝에, 저는 그것을 제거함으로써 해결했습니다.Session_Startglobal.asax 파일의 method(비우더라도).

이것은 제가 테스트한 모든 프로젝트에서 작동합니다.

사용 가능한 모든 옵션을 고심한 끝에 JWT 토큰 기반 SessionStore 공급자를 작성하게 되었습니다(세션은 쿠키 내부로 이동하며 백엔드 스토리지는 필요하지 않음).

http://www.drupalonwindows.com/en/content/token-sessionstate

장점:

  • 드롭인 교체. 코드를 변경할 필요
  • 세션 스토리지 백엔드가 필요하지 않으므로 다른 중앙 집중식 저장소보다 확장성이 뛰어납니다.
  • 세션 스토리지에서 데이터를 검색할 필요가 없으므로 다른 세션 스토리지보다 빠름
  • 세션 저장소에 서버 리소스를 사용하지 않습니다.
  • 기본 비차단 구현: 동시 요청은 서로 차단하지 않고 세션에서 잠금을 유지합니다.
  • 응용프로그램 수평 확장: 세션 데이터는 요청 자체와 함께 이동하므로 세션 공유에 대한 걱정 없이 여러 웹 헤드를 가질 수 있습니다.

이 문제가 발생했지만 도움이 되지 않는 솔루션을 발견한 Mono 사용자의 경우 잘못한 것이 없습니다.
Mono(Issue #19618)에 다음과 같은 버그가 있습니다.SessionStateBehavior에쓸는에 SessionStateModule그래서 당신이 설정하는 것은 문제가 없습니다.SessionStateBehaviorWeb.config/pages,Application_BeginRequest합니다.Controller 는또.Action아무 것도 안 됩니다.나는 노력했다.

하는 논리은 호잠을금(그출))GetItemGetItemExclusiveSessionStateModule)에는 한 가지 제한이 있습니다.HttpHandler 인터페이스 " " " 를 .IReadOnlySessionState.

만의 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅠSessionStateModule저는 다른 접근 방식을 취했습니다.


고려할 사항:

// Custom handler that derives from MvcHandler which implements IReadOnlySessionState
public class MvcReadOnlyHandler : MvcHandler, IReadOnlySessionState
{
    public MvcReadOnlyHandler(RequestContext requestContext) : base(requestContext)
    {
    }
}
// Custom RouteHandler that derives from `MvcRouteHandler` which
// returns our very own `MvcReadOnlyHandler`
public class MvcConcurrentRouteHandler : MvcRouteHandler
{
    protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new MvcReadOnlyHandler(requestContext);
    }
}
// On Global.asax.cs Application_Start, after all the Routes and Areas are registered
// change only the route handler to the new concurrent route handler
foreach (var routeBase in RouteTable.Routes)
{
    // Check if the route handler is of type MvcRouteHandler
    if (routeBase is Route { RouteHandler: MvcRouteHandler _ } route)
    {
         // Replace the route handler
         route.RouteHandler = new MvcConcurrentRouteHandler();
    }
}

는 이터라는구다니를 합니다.IReadOnlySessionState에 잠금이 없습니다.

버그가 해결되면 제 솔루션이 중복되기를 바라지만, 그때까지는 누군가에게 도움이 되기를 바랍니다.


중요한 참고:이 솔루션을 사용하면 기본적으로 세션에 항목을 저장하는 것이 안전하지 않습니다. 저는 이 기능을 사용하지 않기 때문에 작동합니다.읽기 전용은 쓰기를 금지하지 않고 잠기지 않으므로 항목을 추가할 수 있습니다.
글쓰기를 , 방법을 할 수 .MapRouteRouteCollection새 라우터를 사용하여 잠기지 않는 경로를 등록합니다.당신은 당신의 경로를 새로운 것에 등록할 수 있습니다.MvcConcurrentRouteHandler라우터 또는 기존 라우터에 대한 쓰기 작업입니다.

언급URL : https://stackoverflow.com/questions/3629709/session-lock-causes-asp-net-websites-to-be-slow

반응형