Qbit Java Micorservices lib 튜토리얼 | QBIT 웹 사이트 | QBIT는 Reakt |를 사용합니다 qbit은 vert.x |와 함께 작동합니다 Reakt Vertx
Java MicroService lib. QBIT는 JSON, HTTP, WebSocket 및 REST를 마이크로 서비스를 구축하기위한 반응 형 프로그래밍 LIB입니다. QBIT는 반응성 프로그래밍을 사용하여 탄성 휴식과 WebSockets 기반 클라우드 친화적 인 웹 서비스를 구축합니다. SOA는 모바일과 클라우드로 진화했습니다. 서비스, 건강, 반응성 통계 서비스, 이벤트, 마이크로 서비스에 대한 Java 관용 반응성 프로그래밍.
질문이 있습니까? QBIT Google Group.
모든 것이 대기열입니다. 당신은 선택의 여지가 있습니다. 당신은 그것을 받아들이고 통제 할 수 있습니다. 최적화 할 수 있습니다. 또는 추상화 뒤에 숨길 수 있습니다. QBIT는 당신을 열어 일하고있는 일을 엿볼 수있게 해주 며, 당신의 영혼을 팔지 않고도 약간의 레버를 당길 수 있습니다.
QBIT는 프레임 워크가 아닌 라이브러리입니다. QBIT와 Spring, Guice 등을 혼합하고 일치시킬 수 있습니다.
QBIT는 이제 로컬 및 원격 클라이언트 프록시에 대한 REAKT VERKOBLE 약속을 지원합니다. 이것은 비동기 프로그래밍을위한 유창한 API를 제공합니다.
employeeService . lookupEmployee ( "123" )
. then (( employee )-> {...}). catchError (...). invoke ();
QBIT 콜백은 이제 콜백에 대한 QBIT 계약을 중단하지 않고 콜백을 다시 시작합니다.
자세한 내용은 Reakt Invokable 약속을 참조하십시오.
QBIT는 Maven Public Repo에 게시됩니다.
< dependency >
< groupId >io.advantageous.qbit</ groupId >
< artifactId >qbit-admin</ artifactId >
< version >1.10.0.RELEASE</ version >
</ dependency >
< dependency >
< groupId >io.advantageous.qbit</ groupId >
< artifactId >qbit-vertx</ artifactId >
< version >1.10.0.RELEASE</ version >
</ dependency >
compile 'io.advantageous.qbit:qbit-admin:1.10.0.RELEASE'
compile 'io.advantageous.qbit:qbit-vertx:1.10.0.RELEASE'
여러 대형 Fortune 100 회사에 배치되었습니다. QBIT는 이제 Vertx (독립형 또는 임베디드)와 함께 작동합니다. 비 QBIT 프로젝트에서 QBIT를 사용할 수도 있습니다. 단지 lib 일뿐입니다.
아파치 2
QBIT에는 Inproc 서비스, REST 마이크로 서비스 및 WebSocket 마이크로 서비스뿐만 아니라 모듈 당 모듈 또는 앱 당일 수 있음)가 있습니다. 근로자 및 메모리 서비스를 지원합니다.
더 자세히 설명하기 전에 두 가지 샘플 서비스가 있습니다.
@ RequestMapping ( "/todo-service" )
public class TodoService {
@ RequestMapping ( "/todo/count" )
public int size () {...
@ RequestMapping ( "/todo/" )
public List < TodoItem > list () {...
@ RequestMapping ( "/adder-service" )
public class AdderService {
@ RequestMapping ( "/add/{0}/{1}" )
public int add ( @ PathVariable int a , @ PathVariable int b ) {...
}
하루가 끝나면 QBIT는 프레임 워크가 아닌 간단한 라이브러리입니다. 앱은 QBIT 앱이 아니라 QBIT LIB를 사용하는 Java 앱입니다. QBIT를 사용하면 Java Util Concurrent와 함께 일할 수 있으며, 그것을 숨기려고 노력하지 않습니다. 그냥 찌르기를 시도합니다.
우리는 BOON과 QBIT의 기술을 사용하여 고급, 고성능, 고소성 앱에서 큰 성공을 거두었습니다. 우리는 클라이언트가 QBIT의 기술을 사용하여 경쟁 업체의 서버 1/10을 사용하여 10 배의 부하를 처리하도록 도와주었습니다. QBIT는 우리가 손을 튜닝하는 큐 액세스 및 스레드로 아프다.
Boon과 Qbit에 대한 아이디어는 종종 웹 전체에서 나옵니다. 우리는 실수를합니다. 그들을 지적하십시오. Boon and Qbit의 개발자로서 우리는 동료 여행자입니다. 공유하려는 아이디어 나 기술이 있다면 우리는 듣습니다.
Boon/Qbit에 대한 큰 영감은 Vertx, Akka, Go 채널, 액티브 객체, 아파트 모델 스레딩, 액터 및 기계적 동정 용지였습니다.
QBIT에는 많은 프레임 워크와 유사한 아이디어가 있습니다. 우리는 모두 같은 논문을 읽고 있습니다. QBIT는 LMAX Disruptor Papers 와이 블로그 게시물에서 링크 전송 큐 대 Druptor에 대한 영감을 얻었습니다. 우리는 블로그 게시물이 우리에게 시도해 보도록 영감을주는 대기열에 대한 몇 가지 이론을 가지고있었습니다. 이러한 이론 중 일부는 가장 큰 미들웨어 백엔드 중 일부에 배치되었으며 전 세계적으로 이름 브랜드가 알려져 있습니다. 따라서 Qbit은 태어났습니다.
Qbit은 또한 Vertx의 Tim Fox가 수행 한 위대한 작품으로 많은 영감을 얻었습니다. 실제로 QBIT (초기 QBIT)라고 할 수있는 것을 사용하는 첫 번째 프로젝트는 웹/모바일 마이크로 서비스에서 Vertx를 사용하여 8 천만 명의 사용자가있을 수있는 앱을 사용하는 것이 었습니다. QBIT 개발과 진화로 이어진 VERTX와 초기 QBIT에 대한 이러한 경험이었습니다. QBIT는 자이언츠 어깨 (Netty/Vertx) 위에 세워져 있습니다.
Spring Disruptor : 아니요. QBIT를 사용하여 스프링 장애물에 대한 플러그인을 작성할 수 있지만 QBIT는 스프링 방해자와 경쟁하지 않습니다. Spring Boot/Spring MVC : 아니요. 우리는 동일한 주석을 사용하지만 QBIT는 고속 내 메모리 마이크로 서비스를 제공합니다. 그것은 스프링 부츠보다 아크카와 비슷합니다. QBIT는 마이크로 서비스, 즉 WebSocket RPC, REST, JSON Marshaling 등에 만 기어링 된 Spring MVC 기능의 하위 집합을 가지고 있습니다. AKKA : 아일 수도 있습니다. Akka는 비슷한 개념을 가지고 있지만 다른 접근 방식을 취합니다. QBIT는 AKKA보다 Java 및 MicroServices (REST, JSON, WebSocket)에 더 중점을 둡니다. LMAX DIRRUPTOR : 아니요. 실제로, 우리는 QBIT가 덮개 아래에 사용하는 대기열에서 Disruptor를 사용할 수 있습니다.
(초기 벤치 마크가 제거되었습니다. 그들은 여기에있었습니다. Qbit은 훨씬 더 빨라졌습니다. 벤치마킹 QBIT는 현재 움직이는 목표입니다. 링크와 보고서가 만들어집니다.)
코드 예제
====
BasicQueue < Integer > queue = BasicQueue . create ( Integer . class , 1000 );
//Sending threads
SendQueue < Integer > sendQueue = queue . sendQueue ();
for ( int index = 0 ; index < amount ; index ++) {
sendQueue . send ( index );
}
sendQueue . flushSends ();
...
sendQueue . sendAndFlush ( code );
//other methods for sendQueue, writeBatch, writeMany
//Receiving Threads
ReceiveQueue < Integer > receiveQueue = queue . receiveQueue ();
Integer item = receiveQueue . take ();
//other methods poll(), pollWait(), readBatch(), readBatch(count)
QBIT는 마이크로 서비스를위한 대기열 라이브러리입니다. Akka, Spring Reactor 등과 같은 다른 많은 프로젝트와 유사합니다. QBIT는 플랫폼이 아닌 라이브러리 일뿐입니다. QBIT에는 대기열 뒤에 서비스를 제공하는 라이브러리가 있습니다. QBIT 대기열을 직접 사용하거나 서비스를 만들 수 있습니다. QBIT 서비스는 WebSocket, HTTP, HTTP 파이프 라인 및 기타 유형의 원격으로 노출 될 수 있습니다. QBIT의 서비스는 서비스 대기열 뒤에 메소드가 실행되는 Java 클래스입니다. QBIT는 아파트 모델 스레딩을 구현하며 액터 모델과 유사하거나 더 나은 설명은 활성 객체입니다. QBIT는 방해물을 사용하지 않지만 (할 수 있음). 정기적 인 자바 대기열을 사용합니다. QBIT는 1 억 개의 북쪽으로 초당 1 억 탁구 통화를 할 수 있으며, 이는 놀라운 속도 (200m만큼 높은)입니다. QBIT는 또한 REST 및 WebSocket을 통해 전화 서비스를 지원합니다. QBIT는 순수한 웹 센스의 마이크로 서비스입니다 : JSON, HTTP, WebSocket 등. QBIT는 마이크로 배치를 사용하여 파이프 (큐, IO 등)를 통해 메시지를 더 빨리 푸시하여 스레드 핸드 오프를 줄입니다.
QBIT는 REST, JSON 및 WebSocket을 지원하는 Java MicroService Lib입니다. Java로 작성되었지만 언젠가 Rust 또는 Go 또는 C#에 버전을 쓸 수 있습니다 (그러나 큰 월급 날이 필요합니다).
프록시 호출 또는 이벤트를 통해 메소드 호출을받을 수있는 대기열 뒤에 서비스 Pojo (평범한 오래된 Java 개체) (하나의 스레드 관리 이벤트, 메소드 호출 및 응답 또는 메소드 호출 및 이벤트 및 응답에 대한 하나는 응답 처리기에 대해 하나가있을 수 있습니다. 서비스를 차단하지 마십시오. 응답 블록이 아니라면 하나는 더 빠릅니다). 서비스는 Spring MVC Style Rest Annotation을 사용하여 REST 및 WebSocket을 통해 외부 세계에 노출 될 수 있습니다.
ServiceBundle 한 응답 대기열 뒤에 많은 Pojos가 있으며 많은 사람들이 대기열을받습니다. 모든 응답에 대해 하나의 스레드가있을 수 있습니다. 그들은 또한 하나의 수신 대기열 일 수 있습니다.
대기열을 관리하는 스레드 . 배치를 지원합니다. 비어있는 이벤트가 있습니다. 줄 뒤에 앉아있는 서비스에서 이러한 이벤트를들을 수 있습니다. 서비스를 사용할 필요가 없습니다. 큐의 직접을 사용할 수 있습니다. QBIT에는 발신자 대기열과 수신기 대기열이 있습니다. 그들은 마이크로 배치를 지원하기 위해 분리되어 있습니다.
ServiceEndPointserver ServiceBundle REST 및 WebSocket Communication에 노출됩니다.
EventBus EventBus는 느슨하게 결합 될 수있는 서비스에 많은 메시지를 보내는 방법입니다.
ClientProxy ClientProxy는 Async 인터페이스를 통해 서비스를 호출하는 방법입니다. 서비스는 Inproc (동일한 프로세스) 또는 WebSocket을 통해 원격으로 제공 될 수 있습니다.
비 블로킹 QBIT는 비 블로킹 리브입니다. Java 8 Lambdas를 통해 콜백을 사용합니다. 이벤트 메시지를 보내고 답장을받을 수도 있습니다. 메시징은 시스템에 내장되어있어 복잡한 작업을 쉽게 조정할 수 있습니다. QBIT는 서비스 개발에 대한 객체 지향적 접근 방식을 취하므로 서비스는 이미 작성한 일반적인 Java 서비스처럼 보이지만 서비스는 대기열/스레드 뒤에 있습니다. 이것은 새로운 개념이 아닙니다. Microsoft는 DCOM/COM을 사용하여 활성 객체라고 불렀습니다. Akka는 배우들과 함께 그것을하고 그들을 강력하게 입력 한 배우라고 불렀습니다. 중요한 개념은 반응성 및 액터 스타일 메시징의 속도를 얻지 만 자연스러운 OOP 접근 방식으로 발전한다는 것입니다. QBIT는 첫 번째가 아닙니다. QBIT만이 아닙니다.
속도 Qbit은 매우 빠릅니다. 물론 개선의 여지가 많이 있습니다. 그러나 이미 200m+ TPS Inproc Ping Pong, 10M-20M+ TPS 이벤트 버스, WebSocket/JSON을 통해 500K TPS RPC 통화 등의 속도를 향상시키기 위해 더 많은 작업을 수행해야하지만 이제는 유용성에 더 집중하는 곳에 충분히 빠릅니다. JSON 지원은 기본적으로 BOON을 기본적으로 사용하며, 이는 REST/JSON, WebSocket/JSON 사용 사례에 대한 다른 JSON 파서보다 최대 4 배 빠릅니다.
반응성 프로그래밍 QBIT는 비동기 호출을 관리하는 원자로를 제공합니다. 이를 통해 콜백은 호출 된 것과 동일한 스레드에서 처리 할 수 있으며 시간 초과 및 오류 처리를 제공합니다. 반응성 마이크로 서비스 프로그래밍을 만들기위한 Reactor 튜토리얼을 읽으십시오
서비스 발견을 지원하는 서비스 발견 . 여기에는 영사와의 통합이 포함됩니다.
통계를 지원하는 통계 서비스 . 통계 서비스 는 STATSD (graphite, grafana, datadog 등)와 통합되어 수동 통계를 게시 할 수 있습니다. 또는 통계 엔진을 쿼리하고 통계 (카운트, 타이밍 및 레벨)에 반응 할 수 있습니다. 통계 서비스 는 클러스터링 될 수있는 반응성 통계 시스템입니다. 통계 서비스는 귀하의 서비스가이를 게시하고 쿼리하고 결과에 따라 반응 할 수 있다는 점에서 반응합니다. 요금 제한과 같은 것들을 구현하고 증가 된 비율에 반응 할 수 있습니다. ServiceScovery 시스템은 HealthSystem 및 Consul과 통합되어 마이크로 서비스를 구성하고 마이크로 서비스의 복합재를 단일 HTTP 엔드 포인트 또는 Consul (TTL)의 Dead Mans 스위치에 게시하는 각 내부 서비스를 롤업합니다.
대화는 싸다. 몇 가지 코드를 살펴 보겠습니다. 위키에서 상세하게 걸어 갈 수 있습니다. 우리는 이미 많은 문서를 가지고 있습니다.
REST/JSON을 통해 노출되는 서비스를 만들 것입니다.
TODO 목록의 크기를 쿼리하려면 :
curl localhost:8080/services/todo-service/todo/count
새로운 TODO 항목을 추가합니다.
curl -X POST -H " Content-Type: application/json " -d
' {"name":"xyz","description":"xyz"} '
http://localhost:8080/services/todo-service/todo
TODO 항목 목록을 얻으려면
curl http://localhost:8080/services/todo-service/todo/
TODO 예제는 TODO 항목을 사용하고 추적합니다.
package io . advantageous . qbit . examples ;
import java . util . Date ;
public class TodoItem {
private final String description ;
private final String name ;
private final Date due ;
Todoservice는 Spring MVC 스타일 주석을 사용합니다.
@ RequestMapping ( "/todo-service" )
public class TodoService {
private List < TodoItem > todoItemList = new ArrayList <>();
@ RequestMapping ( "/todo/count" )
public int size () {
return todoItemList . size ();
}
@ RequestMapping ( "/todo/" )
public List < TodoItem > list () {
return todoItemList ;
}
@ RequestMapping ( value = "/todo" , method = RequestMethod . POST )
public void add ( TodoItem item ) {
todoItemList . add ( item );
}
}
비 JSON을 게시/배치 할 수 있으며 몸체를 String
으로 또는 byte[]
로 캡처 할 수 있습니다. 컨텐츠 유형이 application/json
이외의 것으로 설정된 경우 신체가 문자열 또는 바이트 []로 정의됩니다. 이것은 자동으로 작동합니다. (내용 유형을 설정해야합니다.)
@ RequestMapping ( value = "/body/bytes" , method = RequestMethod . POST )
public boolean bodyPostBytes ( byte [] body ) {
String string = new String ( body , StandardCharsets . UTF_8 );
return string . equals ( "foo" );
}
@ RequestMapping ( value = "/body/string" , method = RequestMethod . POST )
public boolean bodyPostString ( String body ) {
return body . equals ( "foo" );
}
기본적으로 QBIT는 비 방사 호출 (반품 또는 콜백이있는 통화)에 대해 200
(OK)을 보냅니다. 나머지 작업에 반품이 없거나 콜백이 없으면 QBIT는 202
(허용)를 보냅니다. 201 (생성) 또는 예외가 아닌 다른 코드를 보내려고 할 때가있을 수 있습니다. @RequestMapping
에서 code
설정하여 그렇게 할 수 있습니다. 기본적으로 코드는 -1입니다. 즉, 기본 동작 (성공의 경우 200, 일방 통행 메시지의 경우 202, 오류의 경우 500)을 사용합니다.
@ RequestMapping ( value = "/helloj7" , code = 221 )
public void helloJSend7 ( Callback < JSendResponse < List < String >>> callback ) {
callback . returnThis ( JSendResponseBuilder . jSendResponseBuilder ( Lists . list (
"hello " + System . currentTimeMillis ())). build ());
}
Callbacks
내부 서비스에도 사용할 수 있습니다. 콜백 빌더 또는 QBIT 원자로를 사용하여 서비스 호출을 관리하는 경우가 종종 있습니다.
JSON 양식 휴식 전화를 반환 할 필요가 없습니다. HttpBinaryResponse
및 HttpTextResponse
사용하여 바이너리 또는 텍스트를 반환 할 수 있습니다.
@ RequestMapping ( method = RequestMethod . GET )
public void ping2 ( Callback < HttpTextResponse > callback ) {
callback . resolve ( HttpResponseBuilder . httpResponseBuilder ()
. setBody ( "hello mom" ). setContentType ( "mom" )
. setCode ( 777 )
. buildTextResponse ());
}
@ RequestMapping ( method = RequestMethod . GET )
public void ping2 ( Callback < HttpBinaryResponse > callback ) {
callback . resolve ( HttpResponseBuilder . httpResponseBuilder ()
. setBody ( "hello mom" ). setContentType ( "mom" )
. setCode ( 777 )
. buildBinaryResponse ());
}
왜 우리는 스프링 스타일 주석을 선택 했습니까?
이제 시작하십시오.
public static void main ( String ... args ) {
ServiceEndpointServer server = new EndpointServerBuilder (). build ();
server . initServices ( new TodoService ());
server . start ();
}
그게 다야. 클라이언트 측 프록시 생성과 함께 Box WebSocket 지원이 없으므로 초당 수백만 건의 전화 속도로 서비스를 요청할 수 있습니다.
@ RequestMapping ( "/adder-service" )
public class AdderService {
@ RequestMapping ( "/add/{0}/{1}" )
public int add ( @ PathVariable int a , @ PathVariable int b ) {
return a + b ;
}
}
WebSocket 프록시를 통해 언제든지 QBIT 서비스를 호출 할 수 있습니다. WebSocket 프록시의 장점은 1M RPC+를 1 초 동안 실행할 수 있다는 것입니다 (매 초마다 1 백만 개의 원격 통화).
/* Start QBit client for WebSocket calls. */
final Client client = clientBuilder ()
. setPort ( 7000 ). setRequestBatchSize ( 1 ). build ();
/* Create a proxy to the service. */
final AdderServiceClientInterface adderService =
client . createProxy ( AdderServiceClientInterface . class ,
"adder-service" );
client . start ();
/* Call the service */
adderService . add ( System . out :: println , 1 , 2 );
출력은 3입니다.
3
위는 WebSocket 프록시 인터페이스를 사용하여 서비스 비동기를 호출합니다.
interface AdderServiceClientInterface {
void add ( Callback < Integer > callback , int a , int b );
}
서비스를 제공하는 WebSocket Service 클라이언트를 만듭니다.
final Client client = clientBuilder . setServiceDiscovery ( serviceDiscovery , "echo" )
. setUri ( "/echo" ). setProtocolBatchSize ( 20 ). build (). startClient ();
final EchoAsync echoClient = client . createProxy ( EchoAsync . class , "echo" );
현재 clientBuilder
서비스 이름에 등록 된 모든 서비스 엔드 포인트를로드하고 무작위로 선택합니다.
ServiceScovery에는 영사 기반, 디스크에서 JSON 파일 시청 및 DNS가 포함됩니다. 자신의 서비스 검색도 작성하여 QBIT에 연결하기 쉽습니다.
앞으로 우리는 Roundrobin 호출 또는 샤드 호출을 WebSocket Service로 통화하거나 연결이 닫히면 자동 실패를 제공 할 수 있습니다. 우리는 서비스 검색을 사용하는 이벤트 버스를 위해이 작업을 수행하지만 아직 WebSocket 기반 클라이언트 스텁으로 구운 것은 아닙니다.
마지막 클라이언트 예제는 WebSocket을 사용합니다. REST를 사용하고 실제로 설정 한 URI 매개 변수를 사용할 수도 있습니다. 휴식은 좋지만 WebSocket 지원보다 느리게 진행됩니다.
QBIT는 멋진 작은 HTTP 클라이언트와 함께 배송됩니다. 우리는 그것을 사용할 수 있습니다.
이를 사용하여 HTTP 클라이언트와 비동기 통화 및 WebSocket 메시지를 보낼 수 있습니다.
여기서는 HTTP 클라이언트를 사용하여 원격 방법을 호출합니다.
HttpClient httpClient = httpClientBuilder ()
. setHost ( "localhost" )
. setPort ( 7000 ). build ();
httpClient . start ();
String results = httpClient
. get ( "/services/adder-service/add/2/2" ). body ();
System . out . println ( results );
출력은 4입니다.
4
Curl에서 서비스에 액세스 할 수도 있습니다.
$ curl http://localhost:7000/services/adder-service/add/2/2
이 전체 예를 참조하십시오. QBIT MICROSERVICE 시작 튜토리얼.
Qbit URI 매개 변수 및 WebSocket 프록시 클라이언트
QBIT에는 가볍고 사용하기가 재미있는 비동기 마이크로 서비스 작업 및 작성을위한 라이브러리가 있습니다.
/* Create an HTTP server. */
HttpServer httpServer = httpServerBuilder ()
. setPort ( 8080 ). build ();
/* Setup WebSocket Server support. */
httpServer . setWebSocketOnOpenConsumer ( webSocket -> {
webSocket . setTextMessageConsumer ( message -> {
webSocket . sendText ( "ECHO " + message );
});
});
/* Start the server. */
httpServer . start ();
/** CLIENT. */
/* Setup an httpClient. */
HttpClient httpClient = httpClientBuilder ()
. setHost ( "localhost" ). setPort ( 8080 ). build ();
httpClient . start ();
/* Setup the client websocket. */
WebSocket webSocket = httpClient
. createWebSocket ( "/websocket/rocket" );
/* Setup the text consumer. */
webSocket . setTextMessageConsumer ( message -> {
System . out . println ( message );
});
webSocket . openAndWait ();
/* Send some messages. */
webSocket . sendText ( "Hi mom" );
webSocket . sendText ( "Hello World!" );
ECHO Hi mom
ECHO Hello World!
이제 서버와 클라이언트를 중지하십시오. 꽤 쉬운?
/* Create an HTTP server. */
HttpServer httpServer = httpServerBuilder ()
. setPort ( 8080 ). build ();
/* Setting up a request Consumer with Java 8 Lambda expression. */
httpServer . setHttpRequestConsumer ( httpRequest -> {
Map < String , Object > results = new HashMap <>();
results . put ( "method" , httpRequest . getMethod ());
results . put ( "uri" , httpRequest . getUri ());
results . put ( "body" , httpRequest . getBodyAsString ());
results . put ( "headers" , httpRequest . getHeaders ());
results . put ( "params" , httpRequest . getParams ());
httpRequest . getReceiver ()
. response ( 200 , "application/json" , Boon . toJson ( results ));
});
/* Start the server. */
httpServer . start ();
코드가 빡빡하고 작아서 콜백에 Java 8 Lambdas를 사용하기 쉽고 Java 8 Lambdas를 사용하는 데 중점을 둡니다.
QBIT의 마이크로 서비스 스타일 WebSocket 지원에 대한 자세한 내용은 여기를 참조하십시오.
이제 HTTP 클라이언트를 사용해 보겠습니다.
/* Setup an httpClient. */
HttpClient httpClient = httpClientBuilder ()
. setHost ( "localhost" ). setPort ( 8080 ). build ();
httpClient . start ();
URL, 포트를 통과 한 다음 시작을 호출합니다.
이제 HTTP 요청을 보내기 시작할 수 있습니다.
/* Send no param get. */
HttpResponse httpResponse = httpClient . get ( "/hello/mom" );
puts ( httpResponse );
HTTP 응답에는 서버의 결과 만 포함됩니다.
public interface HttpResponse {
MultiMap < String , String > headers ();
int code ();
String contentType ();
String body ();
}
http get 호출을 동기화하기위한 도우미 방법이 있습니다.
/* Send one param get. */
httpResponse = httpClient . getWith1Param ( "/hello/singleParam" ,
"hi" , "mom" );
puts ( "single param" , httpResponse );
/* Send two param get. */
httpResponse = httpClient . getWith2Params ( "/hello/twoParams" ,
"hi" , "mom" , "hello" , "dad" );
puts ( "two params" , httpResponse );
...
/* Send five param get. */
httpResponse = httpClient . getWith5Params ( "/hello/5params" ,
"hi" , "mom" ,
"hello" , "dad" ,
"greetings" , "kids" ,
"yo" , "pets" ,
"hola" , "neighbors" );
puts ( "5 params" , httpResponse );
PUTS 메소드는 System.out.println을 다소 수행하는 도우미 방법입니다.
처음 5 개의 매개 변수가 다루어집니다. 5 개를 넘어서, 당신은 httpbuilder를 사용해야합니다.
/* Send six params with get. */
final HttpRequest httpRequest = httpRequestBuilder ()
. addParam ( "hi" , "mom" )
. addParam ( "hello" , "dad" )
. addParam ( "greetings" , "kids" )
. addParam ( "yo" , "pets" )
. addParam ( "hola" , "pets" )
. addParam ( "salutations" , "all" ). build ();
httpResponse = httpClient . sendRequestAndWait ( httpRequest );
puts ( "6 params" , httpResponse );
Async 요청도 있습니다.
/* Using Async support with lambda. */
httpClient . getAsync ( "/hi/async" , ( code , contentType , body ) -> {
puts ( "Async text with lambda" , body );
});
Sys . sleep ( 100 );
/* Using Async support with lambda. */
httpClient . getAsyncWith1Param ( "/hi/async" , "hi" , "mom" , ( code , contentType , body ) -> {
puts ( "Async text with lambda 1 param n " , body );
});
Sys . sleep ( 100 );
/* Using Async support with lambda. */
httpClient . getAsyncWith2Params ( "/hi/async" ,
"p1" , "v1" ,
"p2" , "v2" ,
( code , contentType , body ) -> {
puts ( "Async text with lambda 2 params n " , body );
});
Sys . sleep ( 100 );
...
/* Using Async support with lambda. */
httpClient . getAsyncWith5Params ( "/hi/async" ,
"p1" , "v1" ,
"p2" , "v2" ,
"p3" , "v3" ,
"p4" , "v4" ,
"p5" , "v5" ,
( code , contentType , body ) -> {
puts ( "Async text with lambda 5 params n " , body );
});
Sys . sleep ( 100 );
[사용하기 쉬운 빠른 마이크로 서비스 http 클라이언트에 대해 자세히 알아보십시오.] -et-al, -json, -java-8-lambda).
QBIT는 대기열 뒤의 서비스를 실행할 수 있도록 허용합니다.
/* POJO service. */
final TodoManager todoManagerImpl = new TodoManager ();
/*
Create the service which manages async calls to todoManagerImpl.
*/
final Service service = serviceBuilder ()
. setServiceObject ( todoManagerImpl )
. build (). startServiceQueue ();
/* Create Asynchronous proxy over Synchronous service. */
final TodoManagerClientInterface todoManager =
service . createProxy ( TodoManagerClientInterface . class );
service . startCallBackHandler ();
System . out . println ( "This is an async call" );
/* Asynchronous method call. */
todoManager . add ( new Todo ( "Call Mom" , "Give Mom a call" ));
AtomicInteger countTracker = new AtomicInteger ();
//Hold count from async call to service... for testing and showing it is an async callback
System . out . println ( "This is an async call to count" );
todoManager . count ( count -> {
System . out . println ( "This lambda expression is the callback " + count );
countTracker . set ( count );
});
todoManager . clientProxyFlush (); //Flush all methods. It batches calls.
Sys . sleep ( 100 );
System . out . printf ( "This is the count back from the server %d n " , countTracker . get ());
프로그램 중 서비스에 대한 자세한 자습서가 작성되었습니다.
QBIT 이벤트 버스보다 자세한 예
QBIT에는 서비스 이벤트 버스도 있습니다. 이 예는 직원 혜택 서비스 예입니다.
두 개의 채널이 있습니다.
public static final String NEW_HIRE_CHANNEL = "com.mycompnay.employee.new";
public static final String PAYROLL_ADJUSTMENT_CHANNEL = "com.mycompnay.employee.payroll";
직원 객체는 다음과 같습니다.
public static class Employee {
final String firstName ;
final int employeeId ;
이 예제에는 Employeehiringservice, Bensepservice 및 PayrollService의 세 가지 서비스가 있습니다.
이러한 서비스는 Inproc 서비스입니다. QBIT는 WebSocket, HTTP 및 REST 원격 서비스를 지원하지만 현재로서는 Inproc 서비스에 중점을 두겠습니다. Inproc을 이해하면 원격을 이해하게됩니다.
Employeehiringservice는 실제로 다른 두 서비스로 이벤트를 발사합니다.
public class EmployeeHiringService {
public void hireEmployee ( final Employee employee ) {
int salary = 100 ;
System . out . printf ( "Hired employee %s n " , employee );
//Does stuff to hire employee
//Sends events
final EventManager eventManager =
serviceContext (). eventManager ();
eventManager . send ( NEW_HIRE_CHANNEL , employee );
eventManager . sendArray ( PAYROLL_ADJUSTMENT_CHANNEL ,
employee , salary );
}
}
직원과 급여를 보낼 수 있도록 SendArray에 전화하십시오. Payroll_AdJustment_channel의 리스너는 신입 사원 급여를 나타내는 직원과 INT를 모두 처리해야합니다. 이벤트 버스 프록시를 사용할 수도 있으므로 이벤트 버스에 전혀 전화 할 필요가 없습니다.
BenefitsService는 신입 사원을 고용하여 혜택 시스템에 등록 할 수 있습니다.
public static class BenefitsService {
@ OnEvent ( NEW_HIRE_CHANNEL )
public void enroll ( final Employee employee ) {
System . out . printf ( "Employee enrolled into benefits system employee %s %d n " ,
employee . getFirstName (), employee . getEmployeeId ());
}
아빠는 돈을받을 필요가 있습니다.
public static class PayrollService {
@ OnEvent ( PAYROLL_ADJUSTMENT_CHANNEL )
public void addEmployeeToPayroll ( final Employee employee , int salary ) {
System . out . printf ( "Employee added to payroll %s %d %d n " ,
employee . getFirstName (), employee . getEmployeeId (), salary );
}
}
직원은 Employeehiringservice의 직원 대상입니다.
따라서 혜택을 받고 지불 할 수 있습니다!
자세한 내용은 여기를 참조하십시오.
QBIT 이벤트 버스보다 자세한 예
이벤트 버스에 대한 자신의 인터페이스를 정의 할 수 있으며 QBIT와 함께 자신의 이벤트 버스를 사용할 수 있습니다. 서비스의 각 모듈에는 자체 내부 이벤트 버스가있을 수 있습니다.
자세한 내용을 알아 보려면 : QBIT MicroService 개인 이벤트 버스 및 QBIT Java MicroService Lib에서 이벤트 버스와의 인터페이스를 사용하여 작업합니다.
QBIT를 실제로 파악하려면 콜백의 개념을 파악해야합니다.
콜백은 QBIT에서 비동기 응답을 얻는 방법입니다.
서비스 방법을 호출하고 다시 전화합니다.
클라이언트 프록시는 콜백을 가질 수 있습니다.
public interface RecommendationServiceClient {
void recommend ( final Callback < List < Recommendation >> recommendationsCallback ,
final String userName );
}
콜백은 선택적 추가 오류 처리가있는 Java 8 소비자입니다.
public interface Callback < T > extends java . util . function . Consumer < T > {
default void onError ( java . lang . Throwable error ) { /* compiled code */ }
}
차단할 수있는 서비스는 콜백을 사용해야합니다. 따라서 다음 예제에서로드 셔가 차단 된 경우 값을 반환하는 대신 실제로 콜백을 사용해야합니다.
공개 클래스 추천 서비스 서비스 {
private final SimpleLRUCache < String , User > users =
new SimpleLRUCache <>( 10_000 );
public List < Recommendation > recommend ( final String userName ) {
User user = users . get ( userName );
if ( user == null ) {
user = loadUser ( userName );
}
return runRulesEngineAgainstUser ( user );
}
loadUser
로컬 캐시를 살펴보아야한다고 가정하고, 사용자를 찾을 수없는 경우, 오프 헤어 캐시를 살펴보고 찾지 못하면 사용자 서비스에서 사용자에게 캐시를 확인하고 아마도 폴백을로드해야합니다. 데이터베이스 또는 다른 서비스의 사용자 데이터. 다시 말해, loadUser
IO에서 잠재적으로 차단할 수 있습니다.
우리의 고객은 차단하지 않지만 우리의 서비스는 그렇습니다. RecommendationService
서비스로 돌아갑니다. 사용자로드에 대한 많은 캐시 히트를 얻으면 블록이 길지는 않지만, 거기에있을 것이고, 사용자에게 결함이있을 때마다 전체 시스템이 꽉 찼습니다. 우리가 할 수있는 것은 권장 요청을 처리 할 수 없다면 UserDataService
에 비동기 호출을합니다. 해당 비동기 콜백이 다시 오면 해당 요청을 처리합니다. 그 동안, 우리는 최대한 빨리 추천 목록 요청을 처리합니다. 우리는 결코 차단하지 않습니다.
서비스를 다시 방문합시다. 우리가해야 할 첫 번째 일은 서비스 방법이 콜백을하는 것입니다. 그렇게하기 전에 몇 가지 규칙을 설정합시다.
public class RecommendationService {
public void recommend ( final Callback < List < Recommendation >> recommendationsCallback ,
final String userName ) {
이제 우리는 콜백을 받고 있으며이 권장 사항 생성 요청을 처리 할시기를 결정할 수 있습니다. 필요한 사용자 데이터가 메모리 인 경우 즉시 수행 할 수 있습니다.
public void recommend ( final Callback < List < Recommendation >> recommendationsCallback ,
final String userName ) {
/** Look for user in user cache. */
User user = users . get ( userName );
/** If the user not found, load the user from the user service. */
if ( user == null ) {
...
} else {
/* Call the callback now because we can handle the callback now. */
recommendationsCallback . accept ( runRulesEngineAgainstUser ( user ));
}
}
사용자가 캐시에서 찾을 수있는 경우, 권장 규칙을 메모리에서 실행하고 콜백을 즉시 권장합니다 recommendationsCallback.accept(runRulesEngineAgainstUser(user))
.
흥미로운 부분은 사용자에게로드하지 않으면 우리가하는 일입니다.
public void recommend ( final Callback < List < Recommendation >> recommendationsCallback ,
final String userName ) {
/** Look for user in users cache. */
User user = users . get ( userName );
/** If the user not found, load the user from the user service. */
if ( user == null ) {
/* Load user using Callback. */
userDataService . loadUser ( new Callback < User >() {
@ Override
public void accept ( final User loadedUser ) {
handleLoadFromUserDataService ( loadedUser ,
recommendationsCallback );
}
}, userName );
}
...
여기서 우리는 콜백을 사용하여 사용자를로드하고 사용자가로드되면 handleLoadFromUserDataService
호출하여 콜백 처리에 대한 일부 관리를 추가하여 지금은 아니지만이 호출을 처리 할 수 있습니다.
public void recommend ( final Callback < List < Recommendation >> recommendationsCallback ,
final String userName ) {
/** Look for user in users cache. */
User user = users . get ( userName );
/** If the user not found, load the user from the user service. */
if ( user == null ) {
/* Load user using lambda expression. */
userDataService . loadUser (
loadedUser -> {
handleLoadFromUserDataService ( loadedUser ,
recommendationsCallback );
}, userName );
}
...
이와 같은 람다를 사용하면 코드를 더 읽기 쉽고 간결하게 만들지 만 람다 표현식을 깊이 둥지하지 마십시오. 그렇지 않으면 코드 유지 보수 악몽이 생길 것입니다. 신중하게 사용하십시오.
우리가 원하는 것은 사용자 서비스 시스템이 스토어에서 사용자를로드 한 후 권장 사항 요청을 처리하는 것입니다.
public class RecommendationService {
private final SimpleLRUCache < String , User > users =
new SimpleLRUCache <>( 10_000 );
private UserDataServiceClient userDataService ;
private BlockingQueue < Runnable > callbacks =
new ArrayBlockingQueue < Runnable >( 10_000 );
...
public void recommend ( final Callback < List < Recommendation >> recommendationsCallback ,
final String userName ) {
...
}
/** Handle defered recommendations based on user loads. */
private void handleLoadFromUserDataService ( final User loadedUser ,
final Callback < List < Recommendation >> recommendationsCallback ) {
/** Add a runnable to the callbacks queue. */
callbacks . add ( new Runnable () {
@ Override
public void run () {
List < Recommendation > recommendations = runRulesEngineAgainstUser ( loadedUser );
recommendationsCallback . accept ( recommendations );
}
});
}
public class RecommendationService {
...
/** Handle defered recommendations based on user loads. */
private void handleLoadFromUserDataService ( final User loadedUser ,
final Callback < List < Recommendation >> recommendationsCallback ) {
/** Add a runnable to the callbacks list. */
callbacks . add (() -> {
List < Recommendation > recommendations = runRulesEngineAgainstUser ( loadedUser );
recommendationsCallback . accept ( recommendations );
});
}
중요한 부분은 UserDataService
에서 콜백 호출을받을 때마다 CPU 집약적 권장 규칙을 수행하고 발신자 콜백을 수행한다는 것입니다. 정확히 말하지만, 우리가하는 일은 콜백 대기열에 달리기가 가능한 일을하고 나중에 우리는 언제부터 반복 할 것인가?
큐가 비어있을 때 RecommendationService
알릴 수 있고 새로운 배치를 시작했으며 배치 제한에 도달했을 때 알 수 있습니다. 이것은 모두 UserDataService
의 콜백을 처리하기에 좋은시기입니다.
@ QueueCallback ({
QueueCallbackType . EMPTY ,
QueueCallbackType . START_BATCH ,
QueueCallbackType . LIMIT })
private void handleCallbacks () {
flushServiceProxy ( userDataService );
Runnable runnable = callbacks . poll ();
while ( runnable != null ) {
runnable . run ();
runnable = callbacks . poll ();
}
}
다른 마이크로 서비스에서 콜백을 처리 할 때 다른 서비스에서 콜백을 처리하려는 것을 기억하는 것이 중요합니다. 기본적으로 대기중인 클라이언트가 있습니다 (비동기 대기하지만 여전히).이 클라이언트는 HTTP 통화와 같은 열린 TCP/IP 연결을 나타낼 수 있으므로 더 많은 요청을 처리하기 전에 클라이언트를 닫는 것이 가장 좋습니다. 사용자가 사용자 서비스를로드 할 수있는 열린 연결이 있습니다.
콜백에 대해 자세히 알아 보려면 Plesae는 [Qbit Java Microservice lib 콜백 기초] ([거친 컷] Qbit MicroService lib 콜백으로 작업)를 읽습니다.
public class ServiceWorkers {
public static RoundRobinServiceDispatcher workers () {...
public static ShardedMethodDispatcher shardedWorkers ( final ShardRule shardRule ) {...
샤드 근로자 (메모리, 스레드 안전, CPU 집약적 인 서비스) 또는 IO를위한 근로자 또는 외국 서비스 또는 외국 버스와 대화 할 수 있습니다.
다음은 3 명의 서비스 근로자가있는 작업자 풀을 사용하는 예입니다.
무언가를하는 서비스가 있다고 가정 해 봅시다.
//Your POJO
public class MultiWorker {
void doSomeWork (...) {
...
}
}
이제 이것은 일종의 IO를 수행하고 당신은 하나뿐만 아니라 이행의 은행을 가지고 있기 때문에 IO를 병렬로 수행 할 수 있습니다. 성능 테스트 후에는 세 가지가 마법의 숫자라는 것을 알았습니다.
이 서비스에 액세스하기 위해 API를 사용하려고합니다.
public interface MultiWorkerClient {
void doSomeWork (...);
}
이제 이것들의 은행을 만들어 사용합시다.
먼저 스레드/큐/마이크로치를 추가하는 QBIT 서비스를 만듭니다.
/* Create a service builder. */
final ServiceBuilder serviceBuilder = serviceBuilder ();
/* Create some qbit services. */
final Service service1 = serviceBuilder . setServiceObject ( new MultiWorker ()). build ();
final Service service2 = serviceBuilder . setServiceObject ( new MultiWorker ()). build ();
final Service service3 = serviceBuilder . setServiceObject ( new MultiWorker ()). build ();
이제 ServiceWorkers 객체에 추가하십시오.
ServiceWorkers dispatcher ;
dispatcher = workers (); //Create a round robin service dispatcher
dispatcher . addServices ( service1 , service2 , service3 );
dispatcher . start (); // start up the workers
서비스, Pojos 및 Method Consumer, Method Dispatcher를 서비스 번들에 추가 할 수 있습니다. 서비스 번들은 QBIT에 대한 통합 지점입니다.
새로운 서비스 직원을 추가합시다. ServiceWorkers는 ServiceMethoddispatcher입니다.
/* Add the dispatcher to a service bundle. */
bundle = serviceBundleBuilder (). setAddress ( "/root" ). build ();
bundle . addServiceConsumer ( "/workers" , dispatcher );
bundle . start ();
우리는 아마도 서비스 번들에 헬퍼 방법을 추가 할 것입니다. 그래서 대부분의 호출에서 발생할 수 있습니다.
이제 근로자를 사용하기 시작할 수 있습니다.
/* Start using the workers. */
final MultiWorkerClient worker = bundle . createLocalProxy ( MultiWorkerClient . class , "/workers" );
이제 Spring 또는 Guice를 사용하여 빌더와 서비스 번들을 구성 할 수 있습니다. 그러나 QBIT 내부를 테스트하고 이해하는 데 좋은 위의 것과 같이 할 수 있습니다.
QBIT는 또한 CPU와 같은 리소스를 보충하는 데 유용한 Sharded Services의 개념을 지원합니다 (사용자 추천 엔진을 위해 각 CPU 코어에서 각 CPU 코어에서 규칙 엔진을 실행).
QBIT는 서비스를 제공하는 방법을 모르고 힌트를 주어야합니다. 당신은 샤드 규칙을 통해 이것을합니다.
public interface ShardRule {
int shard ( String methodName , Object [] args , int numWorkers );
}
우리는 서비스에 대한 첫 번째 인수가 사용자 이름 인 앱에서 작업 한 다음이를 사용하여 CPU 집약적 인 내부 규칙 엔진으로 전화를 걸었습니다. 이 기술은 작동합니다. :)
ServiceWorkers 클래스에는 샤드 작업자 풀을 만드는 방법이 있습니다.
public static ShardedMethodDispatcher shardedWorkers ( final ShardRule shardRule ) {
...
}
사용하려면 서비스 작업자를 만들 때 샤드 키를 전달하십시오.
dispatcher = shardedWorkers (( methodName , methodArgs , numWorkers ) -> {
String userName = methodArgs [ 0 ]. toString ();
int shardKey = userName . hashCode () % numWorkers ;
return shardKey ;
});
그런 다음 ServiceWorkers 구성에 서비스를 추가하십시오.
int workerCount = Runtime . getRuntime (). availableProcessors ();
for ( int index = 0 ; index < workerCount ; index ++) {
final Service service = serviceBuilder
. setServiceObject ( new ContentRulesEngine ()). build ();
dispatcher . addServices ( service );
}
그런 다음 이전과 같이 서비스 번들에 추가하십시오.
dispatcher . start ();
bundle = serviceBundleBuilder (). setAddress ( "/root" ). build ();
bundle . addServiceConsumer ( "/workers" , dispatcher );
bundle . start ();
그런 다음 사용하십시오.
final MultiWorkerClient worker = bundle . createLocalProxy ( MultiWorkerClient . class , "/workers" );
for ( int index = 0 ; index < 100 ; index ++) {
String userName = "rickhigh" + index ;
worker . pickSuggestions ( userName );
}
public class ServiceWorkers {
...
public static ShardedMethodDispatcher shardOnFirstArgumentWorkers () {
...
}
...
public static ShardedMethodDispatcher shardOnFifthArgumentWorkers () {
...
}
public static ShardedMethodDispatcher shardOnBeanPath ( final String beanPath ) {
...
}
ShardonbeanPath를 사용하면 복잡한 Bean Path Navigation Call을 생성하고 해당 속성을 사용하여 샤드를 사용할 수 있습니다.
/* shard on 2nd arg which is an employee
Use the employees department's id property. */
dispatcher = shardOnBeanPath ( "[1].department.id" );
/* Same as above. */
dispatcher = shardOnBeanPath ( "1/department/id" );
서비스 샤딩 및 서비스 근로자에 대한 자세한 내용은 여기를 참조하십시오
위키에서 더 많은 것을 찾을 수 있습니다. 또한 커밋을 따르십시오. 우리는 바쁜 비버였습니다. QBIT Java -JSON, REST, WEBSOCKE에 대한 MicroService lib.