JavaのRPCリモート呼び出し手書き分散システムフレームワーク

注目点は、迷子にしないでください。Java関連のテクノロジーと継続的に更新情報!

、RPCの紹介

彼らは最近、Hadoopの基礎となる通信はRPCによって達成されます。

RPC(リモートプロシージャコールプロトコル)、リモートコール:リモートプロシージャコール隠された内容の通信ネットワークが、あなたがコンピュータをプログラムするために別のコンピュータのサブルーチンコールを実行することを可能にする一般的な分散型ネットワーク通信プロトコルでありますこのプログラムの追加なしのユーザ対話するように。RPCで実装分散システム間のほとんどの通信

二、RPC要求手順
ここに画像を挿入説明

  1. クライアントは、サービスを呼び出す要求を送信します
  2. この方法は、ネットワークが要求を開始し、サービス側のアドレス、formatパラメータでカプセル化され、エージェントのクライアントスタブを呼び出します
  3. サーバにネットワークによって送信されたメッセージは、サーバ・スタブは、メッセージを受信し、対応するサービスコールをローカル反射をアンパック
  4. ローカルサービスの実行はサーバースタブに結果を返し、サーバスタブは、再度クライアントパッケージにメッセージを発生します
  5. 最終的な結果を得るために復号されたメッセージを受信したクライアントスタブ。

三、RPCフレームワークのアーキテクチャ

RPCフレームワーク、コンポーネントが必要に書きますか?

  1. シリアル化。シリアライゼーション主な役割は、ネットワークを介して永続ストレージまたは伝送に書き込むバイトのストリームにオブジェクトが構成されています。
  2. 一般的に、JDKの動的プロキシまたはCGLIBを使用してリモートプロキシオブジェクト、
  3. 代理店サービスは、レジストリの飼育係を公開します
  4. ネットワーク通信、イベント駆動型モードリアクトル

四、RPC例示的なフレーム

  1. サービスプロバイダは、サービス・インターフェース定義とサービス実装クラスを提供し、サーバ側で実行されています
  2. サービス出版社は、サーバー側で実行すると、ローカルサービスを担当してリモートサービス、リモート管理サービス、消費者に提供するサービスに公開
  3. 消費者サービスは、クライアント上で実行して、リモートプロキシオブジェクトを介してリモートサービスを呼び出します

サーバ・コード

サービスインタフェース:

 //计算学生年龄和的接
public interface CalculateService {
 String cal(Student sta, Student stb);
}
public class CalculateServiceImpl implements CalculateService {
 @Override
 public String cal(Student sta, Student stb) {
 return "学生年龄之和:" + (sta.getAge() + stb.getAge());
 }
}

サービスリリース

public class PublishUtilI {
 //服务接口集合
 private static List<Object> serviceList;
 private static ThreadPoolExecutor executor = new ThreadPoolExecutor(5,10,10, TimeUnit.SECONDS,
 new LinkedBlockingQueue<Runnable>(10));
 public static void publish(int port,Object... services) throws IOException {
 serviceList= Arrays.asList(services);
 ServerSocket server = new ServerSocket(port);
 Socket client;
 while (true) {
 //阻塞等待请求
 client = server.accept();
 //使用线程池处理请求
 executor.submit(new ServerHandler(client, serviceList));
 }
 }
}

リフレクションコールサービス

  1. クライアントから送信されたサービス名を読み込み

  2. サービスがリリースされるかどうかを確認

  3. リリースされた場合は、対応するサービスコールサーバを反映

  4. クライアントに結果を返します。

    パブリッククラスServerHandlerはRunnableを実装して、{
    プライベートソケットクライアント= NULLを。
    プライベートリストserviceList = NULL;
    公共ServerHandler(ソケットクライアント、リストサービス){
    this.client =クライアント。
    this.serviceList =サービス。
    }
    @Override
    ます。public void実行(){
    してみてください(
    ObjectInputStreamの入力=新しいObjectInputStreamの(client.getInputStream());
    ObjectOutputStreamの出力は=新しいObjectOutputStreamの(client.getOutputStream())
    ){
    //读取客户端要访问那个サービス
    クラスserviceClass =(クラス)input.readObject();
    //找到该服务类
    オブジェクトOBJ = findService(serviceClass)。
    もし(OBJ == NULL){
    output.writeObject(serviceClass.getName()+「服务未发现」)。
    他{}
    //メソッドを呼び出すためにリフレクションを使用して、結果を返す
    文字列methodNameの= input.readUTF(); //読み出す符号化UTF文字列
    //読み取りパラメータ型
    クラス[] parameterTypesパラメータ=(クラス< <>? > [])input.readObject();
    //読み取りパラメータ
    オブジェクト[] =引数(オブジェクト[])input.readObject()
    メソッド、メソッドobj.getClass =()getMethod(methodNameの、parameterTypesパラメータ);
    //反射メソッドの実行
    ; =(OBJ、引数)オブジェクトMethod.invoke結果
    、output.writeObject(結果)
    }
    キャッチ(例外E){}
    e.printStackTrace();
    }
    }
    プライベートfindServiceオブジェクト(クラスserviceClass){
    (対象物OBJのために: serviceList){
    ブールisFather = serviceClass.isAssignableFrom(obj.getClass());
    IF(isFather){
    OBJを返します。
    }
    }
    はnullを返します。
    }
    }

クライアントコード

public class Client {
 public static void main(String[] args) {
 CallProxyHandler handler = new CallProxyHandler("127.0.0.1", 1111);
 CalculateService calculateService = handler.getService(CalculateService.class);
 Student sta = new Student(1);
 Student stb = new Student(2);
 String result = calculateService.cal(sta, stb);
 System.out.println(result);
 }
}

リモートサーバーに公開サービスを呼び出すためにプロキシクラスを作成します。

 public class CallProxyHandler implements InvocationHandler {
 private String ip;
 private int port;
 public CallProxyHandler(String ip, int port) {
 this.ip = ip;
 this.port = port;
 }
 /**
 * 获取代理对象
 * @param clazz
 * @param <T>
 * @return
 */
 @SuppressWarnings("all")
 public <T> T getService(Class<T> clazz) {
 return (T) Proxy.newProxyInstance(CallProxyHandler.class.getClassLoader(),
 new Class<?>[] {clazz}, this);
 }
 
 /**
 * 将需要调用服务的方法名,参数类型,参数按照一定格式封装发送至服务端
 * 读取服务端返回的结果
 * @param proxy
 * @param method
 * @param args
 * @return
 * @throws Throwable
 */
 @SuppressWarnings("all")
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 try (
 Socket socket = new Socket(ip, port);
 ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
 ObjectInputStream input = new ObjectInputStream(socket.getInputStream())
 ) {
 output.writeObject(proxy.getClass().getInterfaces()[0]);
 output.writeUTF(method.getName());
 output.writeObject(method.getParameterTypes());
 output.writeObject(args);
 output.flush();
 Object result = input.readObject();
 if (result instanceof Throwable) {
 throw (Throwable) result;
 }
 return result;
 }
 }
}

このように、簡単なRPCサービス呼び出しフレームワークが完成されます。しかし、多くの問題があります。

  1. シリアライゼーションのJava運ぶ、効率が高くなく、HadoopのアブロいるProtobufを使用することができます
  2. ネットワーク通信のための網状フレームワークを使用し、高い並行性に対応できない、ネットワーク送信のためBIOの方法を使用
  3. レジストリの欠如は、登録サービスは、飼育係を管理するために使用することができます。

収集したいくつかのソース解析、ダボ、Redisの、ネッティー、飼育係、春、雲、分散されたデータを与え、共有、コメント、共有知識のJava毎日を次の

おすすめ

転載: blog.csdn.net/XingXing_Java/article/details/91432554