迭代速度太快,对于我们这种互联网从业人员来说,过去四十年的互联网公司典型架构真是沧海桑田。
洪荒时代
上个世纪九十年代。
最典型的架构是
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又能在激烈的市场中引领潮流最终形成大家都能接受的规范和标准吗?我们拭目以待。
总结
没有一种技术会说自己不如别人。他们只是慢慢的落后时代,被逐步抛弃罢了。与其说这种技术不如别人,倒不如说是这种技术的支持者不如别人。市场永远在追求足够简单,或者“让别人觉得”足够简单。在功能的底线下,简单就是第一竞争力。那么性能呢?性能总是有改进和优化的办法。那为什么人类会反复寻找不到一个正确的答案呢?换个问题,为什么人类几万年也追求不到一个正义呢?因为大家对正义的定义不同,大家对简单的定义也不同。我们有些时候的简单是自己自由扩展体会一切皆有肯能,有些时候追求的简单则是被包养的幸福。我们永远可能永远无法就何为简单这个话题,和别人,和曾经的自己,和未来的自己达成一致。
唯一欣慰的是,在我们追求简单的过程中,互联网编程的架构功能日益完善。我不相信有人能告诉我们未来的互联网架构会是如何的,每个人,每个公司,每个技术支持者,都有他们梦中的明天。但我能告诉你,现在我们能做到的功能,在以后的任意时代的互联网编程工程师手里,都能够做到。