Qbit Java Micorservices الدروس التعليمية | موقع QBIT | QBIT يستخدم REAKT | يعمل QBIT مع Vert.x | Reakt Vertx
جافا microservice lib. QBIT هي برمجة تفاعلية لوب لبناء الخدمات المجهرية - JSON و HTTP و WebSocket و REST. يستخدم QBIT البرمجة التفاعلية لبناء مرونة راحة ، وخدمات ويب سحابة قائمة على WebSockets. تطورت SOA للهاتف المحمول والسحابة. ServiceScovery ، الصحة ، الخدمات الإحصائية التفاعلية ، الأحداث ، البرمجة التفاعلية الاصطلاحية Java للخدمات الدقيقة.
هل لديك سؤال؟ اسأل هنا: QBIT Google Group.
كل شيء قائمة انتظار. لديك خيار. يمكنك احتضانها والسيطرة عليها. يمكنك تحسين ذلك. أو يمكنك الاختباء وراء التجريدات. QBIT يفتحك حتى تطل على ما يجري ، ويسمح لك بسحب بعض الرافعات دون بيع روحك.
QBIT هي مكتبة ليست إطار عمل. يمكنك مزج وتوافق QBIT مع الربيع ، guice ، إلخ.
يدعم QBIT الآن وعود REAKT المحدودة لكوائد العميل المحلية والبعيدة. هذا يعطي واجهة برمجة تطبيقات بطلاقة لطيفة للبرمجة غير المتزامنة.
employeeService . lookupEmployee ( "123" )
. then (( employee )-> {...}). catchError (...). invoke ();
تعود عمليات اتصال QBIT الآن أيضًا إلى عمليات رد الاتصال دون كسر عقد QBIT لعمليات الاسترجاعات.
انظر REAKT الوعود المحدودة لمزيد من التفاصيل.
تم نشر 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'
تم نشرها في العديد من الشركات الكبيرة 100. يعمل QBIT الآن مع Vertx (مستقل أو مضمن). يمكنك أيضًا استخدام QBIT في مشاريع غير QBIT ، إنه مجرد lib.
Apache 2
لدى QBIT خدمات inproc ، والراحة microservices و WebSocket Microservices بالإضافة إلى ناقل حدث للخدمة في الخدمة (والتي يمكن أن تكون لكل وحدة أو لكل تطبيق). وهو يدعم العمال والخدمات في الذاكرة.
قبل وصف المزيد ، إليك خدمتان للعينة:
@ 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 ولكن تطبيق Java يستخدم QBIT LIB. يتيح لك QBIT العمل مع Java Util Conversion ، ولا يسعى إلى إخفاءه منك. فقط أحاول إخراج اللدغة منه.
لقد استخدمنا تقنيات في BOON و QBIT مع نجاح كبير في تطبيقات عالية الأداء ، عالية الأداء ، عالية القابلة للتطبيق. لقد ساعدنا العملاء على التعامل مع 10x الحمل مع 1/10 خوادم منافسيهم باستخدام تقنيات في QBIT. QBIT هو أننا سئمت من الوصول إلى قائمة انتظار وصول اليدين.
غالبًا ما تأتي أفكار Boon و Qbit من جميع أنحاء الويب. نرتكب أخطاء. أشر لهم. كمطور لـ Boon و QBIT ، نحن زملاء المسافرين. إذا كان لديك فكرة أو تقنية تريد مشاركتها ، فنحن نستمع.
كان مصدر إلهام كبير لـ Boon/QBIT هو Vertx و Akka و GO Connels و Active Comples و Entertaining Model Therbing و Actor و Mechanical Symbers.
QBIT لديه أفكار مماثلة للعديد من الأطر. كلنا نقرأ نفس الأوراق. حصلت QBIT على إلهام من أوراق LMAX Disruptor و POST المدونة حول قائمة انتظار نقل الارتباط مقابل Disruptor. كان لدينا بعض النظريات حول قوائم الانتظار التي ألهمتنا نشر المدونة لتجربتها. يتم نشر بعض هذه النظريات في بعض أكبر البرامج الوسيطة التي تُعرف العلامات التجارية التي تُعرف بها أسماءها في جميع أنحاء العالم. وهكذا ولد QBIT.
استغرق QBIT أيضًا الكثير من الإلهام من خلال العمل الرائع الذي قام به تيم فوكس على Vertx. كان المشروع الأول الذي يستخدم شيئًا يمكن أن يطلق عليه بالفعل QBIT (وإن كان QBIT المبكر) يستخدم VERTX على خدمة microservice على الويب/الجوال لتطبيق يمكن أن يكون له 80 مليون مستخدم. كانت هذه التجربة مع Vertx و QBIT المبكرة هي التي أدت إلى تطوير QBIT والتطور. تم بناء QBIT على أكتاف العمالقة (netty/vertx).
Dring Disruptor: لا ، يمكنك استخدام QBIT لكتابة المكونات الإضافية لمرض الربيع الذي أفترضه ، لكن QBIT لا يتنافس مع DRIPT DISPORTOR. Spring Boot/Spring MVC: لا. نستخدم نفس التعليقات التوضيحية ولكن QBIT موجهة للخدمات الدقيقة عالية السرعة في الذاكرة. هو أشبه أككا من الحذاء الربيعي. يحتوي QBIT على مجموعة فرعية من ميزات Spring MVC موجهة فقط للخدمات الدقيقة ، أي WebSocket RPC ، REST ، JSON MASTALING ، إلخ. AKKA: لا. Akka لديها مفاهيم مماثلة لكنها تتخذ نهجا مختلفا. تركز QBIT أكثر على Java ، و Microservices (REST ، JSON ، WebSocket) من AKKA. LMAX Disruptor: لا. في الواقع ، يمكننا استخدام Disruptor كما في قوائم الانتظار التي يستخدمها QBIT أسفل الأغطية.
(تمت إزالة المعايير المبكرة. لقد كانت هنا. حصلت 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 أن تفعل شمالًا من 100 مليون مكالمة Ping Pong في الثانية وهي سرعة مذهلة (التي تصل إلى 200 متر). يدعم QBIT أيضًا خدمات الاتصال عبر REST و WebSocket. QBIT هي الخدمات الدقيقة بالمعنى الخالص على الويب: JSON ، HTTP ، WebSocket ، إلخ. يستخدم QBIT تجميعًا صغيرًا لدفع الرسائل عبر الأنبوب (قائمة الانتظار ، IO ، وما إلى ذلك) بشكل أسرع لتقليل تسليم مؤشر الترابط.
QBIT هو Java Microservice LIB يدعم الراحة ، JSON و WebSocket. إنه مكتوب في Java ، لكن يمكننا في يوم من الأيام كتابة نسخة في Rust أو Go أو C# (ولكن هذا يتطلب يوم دفع كبير).
Service Pojo (كائن Java القديم البسيط) وراء قائمة انتظار يمكن أن تتلقى مكالمات الأسلوب عبر مكالمات أو أحداث الوكيل (قد تحتوي على أحداث واحدة لإدارة مؤشرات الترابط ومكالمات الأسلوب والاستجابات أو اثنين لمكالمات الطريقة والأحداث والآخر للاستجابات حتى معالجات الاستجابة لا تمنع الخدمة. يمكن للخدمات استخدام التعليقات التوضيحية على نمط MVC لفضح أنفسهم للعالم الخارجي عبر REST و WebSocket.
ServiceBundle العديد من pojos وراء قائمة انتظار استجابة واحدة والعديد من قوائم الانتظار. قد يكون هناك موضوع واحد لجميع الردود أم لا. كما يمكن أن تكون قائمة انتظار واحدة تلقي.
قائمة انتظار موضوع يدير قائمة انتظار. وهو يدعم التجميع. لديها أحداث لفرقة ، وصولها إلى Legnsbatch ، و IDLE. يمكنك الاستماع إلى هذه الأحداث من الخدمات التي تجلس خلف قائمة انتظار. ليس عليك استخدام الخدمات. يمكنك استخدام قائمة الانتظار المباشرة. في QBIT ، لديك طوابير المرسل ودرجات قوائم قوائم أجهزة الاستقبال. يتم فصلها لدعم الضخم الدقيق.
ServiceNdPointServer ServiceBundle التي تتعرض للاتصالات REST و WebSocket.
EventBus EventBus هي وسيلة لإرسال الكثير من الرسائل إلى الخدمات التي قد تكون مقترنة بشكل فضفاض.
ClientProxy ClientProxy هي وسيلة لاستدعاء الخدمة من خلال واجهة ASYNC ، يمكن أن تكون الخدمة inproc (نفس العملية) أو عن بُعد عبر WebSocket.
QBIT غير المحظور هو lib غير المحظور. يمكنك استخدام عمليات الاسترجاعات عبر Java 8 Lambdas. يمكنك أيضًا إرسال رسائل الحدث والحصول على ردود. تم دمج المراسلة في النظام بحيث يمكنك بسهولة تنسيق المهام المعقدة. يأخذ QBIT نهجًا موجهًا نحو كائن لتطوير الخدمة ، لذا تبدو الخدمات مثل خدمات Java العادية التي تكتبها بالفعل ، ولكن الخدمات تعيش خلف قائمة انتظار/موضوع. هذا ليس مفهومًا جديدًا. فعلت Microsoft هذا مع DCOM/COM ووصفته كائنات نشطة. Akka يفعل ذلك مع الجهات الفاعلة ودعاهم الجهات الفاعلة المكتوبة بقوة. المفاهيم المهمة هي أنك تحصل على سرعة المراسلة التفاعلية وأسلوب الممثل ولكنك تتطور في نهج OOP الطبيعي. QBIT ليس الأول. QBIT ليس هو الوحيد.
السرعة QBIT سريعة جدا. هناك بالطبع مساحة كبيرة للتحسين. ولكن بالفعل 200M+ TPS Inproc Ping Pong ، حافلة الأحداث من 10 م-20 م+ TPS ، ومكالمات 500 كيلو TPS RPC عبر WebSocket/JSON ، وما إلى ذلك. يجب القيام بمزيد من العمل لتحسين السرعة ، ولكن الآن أصبح سريعًا بما فيه الكفاية حيث نركز أكثر على قابلية الاستخدام. يستخدم دعم JSON BOON افتراضيًا وهو ما يصل إلى 4x أسرع من محلات JSON الأخرى لـ REST/JSON ، و WebSocket/JSON CASE.
يوفر البرمجة التفاعلية QBIT مفاعلًا لإدارة مكالمات ASYNC. يتيح ذلك معالجة عمليات الاسترجاعات على نفس الخيط الذي يطلق عليه ويوفر مهلة ومعالجة الأخطاء. اقرأ البرنامج التعليمي للمفاعل لإنشاء برمجة الخدمة الجزئية التفاعلية
اكتشاف الخدمة المدمجة لدعم لاكتشاف الخدمة. وهذا يشمل التكامل مع القنصل.
الإحصائيات المدمجة في دعم الإحصائيات. يمكن دمج Satservice مع STATSD (الجرافيت ، Grafana ، DataDog ، إلخ) لنشر الإحصائيات السلبية. أو يمكنك الاستعلام عن محرك الإحصائيات والرد على الإحصائيات (التهم والتوقيتات والمستويات). STATSSERVICE هو نظام الإحصائيات التفاعلية التي يمكن تجميعها. إن الخدمات الإحصائية تفاعلية من حيث أن خدماتك يمكن أن تنشرها والاستعلام عنها والتفاعل بناءً على النتائج. يمكنك تنفيذ أشياء مثل الحد من المعدل والرد على زيادة معدل شيء ما. يتكامل نظام ServicedIscovery مع نظام HealthSystem و Consul لتشغيل كل من خدماتك الداخلية التي تشكل الخدمة الصغيرة ونشر المركب المتوفر لخدمتك الصغيرة إلى نقطة نهاية HTTP واحدة أو مفتاح Mans الميت في القنصل (TTL).
الحديث رخيص. دعونا نلقي نظرة على بعض التعليمات البرمجية. يمكنك الحصول على نزهة مفصلة في الويكي. لدينا الكثير من الوثائق بالفعل.
سنقوم بإنشاء خدمة تتعرض من خلال REST/JSON.
للاستعلام عن حجم قائمة تودو:
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
(موافق) لمكالمة غير void (مكالمة لها عائد أو رد اتصال). إذا لم يكن لعملية REST عودة أو لا رد من رد الاتصال ، فإن QBIT يرسل 202
(مقبولة). قد تكون هناك أوقات تريد فيها إرسال 201 (تم إنشاؤها) أو بعض التعليمات البرمجية الأخرى التي ليست استثناء. يمكنك القيام بذلك عن طريق تعيين code
على @RequestMapping
. افتراضيًا ، يكون الرمز -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
للخدمات الداخلية أيضًا. غالبًا ما تكون تستخدم جهاز CallbackBuilder أو مفاعل QBIT لإدارة مكالمات الخدمة.
ليس عليك إرجاع مكالمات REST نموذج 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 ();
}
هذا هو. يوجد أيضًا من دعم WebSocket مع توليد الوكيل جانب العميل حتى تتمكن من الاتصال بالخدمات بمعدل ملايين المكالمات في الثانية.
@ RequestMapping ( "/adder-service" )
public class AdderService {
@ RequestMapping ( "/add/{0}/{1}" )
public int add ( @ PathVariable int a , @ PathVariable int b ) {
return a + b ;
}
}
يمكنك دائمًا استدعاء خدمات QBIT عبر وكيل WebSocket. ميزة وكيل WebSocket هي أنها تتيح لك تنفيذ 1M RPC+ ثانية (مليون مكالمة عن بُعد كل ثانية).
/* 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 للاتصال بالخدمة ASYNC.
interface AdderServiceClientInterface {
void add ( Callback < Integer > callback , int a , int b );
}
قم بإنشاء عميل خدمة WebSocket الذي يتم إدراكه.
final Client client = clientBuilder . setServiceDiscovery ( serviceDiscovery , "echo" )
. setUri ( "/echo" ). setProtocolBatchSize ( 20 ). build (). startClient ();
final EchoAsync echoClient = client . createProxy ( EchoAsync . class , "echo" );
حاليًا ، ستقوم clientBuilder
بتحميل جميع نقاط نهاية الخدمة المسجلة تحت اسم الخدمة ، واختيار واحدة بشكل عشوائي.
يتضمن ServiceDiscovery القنصل ، ومشاهدة ملفات JSON على القرص ، و DNS. من السهل كتابة اكتشاف الخدمة الخاص بك أيضًا وتوصيله بـ QBIT.
في المستقبل ، يمكننا Roundrobin المكالمات أو مكالمات Shard إلى WebSocket Service و/أو تقديم الفشل التلقائي في حالة إغلاق الاتصال. نقوم بذلك لحافلة الحدث التي تستخدم خدمة اكتشاف الخدمة ولكنها لم تخبئ في كعب العميل القائم على WebSocket حتى الآن.
مثال العميل الأخير يستخدم WebSocket. يمكنك أيضًا استخدام REST ، واستخدام معاملات URI التي نقوم بإعدادها بالفعل. الباقي لطيف ولكنه سيكون أبطأ من دعم WebSocket.
يشحن QBIT مع عميل HTTP صغير لطيف. يمكننا استخدامه.
يمكنك استخدامه لإرسال مكالمات ASYNC ورسائل WebSocket مع عميل HTTP.
هنا سوف نستخدم عميل 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 http://localhost:7000/services/adder-service/add/2/2
شاهد هذا المثال الكامل هنا: QBIT Microservice بدء تشغيل البرنامج التعليمي.
QBIT URI Params وعميل WebSocket Proxy
لدى 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 لعمليات الاسترجاعات بحيث يكون الرمز ضيقًا وصغيرًا.
تعرف على المزيد حول دعم WebSocket من QBIT Microservice
الآن ، لنجرب عميل 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 الحصول على المكالمات.
/* 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 أكثر أو أقل بالمناسبة.
يتم تغطية المعاملات الخمسة الأولى. بعد خمسة ، يجب عليك استخدام 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 );
هناك مكالمات غير متزامنة للحصول على الحصول على أيضا.
/* 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 للخدمة الدقيقة السهلة للاستخدام هنا] (https://github.com/advantage/qbit/wiki/٪5bdoc٪5d-using-qbit-microservice-lib's-httpclient-get ، post ، -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 ;
يحتوي هذا المثال على ثلاث خدمات: خدمة الموظف ، وخدمة الفوائد ، ورسالة الرواتب.
هذه الخدمات هي خدمات inproc. يدعم QBIT WebSocket و HTTP والخدمات البعيدة أيضًا ، ولكن في الوقت الحالي ، دعونا نركز على الخدمات inproc. إذا فهمت InProc ، فسوف تفهم جهاز التحكم عن بُعد.
الموظف Hiringservice يطلق فعليا من الأحداث إلى خدمتين أخريين.
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 الذي يمثل راتب الموظفين الجدد. يمكنك أيضًا استخدام وكلاء ناقل الحدث حتى لا تضطر إلى الاتصال في حافلة الحدث على الإطلاق.
تستمع خدمة الفوائد للموظفين الجدد التي يتم تعيينها حتى يتمكنوا من تسجيلهم في نظام الفوائد.
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 );
}
}
الموظف هو كائن الموظف من خدمة الموظف.
حتى تتمكن من الحصول على فوائدك ودفعها!
ابحث عن مزيد من التفاصيل هنا:
حافلة حدث 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 */ }
}
يجب أن تستخدم الخدمات التي يمكنها حظر عمليات الاسترجاعات. وبالتالي ، إذا تم حظر LoadUser في المثال التالي ، فيجب عليه استخدام رد اتصال بدلاً من إرجاع القيمة.
توصيات الفئة العامة {
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
. عندما يعود رد الاتصال Async ، نتعامل مع هذا الطلب. في الوقت نفسه ، نتعامل مع قوائم التوصية في أسرع وقت ممكن. نحن لا نحظر أبدا.
لذلك دعونا نعيد النظر في الخدمة. أول شيء سنفعله هو جعل طريقة الخدمة تأخذ رد الاتصال. قبل أن نفعل ذلك ، دعنا نضع بعض القواعد.
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 );
}
...
إن استخدام Lambdas مثل هذا يجعل الرمز أكثر قابلية للقراءة و terse ، ولكن تذكر عدم تعبيرات Lambda بعمق أو ستقوم بإنشاء كابوس لصيانة التعليمات البرمجية. استخدمها بحكمة.
ما نريده هو التعامل مع طلب التوصيات بعد تحميل نظام خدمة المستخدم المستخدم من متجره.
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
، نقوم بعد ذلك بإجراء قواعد التوصية المكثفة في وحدة المعالجة المركزية ومتصل الاتصال. حسنًا ، ليس بالضبط ، ما نفعله هو enqueue a runnable في قائمة انتظار عمليات الاسترجاعات لدينا ، وبعد ذلك سوف نتكرر من خلال هؤلاء ولكن متى؟
يمكن إخطار 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 ();
}
}
من المهم أن تتذكر عند التعامل مع عمليات الاسترجاعات من الخدمات الدقيقة الأخرى التي تريد التعامل معها من عمليات الاسترجاع من الخدمة الأخرى قبل التعامل مع المزيد من الطلبات المتوفرة من العملاء. في الأساس ، لديك عملاء ينتظرون (انتظار غير متزامن ولكن لا يزال) ، وقد يمثل هؤلاء العملاء اتصال TCP/IP مفتوح مثل مكالمة HTTP ، لذلك من الأفضل إغلاقهم قبل التعامل مع المزيد من الطلبات وكما قلنا أنهم ينتظرون بالفعل حول اتصال مفتوح للمستخدمين لتحميل خدمة المستخدم.
لمعرفة المزيد حول عمليات الاسترجاعات ، قرأت Plesae [QBIT Java Microservice LIB LIB LIBLACTALS] ([CUT CUT] QBIT Microservice LIB تعمل مع عمليات الاسترداد).
public class ServiceWorkers {
public static RoundRobinServiceDispatcher workers () {...
public static ShardedMethodDispatcher shardedWorkers ( final ShardRule shardRule ) {...
يمكنك تكوين العمال المشتعلين (للخدمات في الذاكرة ، أو الخدمات الآمنة ، أو وحدة المعالجة المركزية المكثفة) ، أو العمال في IO أو التحدث إلى الخدمات الأجنبية أو الحافلات الأجنبية.
فيما يلي مثال يستخدم تجمع العمال مع ثلاثة عمال خدمة فيه:
لنفترض أن لديك خدمة تفعل شيئًا:
//Your POJO
public class MultiWorker {
void doSomeWork (...) {
...
}
}
الآن هذا يفعل نوعًا ما من IO وتريد أن يكون لديك ضفة من هذه التشغيل وليس فقط واحد حتى تتمكن من القيام IO بالتوازي. بعد بعض اختبارات الأداء ، اكتشفت أن Three هو الرقم السحري.
تريد استخدام واجهة برمجة التطبيقات الخاصة بك للوصول إلى هذه الخدمة:
public interface MultiWorkerClient {
void doSomeWork (...);
}
الآن دعنا ننشئ ضفة من هذه ونستخدمه.
قم أولاً بإنشاء خدمات QBIT التي تضيف مؤشر الترابط/قائمة الانتظار/microbatch.
/* 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 dispatcher ;
dispatcher = workers (); //Create a round robin service dispatcher
dispatcher . addServices ( service1 , service2 , service3 );
dispatcher . start (); // start up the workers
يمكنك إضافة الخدمات ، Pojos والمستهلكين ، مرسلي الأسلوب إلى حزمة خدمة. حزمة الخدمة هي نقطة تكامل في QBIT.
دعنا نضيف عمال الخدمة الجدد لدينا. عمال الخدمة هو 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 أيضًا مفهوم الخدمات المتقطعة وهو أمر جيد لارتفاع الموارد مثل وحدة المعالجة المركزية (قم بتشغيل محرك القواعد في كل قلب وحدة المعالجة المركزية لمحرك توصية المستخدم).
QBIT لا يعرف كيفية تقويم خدماتك ، عليك أن تعطيها تلميحًا. أنت تفعل هذا من خلال قاعدة شارد.
public interface ShardRule {
int shard ( String methodName , Object [] args , int numWorkers );
}
لقد عملنا على تطبيق حيث كانت الحجة الأولى للخدمات هي اسم المستخدم ، ثم استخدمنا ذلك لمكالمات Shard إلى محرك قواعد CPU المكثفة في الذاكرة. هذه التقنية تعمل. سائدا
لدى فئة ServiceWorkers طريقة لإنشاء تجمع العمال المشتعلة.
public static ShardedMethodDispatcher shardedWorkers ( final ShardRule shardRule ) {
...
}
لاستخدامك فقط تمرير مفتاح Shard عند إنشاء عمال الخدمة.
dispatcher = shardedWorkers (( methodName , methodArgs , numWorkers ) -> {
String userName = methodArgs [ 0 ]. toString ();
int shardKey = userName . hashCode () % numWorkers ;
return shardKey ;
});
ثم أضف خدماتك إلى تكوين عمال الخدمة.
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 إنشاء مكالمة معقدة للمسار في مسار الفول واستخدام خاصيةها لتشارد.
/* 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 the microservice lib لـ Java - Json ، Rest ، WebSocket.