網際網路工程的後臺開發架構的變遷。
迭代速度太快,對於我們這種網際網路從業人員來說,過去四十年的網際網路公司典型架構真是滄海桑田。
洪荒時代
上個世紀九十年代。
最典型的架構是
apache http serve + CGI(C++等語言程式碼)。
史前的一些嘗試
CORBA
1991年OMG(物件管理組織)提出了CORBA1.1,定義了IDL介面定義語言,開發出物件請求代理ORB中介軟體,在客戶機/伺服器結構中,ORB通過一定的應用程式介面(API),實現物件之間的互動;
首先,你要定義一個IDL檔案
module CreatorModule{ interface Creator{ boolean login(in string name,in string password); boolean register(in string name,in string password); }; };
然後使用idlj此檔案轉化為一些JAVA程式碼。然後實現對應的介面。必須啟動orbd服務程序。
典型的客戶端程式碼如下
System.out.println("Client init config starts....");
String[] args = {};
Properties properties = new Properties();
properties.put("org.omg.CORBA.ORBInitialHost", "127.0.0.1"); //指定ORB的ip地址
properties. put("org.omg.CORBA.ORBInitialPort", "8080"); //指定ORB的埠
//建立一個ORB例項
orb = ORB.init(args, properties);
//獲取根名稱上下文
try {
objRef = orb.resolve_initial_references("NameService");
} catch (InvalidName e) {
e.printStackTrace();
}
ncRef = NamingContextExtHelper.narrow(objRef);
String name = "Creator";
try {
//通過ORB拿到server例項化好的Creator類
creator = CreatorHelper.narrow(ncRef.resolve_str(name));
} catch (NotFound e) {
e.printStackTrace();
} catch (CannotProceed e) {
e.printStackTrace();
} catch (org.omg.CosNaming.NamingContextPackage.InvalidName e) {
e.printStackTrace();
}
典型的服務端程式碼如下
String[] args = {};
Properties properties = new Properties();
properties.put("org.omg.CORBA.ORBInitialHost", "127.0.0.1"); //指定ORB的ip地址
properties.put("org.omg.CORBA.ORBInitialPort", "8080"); //指定ORB的埠
//建立一個ORB例項
orb = ORB.init(args, properties);
//拿到根POA的引用,並激活POAManager,相當於啟動了server
obj = orb.resolve_initial_references("RootPOA");
rootPOA = POAHelper.narrow(obj);
rootPOA.the_POAManager().activate();
//建立一個CreatorImpl例項
creatorImpl = new CreatorImpl();
creatorImpl.setToDoListServer(this);
//從服務中得到物件的引用,並註冊到服務中
ref = rootPOA.servant_to_reference(creatorImpl);
creatorhref = CreatorHelper.narrow(ref);
//得到一個根命名的上下文
objRef = orb.resolve_initial_references("NameService");
ncRef = NamingContextExtHelper.narrow(objRef);
//在命名上下文中繫結這個物件
String name = "Creator";
NameComponent path[] = ncRef.to_name(name);
ncRef.rebind(path, creatorhref);
System.out.println("server.ToDoListServer is ready and waiting....");
//啟動執行緒服務,等待客戶端呼叫
orb.run();
COM
是在Windows 3.1中最初為支援複合文件而使用OLE技術上發展而來,經歷了OLE 2/COM、ActiveX、DCOM和COM+等幾個階段。
Windows,呵呵。
JAVA的一家獨大
1997年2月,RPC的一種java實現誕生(RMI)。特點是可以像呼叫本地物件一樣呼叫遠端物件。RMI被寄予厚望並被整合進入JDK中。
一個使用RMI呼叫遠端物件的典型程式碼如下所示
try {
UserHandler handler = (UserHandler) Naming.lookup("user");
int count = handler.getUserCount();
String name = handler.getUserName(1);
System.out.println("name: " + name);
System.out.println("count: " + count);
System.out.println("user: " + handler.getUserByName("lmy86263"));
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
服務端程式碼如下
UserHandler userHandler = null;
try {
userHandler = new UserHandlerImpl();
Naming.rebind("user", userHandler);
System.out.println(" rmi server is ready ...");
} catch (Exception e) {
e.printStackTrace();
}
...
//啟動必要的rmiregistry程序(一個監聽指定埠的服務)
java.rmi.registry.LocateRegistry.createRegistry(iPort);
隨後,誕生了整個龐大J2EE標準和生態。JSP/servelet標準,tomcat/weblogic,EJB等等…
服務化時代(WebService)
J2EE和RMI的缺點很明顯,那就是大家都要玩JAVA。微軟等很多人都不會開心。COM和SOBRA也是一樣,憑什麼大家都要遵循如此複雜的RPC規範?真本來就是一個江湖,江湖上誰也不服誰。
1999年12月,微軟推出SOAP(Simple Object Access Protocol)、WSDL(WebServicesDescriptionLanguage)、UDDI(UniversalDescriptionDiscovery andIntegration)。SOAP=RPC+HTTP+XML。
毫無疑問,沒有人理他。
微服務時代
折騰一番之後,大家終於意識到,一個簡單易用而且開放的的規範才是我們真正需要的東西。
SpringCloud,服務註冊發現鏈路跟蹤監控等一些列架構。
典型的通訊是直接HTTP協議的輕量級Restful API。當然,也並非沒有例外。所以,又誕生了基於TCP的Thrift。用於解決效能問題。依舊是IDL語言來定義RPC
一個典型的服務如下
System.out.println("服務端開啟....");
TProcessor tprocessor = new Hello.Processor<Hello.Iface>(new HelloServiceImpl());
// 簡單的單執行緒服務模型
TServerSocket serverTransport = new TServerSocket(9898);
TServer.Args tArgs = new TServer.Args(serverTransport);
tArgs.processor(tprocessor);
tArgs.protocolFactory(new TBinaryProtocol.Factory());
TServer server = new TSimpleServer(tArgs);
server.serve();
}catch (TTransportException e) {
e.printStackTrace();
一個典型的呼叫者如下
transport = new TSocket("localhost", 9898, 30000);
// 協議要和服務端一致
TProtocol protocol = new TBinaryProtocol(transport);
Hello.Client client = new Hello.Client(protocol);
transport.open();
String result = client.helloString("哈哈");
System.out.println(result);
左看右看,似乎和CORBA沒啥區別。至少少了一個獨立的服務程序,而是變成了在程式碼中的整體中。這毫無疑問是因為服務註冊服務發現的發展,開發者需要約定一個統一埠進行通訊的時代已經過去了。
容器時代
SpringBoot + Docker + k8s。也就是我們現在正處於的時代。
可見的未來
sidecar + servicemesh。
歷史都是經歷某種輪迴的,2018年,Thrift相對傳統CORBA的唯一進步(取消獨立的服務程序)又用sidecar的名字死灰復燃了。用一個獨立的程序完成對本地服務的代理?說好的誰也不服誰呢?sidecar又能在激烈的市場中引領潮流最終形成大家都能接受的規範和標準嗎?我們拭目以待。
總結
沒有一種技術會說自己不如別人。他們只是慢慢的落後時代,被逐步拋棄罷了。與其說這種技術不如別人,倒不如說是這種技術的支持者不如別人。市場永遠在追求足夠簡單,或者“讓別人覺得”足夠簡單。在功能的底線下,簡單就是第一競爭力。那麼效能呢?效能總是有改進和優化的辦法。那為什麼人類會反覆尋找不到一個正確的答案呢?換個問題,為什麼人類幾萬年也追求不到一個正義呢?因為大家對正義的定義不同,大家對簡單的定義也不同。我們有些時候的簡單是自己自由擴充套件體會一切皆有肯能,有些時候追求的簡單則是被包養的幸福。我們永遠可能永遠無法就何為簡單這個話題,和別人,和曾經的自己,和未來的自己達成一致。
唯一欣慰的是,在我們追求簡單的過程中,網際網路程式設計的架構功能日益完善。我不相信有人能告訴我們未來的網際網路架構會是如何的,每個人,每個公司,每個技術支持者,都有他們夢中的明天。但我能告訴你,現在我們能做到的功能,在以後的任意時代的網際網路程式設計工程師手裡,都能夠做到。