2016-07-04 3 views
0

시스템의 모든 사용자를 통해 웹 API 검색 기능을 만들어야합니다. (전화를 사용) 클라이언트 나 엔드 포인트를 사용하는 요청 보냅니다신뢰할 수있는 사전을 통해 검색

Q가 검색 필드에 입력 한 문자열 사용자입니다
HTTP 1.1 GET http://sf.cluster:80/ 
Path /search/users?q=Aa&take=10 

. 테이크 - 휴대 전화에 표시 할 항목 수.

Azure Storage Table의 신뢰할 수있는 사전 89000 항목에 업로드했습니다.

public async Task<IEnumerable<UserInfo>> Search(string q, int take) 
    { 
     var usersDictionary = await GetUsersDictionary(); 

     IEnumerable<UserInfo> results; 
     using (var tx = StateManager.CreateTransaction()) 
     { 
      var searchResults = (from r in (await usersDictionary.CreateEnumerableAsync(tx)).ToEnumerable() 
          where r.Value.StartsWith(q, StringComparison.InvariantCultureIgnoreCase) 
          select new UserInfo() 
          { 
           Id = r.Key, 
           Name = r.Value 
          }).Take(take); 

      results = new List<UserInfo>(searchResults); 

      await tx.CommitAsync(); 
     } 

     return results; 
    } 

문제 :

IReliableDictionary<Guid, string> 

내 검색 방법은 다음과 같습니다 그것은 구조를 가지고 그것은 전화에 좋은 일를, 내가 기대했던 얻었다. 그러나 많은 요청 (약 60 스레드가 Soap UI 도구를 사용하여 동시에)으로 끝점을 시작하기 시작하면 제한 시간이 1 초에서 35 초로 증가했습니다. 어딘가에서 실수를하거나 잘못된 검색 방법을 선택하는 것처럼 보입니다.

누군가 이런 식으로 일부 기능을 구현 했습니까? 아무도 정확한 검색 접근법을 도울 수 있습니까?

UPD :List<string>에 이름을 저장하고 동일한 작업 (목록을 검색)을 수행하는 상태 비 저장 서비스가 구현되었습니다. 결과 : 150-300ms. 상태 (상태있는 서비스의 상태)에 List를 저장하고 요청시 가져와야하는 것처럼 보입니다.

답변

3

ToEnumerable 메서드의 구현이 무엇인지 잘 모르겠습니다 만, 비동기 열거 형을 가져 와서 목록에 복사하는 게으른 구현. 이제 890,000 개의 elems의 신뢰할 수있는 사전으로 비효율적입니다. 또한 트랜잭션은 뮤텍스처럼 작동하므로이 거대한 목록을 복사하는 동안 기본 컬렉션을 잠글 수 있습니다. AsyncEnumerable linq 구현을 this library에 체크 아웃 할 것을 제안합니다.이 방법은 서비스 패브릭 AsyncEnumerable과 함께 linq를 사용하는 효율적인 방법을 구현합니다. 그 사용, 검색은 다음과 같이 보일 것입니다 : 또한

using (var tx = StateManager.CreateTransaction()) 
    { 
     var enumerable = await usersDictionary.CreateEnumerableAsync(tx); 
     results = await enumerable.Where(kvp=>kvp.Value.StartsWith(q, StringComparison.InvariantCultureIgnoreCase)) 
      .Select(kvp=> new UserInfo() 
        { 
         Id = r.Key, 
         Name = r.Value 
        }) 
      .Take(take) 
      .ToListAsync(tx); 
    } 

를 보조 노트로, 당신은 당신이 트랜잭션을 커밋 할 필요가 없습니다 어떤 방식으로 내부 컬렉션을 수정하지 않을 때문이다. 트랜잭션을 커밋하는 것은 상태 관리자에게 상태를 수정했음을 알려주고 변경 작업을 완료 한 후 변경된 값을 보조 노드에 전파하는 것입니다. 이 메소드를 2 차적으로 읽으면이 메소드를 읽기 상태의 무거운 조각이라도되지만, 아직 쓰기가 전파되지 않을 수도 있다는 점에 유의하십시오.

1

ReliableDictionary에서 일부 값을 페이징하기 때문에 ReliableDictinonary는 IAsyncEnumerable을 반환합니다. 이것은 디스크 IO가 일부 값을 읽어야 할 수도 있음을 의미합니다. IAsyncEnumerable을 사용하면 최대한 적은 수의 스레드를 차단할 수 있습니다.

읽기 대기 시간이 문제가되는 경우 알림을 사용하여 전체 메모리 내 보조 색인을 작성할 수 있습니다. 접두사 일치 검색의 효율성을 높이려면 보조 색인을 값순으로 정렬 할 수도 있습니다. 다음은 관련 문서입니다. https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-notifications

pdylanross의 답변에 약간 수정 : CreateEnumerableAsync는 컬렉션을 잠그지 않는 mvcc 모델을 사용하여 스냅 샷 격리를 제공합니다.따라서 스냅 샷 읽기 트랜잭션이 진행되는 동안 다른 트랜잭션은 읽기 및 쓰기 작업을 계속 수행 할 수 있습니다. 격리 수준에 대한 자세한 내용 : https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-reliable-collections

희망 하시겠습니까?

관련 문제