11

db에 연결하기 위해 많은 모델을 사용했습니다. 마지막 프로젝트에서는 C #및 amp; 엔티티 프레임 워크, 나는 db 연결에 대한 정적 클래스를 만들었지 만 열 개 이상의 연결 요청이 함께 오면 10-15 개 이상의 요청이 오면 오류가 발생합니다. 모든 정적 메서드와 클래스를 제거했습니다.

이제 나는 알고 싶다.

연결에 가장 적합한 모델은 무엇입니까?

  1. 나는 모든 쿼리를 마친 후에 닫아야하고 사용하기 전에 열어야합니까? 아니면 ...?
  2. 정적 클래스의 연결은 좋은 모델입니다. 그것을 만들 때마다)?
  3. 이 문제에 대한 좋은 디자인 패턴이 있습니까?
  4. 그것 모두는 동일한 질문을위한 것입니다. 데이터베이스 연결 (정적, 추상, 요청 당 ...)?

예를 들어나는 sms 발신자 웹 패널에서 일하고, 나는 초당 100K SMS를 보내야한다.이 sms는 다른 사람들과 모여서 모든 패키지에 1 ~ 20 sms를 가지고있다. 그런 다음 1 초당 5K ~ 100K 패키지를 보내야한다. 패키지 난이 단계를 수행해야합니다 :

  1. 단일 SMS를 배달 또는 배달하지 않도록 업데이트하십시오.
  2. 제공된 경우 사용자 균형 업데이트 useraccounts 테이블에서 사용자 잔액 줄이기
  3. 사용자 테이블에서 SMS 보내기 횟수 업데이트
  4. 휴대 전화 번호 표에서 SMS 전송 횟수 업데이트
  5. 발신자 번호 테이블에서 SMS 전송 횟수 업데이트
  6. 패키지 테이블에서 전달 및 실패한 SMS에 대한 패키지 업데이트
  7. 스레드가 패키지 테이블에서이 패키지를 보내는 방법에 대한 패키지 업데이트
  8. 얼마나 많은 SMS가이 트레드에 의해 그것을 보내고 얼마나 많은가 실패했는지에 대한 스레드 테이블을 업데이트하십시오.
  9. AccountDocument 테이블에서이 트랜잭션에 대한 계정 문서 추가

로그, 사용자 인터페이스 및 모니터링 위젯과 같은 모든 단계와 많은 작업이 수행되어야하며이 트랜잭션을 수행 할 때마다 DB 연결이 필요합니다.

자, DB에 연결하기위한 가장 좋은 모델은 무엇입니까? 인간의 요청이나 스레드 요청 또는 매 트랜잭션마다.


  • 찾다작업 단위리포지토리 패턴은 시작하기에 좋은 곳입니다. - Belogix
  • 트랜잭션을 어떻게 사용할지에 대한 설명이 나오는데, 일반적으로 트랜잭션마다 새로운 연결을 원하기 때문입니다 (트랜잭션이 겹치지 않는 한 확신 할 수 없다면). 성능을 저해 할 분산 트랜잭션을 사용해야하므로 트랜잭션 당 여러 개의 연결을 원하지 않습니다. 트랜잭션 측면에서이 점을 고려하지 않으려면 아마해야 할 것입니다. - James Gaunt
  • 옵션 "2" 명확한 아니오입니다. 그렇게하지 마십시오. - Marc Gravell
  • @ 메디 - 일의 단위는 갈 길입니다. 내 요점은 요청 / 정적 / 인스턴스 / 스레드의 관점에서 생각할 필요가 없습니다. 사업 단위 = 거래. 데이터베이스 액세스 패턴은 수행해야하는 작업 단위 / 트랜잭션과 관련된 다른 것과 관련되어서는 안됩니다. 이것이 최고의 성능과 트랜잭션 안전성을 얻는 방법입니다. Google Unit of Work에는 다양한 구현의 코드 예제가 많이 있습니다. - James Gaunt
  • @MehdiYeganeh TBQH 초당 많은 요청을 처리하는 경우 아마존 규모의 문제에 대해 누가 노력했는지 찾을 수있는 최고의 DBA를 고용하십시오. 이것은 1 ~ 2 백만 달러의 질문이기 때문입니다. - Yaur

3 답변


7

1. Should i close it after every query?

닷넷은 당신을 위해 그것을 처리합니다. 쓰레기 수집 작업입니다. 따라서 수동으로 객체를 폐기해야하는 번거 로움을 피하십시오. Jon Skeet의 좋은 대답입니다.https://stackoverflow.com/a/1998600/544283. 그러나 당신은using(IDisposable){ }GC가 작업을하도록 강제하는 명령문. 다음은 자원 재 할당에 관한 멋진 기사입니다.http://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About.

2. A connection in static class is good?

데이터 컨텍스트를 정적으로 만드십시오! 데이터 컨텍스트아니스레드 안전 또는 동시 안전.

3. Is there a good design pattern for this problem?

Belogix가 의존성 주입과 작업 단위 패턴을 언급했듯이 사실 엔티티 프레임 워크~이다.작업 단위 그 자체. DI와 UoW는 다소 과장되어 있지만 IoC 컨테이너를 처음 다루는 사람이라면 구현하기가 쉽지 않습니다. 또 다른 한 가지는 테스트를 실행하지 않을 경우 DI가 실제로 필요하지 않다는 것입니다. 이러한 패턴의 놀라운 점은 분리되어 땀을 흘리지 않고 테스트하고 조롱 할 수 있습니다.

짧게 : 코드에 대한 테스트를 실행하려는 경우 이러한 패턴을 찾으십시오. 그렇지 않은 경우 원하는 서비스간에 데이터 컨텍스트를 공유하는 방법에 대한 예제를 제공합니다. 이것은 귀하의 네 번째 질문에 대한 해답입니다.

4. What is the best method for making database connection (static, per request)?

컨텍스트 서비스 :

public class FooContextService {
    private readonly FooContext _ctx;

    public FooContext Context { get { return _ctx; } }

    public FooContextService() {
        _ctx = new FooContext();
    }
}

기타 서비스 :

public class UnicornService {
    private readonly FooContext _ctx;

    public UnicornService(FooContextService contextService) {
        if (contextService == null)
            throw new ArgumentNullException("contextService");

        _ctx = contextService.Context;
    }

    public ICollection<Unicorn> GetList() {
        return _ctx.Unicorns.ToList();
    }
}

public class DragonService {
    private readonly FooContext _ctx;

    public DragonService(FooContextService contextService) {
        if (contextService == null)
            throw new ArgumentNullException("contextService");

        _ctx = contextService.Context;
    }

    public ICollection<Dragon> GetList() {
        return _ctx.Dragons.ToList();
    }
}

제어 장치:

public class FantasyController : Controller {
    private readonly FooContextService _contextService = new FooContextService();

    private readonly UnicornService _unicornService;
    private readonly DragonService _dragonService;

    public FantasyController() {
        _unicornService = new UnicornService(_contextService);
        _dragonService = new DragonService(_contextService);
    }

    // Controller actions
}

두 번째 생각 (거의 편집) : 당신의 엔티티에 대한 프락시를 만들지 않도록 컨텍스트가 필요하다면, 다음과 같이 컨텍스트 서비스를 과부하시킬 수도 있습니다 :

public class FooContextService {
    private readonly FooContext _ctx;

    public FooContext Context { get { return _ctx; } }

    public FooContextService() : this(true) { }

    public FooContextService(bool proxyCreationEnabled) {
        _ctx = new FooContext();
        _ctx.Configuration.ProxyCreationEnabled = proxyCreationEnabled;
    }
}

노트:

  • 프록시 생성을 false로 설정하면아니상자 밖에서 게으른로드.
  • API 컨트롤러가 있다면하지마.어떤 완전한 블 로깅 된 객체 그래프를 다루고 싶습니다.

편집하다:

일부 독서 첫 번째 :

이것을 완료하십시오 :

(_context as IObjectContextAdapter).ObjectContext.Connection.Open();

이것에 대한 훌륭한 기사입니다.연결 및 트랜잭션 관리.

Entity 프레임 워크는 Connection 속성을 통해 EntityConnection을 노출합니다. 다음으로 읽기 :public sealed class EntityConnection : DbConnection.

연결 관리에 대한 고려 사항 : (이전 링크에서 가져옴)

  • 오브젝트 컨텍스트는 조작 전에 열려 있지 않은 경우 연결을 엽니 다. 오브젝트 컨텍스트가 조작 중에 연결을 열면, 조작이 완료 될 때 항상 연결을 닫습니다.
  • 수동으로 연결을 열면 개체 컨텍스트가 연결을 닫지 않습니다. 부름닫기또는특징연결을 종료합니다.
  • 오브젝트 컨텍스트가 연결을 작성하면, 컨텍스트가 처리 될 때 항상 연결이 처리됩니다.
  • 장기 실행 오브젝트 컨텍스트에서 더 이상 필요하지 않을 때 컨텍스트가 폐기되었는지 확인해야합니다.

희망이 도움이됩니다.


  • 뭐? " 직접 개체를 폐기하지 마세요 " 나쁜 조언입니다. "using(IDisposable){ }GC가 작업을 " using 문이 GC에 아무 것도하지 않도록합니다. - default.kramer
  • @default.kramer :"Don't bother disposing your objects manually":누가각 객체를 수동으로 처리 하시겠습니까? GC가 각 객체를 수동으로 배치하더라도 GC는 자동으로 아무 것도하지 않으므로 GC를 언제 어떻게 그리고 언제 무료로 사용할 수 있는지에 대해 매우 똑똑하다고 말한 것입니다. 과"use the using{} statement to force the GC to do it's work": 당신은 내부의 자원이using블록이 전화를 걸지 않습니다.Dispose그것의 범위가 끝날 때 그 자원에 대한 방법? 그렇다면 왜 구현해야 하는가?IDisposable를 사용할 때using성명서? 이를 반영하도록 답변을 변경하겠습니다. - Esteban
  • 첫 번째 두 문장은 " 마치 DB 연결을 놓아두고 놓지 말고 GC가 결국 처리합니다. " 어쩌면 당신이 의미하는 것이 아닐 수도 있습니다. 나는 당신이 GC와 그 사이의 관계 (또는 그것의 결여)를 오해한다고 생각합니다.IDisposable. 에이using통화 차단Dispose; GC가 최종자를 호출합니다. 공통의 "안전망" 파이널 라이저가Dispose불렀지 만 잘 작동하는 응용 프로그램에서는이 안전망이 필요하지 않아야합니다.IDisposablesGC 참여없이 폐기되어야합니다. - default.kramer
  • 또한 " 테스트를 실행하지 않으면 DI가 필요하지 않습니다. "와 일치하지 않습니다. 좋은 OO 디자인은 DI (컨테이너 관리 여부)를 선호하는 경향이 있습니다. 나는 주된 이점을 "합성 가능성"이라고 기술 할 것이다. 보다 유지 보수가 용이 한 애플리케이션으로 이어집니다. 테스트 가능성은 확실히 이점이지만 좋은 디자인의 부작용이됩니다. " 테스트를 작성하려면이 작업을 수행하고 그렇지 않으면 수행하십시오. "라고 권장하지 않습니다. " - default.kramer
  • @ Esteban tanx me.i를 도와 주셔서 많은 귀하의 답변에 대해 궁금해, 정말 좋은 tanx. 일회용 개체 및 가비지 컬렉터에 대해 알고 있지만, 가비지 컬렉터에 의해 연결을 닫는 처리를하게하는 것이 안전하지 않은 것 같아요. 예를 들어 보겠습니다. linQ 쿼리를 사용했고, SMS를 대기열에서 보내야합니다. 스레드와 스레드는 레코드 상태를 업데이트하고 모든 SMS 패키지와 모든 모바일 번호를로드하고 비용을 계산해야합니다. 비동기 호출 메소드를 사용하면 GC가이를 처리 할 수 없습니다. 모든 연결은 동시에 열립니다. - Mehdi Yeganeh

7

귀하의 질문에 대한 답변 :

  1. 닫아. .NET은 연결 풀링을 지원합니다.

  2. 그것을 창조하십시오. 매번 (연결 conn = new ....)를 사용하여이 방법을 사용하면 .NET 풀링 메커니즘을 최대한 활용할 수 있습니다.

  3. 당신은 .NET ThreadPool (또는 당신 자신의 커스텀 하나)을 사용할 수 있고 ThreadPool은 단지 10 개의 스레드를 병렬로 사용하고 Enqueue 작업 항목을 하나씩 사용하도록 정의 할 수 있습니다. 이 방법은 더 이상 다음 10 연결을 같은 시간에 사용됩니다 + 그것은 아마 더 빨리 작동합니다. Custom ThreadPools에 대한 추가 정보 :커스텀 ThreadPool 구현

  4. 인스턴스별로.


다음은 아키텍처에 대한 제 제안입니다.

  1. 보류중인 SMS를 보낼 데이터베이스 테이블 (대기열)을 만듭니다.

  2. 각 행에는 SMS에 필요한 모든 정보와 현재 상태가 포함됩니다.

  3. 작업자 프로세스를 생성하십시오. 아마도이 테이블을 샘플링하는 Windows 서비스 일 것입니다. 상태 = '보류 중'(int로 표시되어야 함) 인 TOP20 SMS를 선택합니다. 상태를 '보내기'로 업데이트합니다.

  4. 각 SMS는 Windows 서비스 측에서 사용자 정의 스레드 풀을 사용하여 전송됩니다.

  5. 프로세스가 끝나면 모든 처리 된 SMS 상태가 CTE (공통 테이블 표현식 - '대량 업데이트'작업을 수행 한 모든 SMS 행 ID와 함께 cte를 보낼 수 있음)를 사용하여 '완료'로 업데이트됩니다. ~ '완료'상태).

  6. 상태 업데이트 저장 프로 시저를 'getpending'과 동일한 것으로 만들 수 있습니다. 이렇게하면 잠금없이 선택하여 업데이트 할 수 있고 데이터베이스가 더 빨리 작동 할 수 있습니다.

  7. 이 방법을 사용하면 하나 이상의 프로세서 서비스를 실행할 수 있습니다 (하지만 nolock을 풀어야합니다).

가능한 한 많은 잠금을 피하십시오.

그런데 보류중인 SMS 테이블에 행을 추가하기 만하면 시스템의 어느 위치에서나 SMS를 보낼 수 있기 때문에 이것은 또한 좋은 방법입니다.

그리고 한 가지 더요, 엔티티 프레임 워크를 사용하는 것을 권장하지 않습니다. 왜냐하면 두드러기가 너무 많기 때문입니다. 이런 종류의 작업에 필요한 것은 단순히 3-4 개의 저장 프로 시저를 호출하는 것뿐입니다. 어쩌면 한번보세요.닷퍼 닷넷- 대부분의 경우 EF (Entity Framework)보다 10 배 이상 빠르게 작동하는 매우 가벼운 MicroDal 프레임 워크


  • 도와 줘서 고마워, 좋은 생각이야 .. 시험해 보려구. - Mehdi Yeganeh
  • 맞춤형 수영장에서 일하는 좋은 디자인 패턴을 제게 제안 해 주시겠습니까? - Mehdi Yeganeh

5

제 생각에 요청 당 최고로 비싸다고 생각합니다. 스레드 안전 연결 풀을 사용하고 연결 범위를 작업 단위 (UOW)와 일치 시키십시오. 작업 단위 (UOW)가 커밋되거나 롤백 될 때 트랜잭션 동작 및 작업 단위 (UOW)를 담당하는 서비스가 연결을 체크 아웃하여 사용하고 풀로 리턴하십시오.

최신 정보:

상태 업데이트를 수행하는 데 10-12 초가 소요됩니까? 너는 뭔가 잘못 했어. 서면으로 작성한 귀하의 질문은 적절한 대답을 제공하기에 충분하지 않습니다.

매일 NASDAQ 볼륨8 시간짜리 하루에 ~ 45K 트랜잭션까지 작동하는 1.3B 트랜잭션입니다. 귀하의 볼륨은 NASDAQ의 2 배입니다. 하나의 컴퓨터에서이 작업을 수행하려고한다면 NASDAQ이 둘 이상의 서버를 사용하고 있다고 말할 수 있습니다.

또한 ACID를 사용하여 상태를 업데이트하지 않고도 할 수 있는지 궁금합니다. 아무튼,스타 벅스는 2 단계 커밋을 사용하지 않습니다.. 아마도 더 나은 솔루션은 전송 대기 후에 해당 상태를 업데이트하기 위해 차단 대기열과 함께 생산자 / 고객 패턴을 사용하는 것입니다.


  • 내 프로젝트에 더 많은 문제가 .. 그것의 SMS 발신자 패널 내가 초당 100,000 SMS를 보내 모든 단일 SMS는 내가 DB를 업데이 트 상태해야하고 내가 함께 일한 100 스레드가 있었는데 내가 SMS를 보내는 비동기 메서드를 사용했다 그리고 다른 한편으로는 사용자가 보내는 SMS를 추적합니다 .. 지금은 요청 당 내 CPU 성능이 높은 가서 내가 1 초, 그것의 10-12 초 걸릴 모두를 보낼 수 없습니다. 그것의 아무 문제 나의 기계 설비를 격상 시키십시오, 나가 제일 방법을 알고 있고 사람이 요구 당 연결하고있는 경우에! - Mehdi Yeganeh
  • 10-12 초, 하나의 상태 업데이트를 저 지르지 말 것. 100000은 초당 100000을 보내고, 나스닥은 더 필요하다. 초당 100K를 보내고 그만 보내는 것은 내 휴대 전화 번호 테이블도 업데이트한다. 발신자 번호 & 사용자 발신자 수 & 스레드가 하나의 스레드를 계산 얼마나 많은 SMS를 보내고 나는 사용자의 균형을 감소하고 나는 모든 SMS 문서 및 1 개의 SMS를 보내고 다른 많은 사업을 만들 ... - Mehdi Yeganeh
  • 스타 벅스에 대한 고맙습니다. 2 단계 커밋을 사용하지 않았습니다. 나를 돕기에 좋은 점 .. - Mehdi Yeganeh
  • 이러한 의견에 지나치게 혼란스럽고 일관성이 없습니다. 내가 너를 위해 더 많은 것을 할 수 있다고 생각하지 않는다. 투표를 종료합니다. - duffymo
  • 미안 나는 내 영어가 내 성격이 아니라고 생각해. 나는 5 번 동안 DB에 연결하기 위해 모든 수업을 바꾼다. 그리고 그것에 대해 읽을 때마다 나는 정말로 하나가 길을 찾는 것을 좋아한다. 나는 다음 토요일에 프로젝트를 전달해야한다. 그리고 나는 db connection에 큰 문제가 있다고 생각한다. 저에게 db에 연결하기위한 패턴을 소개해주십시오. 저는 Unit Of Work, & 스타 벅스는 2 단계 커밋을 사용하지 않지만 좋은 생각이지만 더 많은 패턴을 찾고 싶습니다. - Mehdi Yeganeh

연결된 질문


관련된 질문

최근 질문