오늘은 IDL을 이용하여 구현해 보도록 하겠습니다. IDL 이 json 포맷보다 훨씬 가독성이 좋아서, 저는 앞으로는 IDL로 구현해야겠네요.
오늘은 어제보다 좀 더 복잡한 코드를 만들어 보겠습니다. Avro IDL 관련 설명을 읽고 10분만에 구현했으니, 이 글을 보시는 분들도 단박에 이해 되실겁니다.
구현한 예제는 검색 서비스를 흉내낸 것인데, 데이터의 저장, 검색 함수를 지원합니다.
searchService.avdl (Avro IDL 포맷의 확장자는 avdl 입니다)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@namespace("example.avro.search") | |
protocol SearchService { | |
record Entity { | |
string rowId; | |
string @order("ascending") createdAt; | |
string text; | |
map<string> attrs; | |
} | |
record SearchResult { | |
int pageNo; | |
int pageSize; | |
int pageCount; | |
int totalItemCount; | |
array<Entity> entities; | |
} | |
string ping(); // return "PONG" | |
int persist(string id, Entity entity); | |
int persistAll(array<Entity> entities); | |
array<Entity> search(string queryString); | |
SearchResult search(string queryString, int pageNo = 1, int pageSize = 10); | |
} |
SearchService 에는 Entity, SearchResult 라는 자료구조 (java에서는 class) 를 정의하고, 아래에는 rpc 메소드들을 정의했습니다.
JSON 포맷보다 훨씬 보기 좋죠?
이전 글에 설명되었듯이 idl-protocol 에 대해 source-generation 을 수행하고, 아래 코드를 작성하면, Search Service 를 제작할 수 있습니다.
SearchServer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package example.avro.search; | |
import com.google.common.collect.Lists; | |
import com.google.common.collect.Maps; | |
import lombok.extern.slf4j.Slf4j; | |
import org.apache.avro.AvroRemoteException; | |
import org.apache.avro.ipc.NettyServer; | |
import org.apache.avro.ipc.NettyTransceiver; | |
import org.apache.avro.ipc.Server; | |
import org.apache.avro.ipc.specific.SpecificRequestor; | |
import org.apache.avro.ipc.specific.SpecificResponder; | |
import org.apache.avro.util.Utf8; | |
import java.io.IOException; | |
import java.net.InetSocketAddress; | |
import java.util.Date; | |
import java.util.List; | |
import java.util.Map; | |
/** | |
* Apache Avro IDL 을 이용한 RPC 예제입니다. | |
* | |
* @author sunghyouk.bae@gmail.com | |
* @since 13. 4. 18. 오후 3:34 | |
*/ | |
@Slf4j | |
public class SearchServer { | |
public static class SearchServiceImpl implements SearchService { | |
@Override | |
public CharSequence ping() throws AvroRemoteException { | |
return new Utf8("PONG"); | |
} | |
@Override | |
public int persist(CharSequence id, Entity entity) throws AvroRemoteException { | |
System.out.printf("\nPersist entity. id=%s, entity=%s", id, entity); | |
return 1; | |
} | |
@Override | |
public int persistAll(List<Entity> entities) throws AvroRemoteException { | |
System.out.printf("\nPersist entities. entity count=%d", entities.size()); | |
return entities.size(); | |
} | |
@Override | |
public SearchResult search(CharSequence queryString, int pageNo, int pageSize) throws AvroRemoteException { | |
System.out.printf("\nsearch... queryString=%s, pageNo=%d, pageSize=%d", queryString, pageNo, pageSize); | |
// 검색된 엔티티들 | |
List<Entity> entities = Lists.newArrayListWithCapacity(pageSize); | |
Map<String, String> attrs = Maps.newHashMap(); | |
attrs.put("SR-NO", "00001"); | |
attrs.put("SR-TYPE", "장비 불량"); | |
for (int i = 0; i < pageSize; i++) { | |
entities.add(createSampleEntity(i, attrs)); | |
} | |
return SearchResult.newBuilder() | |
.setPageNo(pageNo) | |
.setPageSize(pageSize) | |
.setPageCount(12) | |
.setTotalItemCount(pageSize * 12) | |
.setEntities(entities) | |
.build(); | |
} | |
} | |
public static Entity createSampleEntity(int i, Map attrs) { | |
return Entity.newBuilder() | |
.setRowId("ROW-" + i) | |
.setCreatedAt(new Date().toString()) | |
.setText("entity") | |
.setAttrs(attrs) | |
.build(); | |
} | |
private static Server searchServer; | |
private static final int SEARCH_SERVER_PORT = 65123; | |
private static void startServer() throws IOException { | |
searchServer = new NettyServer(new SpecificResponder(SearchService.class, new SearchServiceImpl()), | |
new InetSocketAddress("localhost", SEARCH_SERVER_PORT)); | |
} | |
public static void main(String[] args) throws Exception { | |
System.out.println("Starting server..."); | |
startServer(); | |
System.out.println("Server started"); | |
NettyTransceiver searchClient = new NettyTransceiver(new InetSocketAddress("localhost", SEARCH_SERVER_PORT)); | |
SearchService searchService = (SearchService) SpecificRequestor.getClient(SearchService.class, searchClient); | |
System.out.println("Client built, get proxy"); | |
System.out.println("ping()=> " + searchService.ping()); | |
Map<String, String> attrs = Maps.newHashMap(); | |
attrs.put("SR-NO", "00001"); | |
attrs.put("SR-TYPE", "장비 불량"); | |
searchService.persist("ROW-1", createSampleEntity(1, attrs)); | |
List<Entity> entities = Lists.newArrayListWithCapacity(1000); | |
for (int i = 0; i < 1000; i++) { | |
entities.add(createSampleEntity(i, attrs)); | |
} | |
int count = searchService.persistAll(entities); | |
System.out.println("\nPersist count=" + count); | |
SearchResult searchResult = searchService.search("en*", 1, 10); | |
System.out.println("\nSearchResult=" + searchResult); | |
searchClient.close(); | |
searchServer.close(); | |
} | |
} |
아주 초간단하게 작성했지만 될 건 다 됩니다^^
이제 Avro 의 좀 더 깊은 영역을 살펴봐야겠습니다.
댓글 없음:
댓글 쓰기