Apache Thrift系列詳解(二)
前言
Thrift
提供的網路服務模型:單執行緒、多執行緒、事件驅動,從另一個角度劃分為:阻塞服務模型、非阻塞服務模型。
-
阻塞服務模型:
TSimpleServer
、TThreadPoolServer
。 -
非阻塞服務模型:
TNonblockingServer
、THsHaServer
和TThreadedSelectorServer
。
TServer
類的層次關係:
正文
TServer
TServer
定義了靜態內部類Args
,Args
繼承自抽象類AbstractServerArgs
。AbstractServerArgs
採用了建造者模式,向TServer
提供各種工廠:
工廠屬性 | 工廠型別 | 作用 |
---|---|---|
ProcessorFactory | TProcessorFactory | 處理層工廠類,用於具體的TProcessor物件的建立 |
InputTransportFactory | TTransportFactory | 傳輸層輸入工廠類,用於具體的TTransport物件的建立 |
OutputTransportFactory | TTransportFactory | 傳輸層輸出工廠類,用於具體的TTransport物件的建立 |
InputProtocolFactory | TProtocolFactory | 協議層輸入工廠類,用於具體的TProtocol物件的建立 |
OutputProtocolFactory | TProtocolFactory | 協議層輸出工廠類,用於具體的TProtocol物件的建立 |
下面是TServer
的部分核心程式碼:
public abstract class TServer {
public static class Args extends org.apache.thrift.server.TServer.AbstractServerArgs<org.apache.thrift.server.TServer.Args> {
public Args(TServerTransport transport) {
super (transport);
}
}
public static abstract class AbstractServerArgs<T extends org.apache.thrift.server.TServer.AbstractServerArgs<T>> {
final TServerTransport serverTransport;
TProcessorFactory processorFactory;
TTransportFactory inputTransportFactory = new TTransportFactory();
TTransportFactory outputTransportFactory = new TTransportFactory();
TProtocolFactory inputProtocolFactory = new TBinaryProtocol.Factory();
TProtocolFactory outputProtocolFactory = new TBinaryProtocol.Factory();
public AbstractServerArgs(TServerTransport transport) {
serverTransport = transport;
}
}
protected TProcessorFactory processorFactory_;
protected TServerTransport serverTransport_;
protected TTransportFactory inputTransportFactory_;
protected TTransportFactory outputTransportFactory_;
protected TProtocolFactory inputProtocolFactory_;
protected TProtocolFactory outputProtocolFactory_;
private boolean isServing;
protected TServer(org.apache.thrift.server.TServer.AbstractServerArgs args) {
processorFactory_ = args.processorFactory;
serverTransport_ = args.serverTransport;
inputTransportFactory_ = args.inputTransportFactory;
outputTransportFactory_ = args.outputTransportFactory;
inputProtocolFactory_ = args.inputProtocolFactory;
outputProtocolFactory_ = args.outputProtocolFactory;
}
public abstract void serve();
public void stop() {}
public boolean isServing() {
return isServing;
}
protected void setServing(boolean serving) {
isServing = serving;
}
}
TServer
的三個方法:serve()
、stop()
和isServing()
。serve()
用於啟動服務,stop()
用於關閉服務,isServing()
用於檢測服務的起停狀態。
TServer
的不同實現類的啟動方式不一樣,因此serve()
定義為抽象方法。不是所有的服務都需要優雅的退出, 因此stop()
方法沒有被定義為抽象。
TSimpleServer
TSimpleServer
的工作模式採用最簡單的阻塞IO,實現方法簡潔明瞭,便於理解,但是一次只能接收和處理一個socket
連線,效率比較低。它主要用於演示Thrift
的工作過程,在實際開發過程中很少用到它。
(一) 工作流程
(二) 使用入門
服務端:
ServerSocket serverSocket = new ServerSocket(ServerConfig.SERVER_PORT);
TServerSocket serverTransport = new TServerSocket(serverSocket);
HelloWorldService.Processor processor =
new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldServiceImpl());
TBinaryProtocol.Factory protocolFactory = new TBinaryProtocol.Factory();
TSimpleServer.Args tArgs = new TSimpleServer.Args(serverTransport);
tArgs.processor(processor);
tArgs.protocolFactory(protocolFactory);
// 簡單的單執行緒服務模型 一般用於測試
TServer tServer = new TSimpleServer(tArgs);
System.out.println("Running Simple Server");
tServer.serve();
客戶端:
TTransport transport = new TSocket(ServerConfig.SERVER_IP, ServerConfig.SERVER_PORT, ServerConfig.TIMEOUT);
TProtocol protocol = new TBinaryProtocol(transport);
HelloWorldService.Client client = new HelloWorldService.Client(protocol);
transport.open();
String result = client.say("Leo");
System.out.println("Result =: " + result);
transport.close();
(三) 原始碼分析
檢視上述流程的原始碼,即TSimpleServer.java
中的serve()
方法如下:
serve()
方法的操作:
- 設定
TServerSocket
的listen()
方法啟動連線監聽。 - 以阻塞的方式接受客戶端地連線請求,每進入一個連線即為其建立一個通道
TTransport
物件。 - 為客戶端建立處理器物件、輸入傳輸通道物件、輸出傳輸通道物件、輸入協議物件和輸出協議物件。
- 通過
TServerEventHandler
物件處理具體的業務請求。
ThreadPoolServer
TThreadPoolServer
模式採用阻塞socket
方式工作,主執行緒負責阻塞式監聽是否有新socket
到來,具體的業務處理交由一個執行緒池來處理。
(一) 工作流程
(二) 使用入門
服務端:
ServerSocket serverSocket = new ServerSocket(ServerConfig.SERVER_PORT);
TServerSocket serverTransport = new TServerSocket(serverSocket);
HelloWorldService.Processor<HelloWorldService.Iface> processor =
new HelloWorldService.Processor<>(new HelloWorldServiceImpl());
TBinaryProtocol.Factory protocolFactory = new TBinaryProtocol.Factory();
TThreadPoolServer.Args ttpsArgs = new TThreadPoolServer.Args(serverTransport);
ttpsArgs.processor(processor);
ttpsArgs.protocolFactory(protocolFactory);
// 執行緒池服務模型 使用標準的阻塞式IO 預先建立一組執行緒處理請求
TServer ttpsServer = new TThreadPoolServer(ttpsArgs);
System.out.println("Running ThreadPool Server");
ttpsServer.serve();
客戶端:
TTransport transport = new TSocket(ServerConfig.SERVER_IP, ServerConfig.SERVER_PORT, ServerConfig.TIMEOUT);
TProtocol protocol = new TBinaryProtocol(transport);
HelloWorldService.Client client = new HelloWorldService.Client(protocol);
transport.open();
String result = client.say("ThreadPoolClient");
System.out.println("Result =: " + result);
transport.close();
(三) 原始碼分析
ThreadPoolServer
解決了TSimpleServer
不支援併發和多連線的問題,引入了執行緒池。實現的模型是One Thread Per Connection
。檢視上述流程的原始碼,先檢視執行緒池的程式碼片段:
TThreadPoolServer.java
中的serve()
方法如下:
serve()
方法的操作:
- 設定
TServerSocket
的listen()
方法啟動連線監聽。 - 以阻塞的方式接受客戶端的連線請求,每進入一個連線,將通道物件封裝成一個
WorkerProcess
物件(WorkerProcess
實現了Runnabel
介面),並提交到執行緒池。 WorkerProcess
的run()
方法負責業務處理,為客戶端建立了處理器物件、輸入傳輸通道物件、輸出傳輸通道物件、輸入協議物件和輸出協議物件。- 通過
TServerEventHandler
物件處理具體的業務請求。
WorkerProcess
的run()
方法:
(四) 優缺點
TThreadPoolServer模式的優點
拆分了監聽執行緒(Accept Thread
)和處理客戶端連線的工作執行緒(Worker Thread
),資料讀取和業務處理都交給執行緒池處理。因此在併發量較大時新連線也能夠被及時接受。
執行緒池模式比較適合伺服器端能預知最多有多少個客戶端併發的情況,這時每個請求都能被業務執行緒池及時處理,效能也非常高。
TThreadPoolServer模式的缺點
執行緒池模式的處理能力受限於執行緒池的工作能力,當併發請求數大於執行緒池中的執行緒數時,新請求也只能排隊等待。
TNonblockingServer
TNonblockingServer
模式也是單執行緒工作,但是採用NIO
的模式,藉助Channel/Selector
機制, 採用IO
事件模型來處理。
所有的socket
都被註冊到selector
中,在一個執行緒中通過seletor
迴圈監控所有的socket
。
每次selector
迴圈結束時,處理所有的處於就緒狀態的socket
,對於有資料到來的socket
進行資料讀取操作,對於有資料傳送的socket則進行資料傳送操作,對於監聽socket
則產生一個新業務socket
並將其註冊到selector
上。
注意:TNonblockingServer要求底層的傳輸通道必須使用TFramedTransport。
(一) 工作流程
(二) 使用入門
服務端:
TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldServiceImpl());
TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket(ServerConfig.SERVER_PORT);
TNonblockingServer.Args tnbArgs = new TNonblockingServer.Args(tnbSocketTransport);
tnbArgs.processor(tprocessor);
tnbArgs.transportFactory(new TFramedTransport.Factory());
tnbArgs.protocolFactory(new TCompactProtocol.Factory());
// 使用非阻塞式IO服務端和客戶端需要指定TFramedTransport資料傳輸的方式
TServer server = new TNonblockingServer(tnbArgs);
System.out.println("Running Non-blocking Server");
server.serve();
客戶端:
TTransport transport = new TFramedTransport(new TSocket(ServerConfig.SERVER_IP, ServerConfig.SERVER_PORT, ServerConfig.TIMEOUT));
// 協議要和服務端一致
TProtocol protocol = new TCompactProtocol(transport);
HelloWorldService.Client client = new HelloWorldService.Client(protocol);
transport.open();
String result = client.say("NonBlockingClient");
System.out.println("Result =: " + result);
transport.close();
(三) 原始碼分析
TNonblockingServer
繼承於AbstractNonblockingServer
,這裡我們更關心基於NIO
的selector
部分的關鍵程式碼。
(四) 優缺點
TNonblockingServer模式優點
相比於TSimpleServer
效率提升主要體現在IO
多路複用上,TNonblockingServer
採用非阻塞IO
,對accept/read/write
等IO
事件進行監控和處理,同時監控多個socket
的狀態變化。
TNonblockingServer模式缺點
TNonblockingServer
模式在業務處理上還是採用單執行緒順序來完成。在業務處理比較複雜、耗時的時候,例如某些介面函式需要讀取資料庫執行時間較長,會導致整個服務被阻塞住,此時該模式效率也不高,因為多個呼叫請求任務依然是順序一個接一個執行。
THsHaServer
鑑於TNonblockingServer
的缺點,THsHaServer
繼承於TNonblockingServer
,引入了執行緒池提高了任務處理的併發能力。THsHaServer
是半同步半非同步(Half-Sync/Half-Async
)的處理模式,Half-Aysnc
用於IO
事件處理(Accept/Read/Write
),Half-Sync
用於業務handler
對rpc
的同步處理上。
注意:THsHaServer和TNonblockingServer一樣,要求底層的傳輸通道必須使用TFramedTransport。
(一) 工作流程
(二) 使用入門
服務端:
TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket(ServerConfig.SERVER_PORT);
TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldServiceImpl());
// 半同步半非同步
THsHaServer.Args thhsArgs = new THsHaServer.Args(tnbSocketTransport);
thhsArgs.processor(tprocessor);
thhsArgs.transportFactory(new TFramedTransport.Factory());
thhsArgs.protocolFactory(new TBinaryProtocol.Factory());
TServer server = new THsHaServer(thhsArgs);
System.out.println("Running HsHa Server");
server.serve();
客戶端:
TTransport transport = new TFramedTransport(new TSocket(ServerConfig.SERVER_IP, ServerConfig.SERVER_PORT, ServerConfig.TIMEOUT));
// 協議要和服務端一致
TProtocol protocol = new TBinaryProtocol(transport);
HelloWorldService.Client client = new HelloWorldService.Client(protocol);
transport.open();
String result = client.say("HsHaClient");
System.out.println("Result =: " + result);
transport.close();
(三) 原始碼分析
THsHaServer
繼承於TNonblockingServer
,新增了執行緒池併發處理工作任務的功能,檢視執行緒池的相關程式碼:
任務執行緒池的建立過程:
下文的TThreadedSelectorServer囊括了THsHaServer的大部分特性,原始碼分析可參考TThreadedSelectorServer。
(四) 優缺點
THsHaServer的優點
THsHaServer
與TNonblockingServer
模式相比,THsHaServer
在完成資料讀取之後,將業務處理過程交由一個執行緒池來完成,主執行緒直接返回進行下一次迴圈操作,效率大大提升。
THsHaServer的缺點
主執行緒仍然需要完成所有socket
的監聽接收、資料讀取和資料寫入操作。當併發請求數較大時,且傳送資料量較多時,監聽socket
上新連線請求不能被及時接受。
TThreadedSelectorServer
TThreadedSelectorServer
是對THsHaServer
的一種擴充,它將selector
中的讀寫IO
事件(read/write
)從主執行緒中分離出來。同時引入worker
工作執行緒池,它也是種Half-Sync/Half-Async
的服務模型。
TThreadedSelectorServer
模式是目前Thrift
提供的最高階的執行緒服務模型,它內部有如果幾個部分構成:
- 一個
AcceptThread
執行緒物件,專門用於處理監聽socket
上的新連線。 - 若干個
SelectorThread
物件專門用於處理業務socket
的網路I/O
讀寫操作,所有網路資料的讀寫均是有這些執行緒來完成。 - 一個負載均衡器
SelectorThreadLoadBalancer
物件,主要用於AcceptThread
執行緒接收到一個新socket
連線請求時,決定將這個新連線請求分配給哪個SelectorThread
執行緒。 - 一個
ExecutorService
型別的工作執行緒池,在SelectorThread
執行緒中,監聽到有業務socket
中有呼叫請求過來,則將請求資料讀取之後,交給ExecutorService
執行緒池中的執行緒完成此次呼叫的具體執行。主要用於處理每個rpc
請求的handler
回撥處理(這部分是同步的)。
(一) 工作流程
(二) 使用入門
服務端:
TNonblockingServerSocket serverSocket = new TNonblockingServerSocket(ServerConfig.SERVER_PORT);
TProcessor processor = new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldServiceImpl());
// 多執行緒半同步半非同步
TThreadedSelectorServer.Args ttssArgs = new TThreadedSelectorServer.Args(serverSocket);
ttssArgs.processor(processor);
ttssArgs.protocolFactory(new TBinaryProtocol.Factory());
// 使用非阻塞式IO時 服務端和客戶端都需要指定資料傳輸方式為TFramedTransport
ttssArgs.transportFactory(new TFramedTransport.Factory());
// 多執行緒半同步半非同步的服務模型
TThreadedSelectorServer server = new TThreadedSelectorServer(ttssArgs);
System.out.println("Running ThreadedSelector Server");
server.serve();
客戶端:
for (int i = 0; i < 10; i++) {
new Thread("Thread " + i) {
@Override
public void run() {
// 設定傳輸通道 對於非阻塞服務 需要使用TFramedTransport(用於將資料分塊傳送)
for (int j = 0; j < 10; j++) {
TTransport transport = null;
try {
transport = new TFramedTransport(new TSocket(ServerConfig.SERVER_IP, ServerConfig.SERVER_PORT, ServerConfig.TIMEOUT));
TProtocol protocol = new TBinaryProtocol(transport);
HelloWorldService.Client client = new HelloWorldService.Client(protocol);
transport.open();
String result = client.say("ThreadedSelector Client");
System.out.println("Result =: " + result);
transport.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 關閉傳輸通道
transport.close();
}
}
}
}.start();
}
(三) 核心程式碼
以上工作流程的三個元件AcceptThread
、SelectorThread
和ExecutorService
在原始碼中的定義如下:
TThreadedSelectorServer
模式中有一個專門的執行緒AcceptThread
用於處理新連線請求,因此能夠及時響應大量併發連線請求;另外它將網路I/O操作分散到多個SelectorThread
執行緒中來完成,因此能夠快速對網路I/O
進行讀寫操作,能夠很好地應對網路I/O
較多的情況。
TThreadedSelectorServer
預設引數定義如下:
- 負責網路IO讀寫的selector預設執行緒數(selectorThreads):2
- 負責業務處理的預設工作執行緒數(workerThreads):5
- 工作執行緒池單個執行緒的任務佇列大小(acceptQueueSizePerThread):4
建立、初始化並啟動AcceptThread
和SelectorThreads
,同時啟動selector
執行緒的負載均衡器(selectorThreads
)。
AcceptThread原始碼
AcceptThread
繼承於Thread
,可以看出包含三個重要的屬性:非阻塞式傳輸通道(TNonblockingServerTransport
)、NIO
選擇器(acceptSelector
)和選擇器執行緒負載均衡器(threadChooser
)。
檢視AcceptThread
的run()
方法,可以看出accept
執行緒一旦啟動,就會不停地呼叫select()
方法:
檢視select()
方法,acceptSelector
選擇器等待IO
事件的到來,拿到SelectionKey
即檢查是不是accept
事件。如果是,通過handleAccept()
方法接收一個新來的連線;否則,如果是IO
讀寫事件,AcceptThread
不作任何處理,交由SelectorThread
完成。
在handleAccept()
方法中,先通過doAccept()
去拿連線通道,然後Selector
執行緒負載均衡器選擇一個Selector
執行緒,完成接下來的IO
讀寫事件。
接下來繼續檢視doAddAccept()
方法的實現,毫無懸念,它進一步呼叫了SelectorThread
的addAcceptedConnection()
方法,把非阻塞傳輸通道物件傳遞給選擇器執行緒做進一步的IO
讀寫操作。
SelectorThreadLoadBalancer原始碼
SelectorThreadLoadBalancer
如何建立?
SelectorThreadLoadBalancer
是一個基於輪詢演算法的Selector
執行緒選擇器,通過執行緒迭代器為新進來的連線順序分配SelectorThread
。
SelectorThread原始碼
SelectorThread
和AcceptThread
一樣,是TThreadedSelectorServer
的一個成員內部類,每個SelectorThread
執行緒物件內部都有一個阻塞式的佇列,用於存放該執行緒被接收的連線通道。
阻塞佇列的大小可由建構函式指定:
上面看到,在AcceptThread
的doAddAccept()
方法中呼叫了SelectorThread
的addAcceptedConnection()
方法。
這個方法做了兩件事:
- 將被此
SelectorThread
執行緒接收的連線通道放入阻塞佇列中。 - 通過
wakeup()
方法喚醒SelectorThread
中的NIO
選擇器selector
。
既然SelectorThread
也是繼承於Thread
,檢視其run()
方法的實現:
SelectorThread
方法的select()
監聽IO
事件,僅僅用於處理資料讀取和資料寫入。如果連線有資料可讀,讀取並以frame
的方式快取;如果需要向連線中寫入資料,快取併發送客戶端的資料。且在資料讀寫處理完成後,需要向NIO
的selector
清空和登出自身的SelectionKey
。
- 資料寫操作完成以後,整個
rpc
呼叫過程也就結束了,handleWrite()
方法如下:
相關推薦
Apache Thrift系列詳解(二)
前言 Thrift提供的網路服務模型:單執行緒、多執行緒、事件驅動,從另一個角度劃分為:阻塞服務模型、非阻塞服務模型。 阻塞服務模型:TSimpleServer、TThreadPoolServer。 非阻塞服務模型:TNonblockingServer
Apache Thrift系列詳解(一)
前言 Thrift是一個輕量級、跨語言的遠端服務呼叫框架,最初由Facebook開發,後面進入Apache開源專案。它通過自身的IDL中間語言, 並藉助程式碼生成引擎生成各種主流語言的RPC服務端/客戶端模板程式碼。 Thrift支援多種不同的程式語言,包括C
Apache Thrift系列詳解(三)
前言 Thrift支援二進位制,壓縮格式,以及json格式資料的序列化和反序列化。開發人員可以更加靈活的選擇協議的具體形式。協議是可自由擴充套件的,新版本的協議,完全相容老的版本! 正文 資料交換格式簡介 當前流行的資料交換格式可以分為如下幾類: (一) 自解
mysql系列詳解二:sql語句操作-技術流ken
option art sql con student redundant cascade 枚舉 創建索引 1.簡介 本篇博客將詳細講解mysql的一些常用sql語句操作,例如創建數據庫,刪除數據庫,創建表,修改表,刪除表,以及簡單查詢案例。 2.關於mysql數據中的S
spark2.x由淺入深深到底系列六之RDD java api詳解二
spark 大數據 javaapi 老湯 rdd package com.twq.javaapi.java7; import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaRDD; import org.
docker系列詳解<二>之常用命令
此篇我們以從docker執行一個tomcat為例,進行一下操作: 拉取映象 檢視映象 建立容器 檢視執行狀態 進入退出容器 停止容器 重啟容器 刪除容器 刪除映象 1.拉取tomcat映象: 1).檢視tomcat映象列表: docker search tomcat&nb
0 httpd2.2配置詳解-Apache配置檔案詳解-(二)
httpd-2.2 15 curl命令 curl是基於URL語法在命令列方式下工作的檔案傳輸工具,它支援FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE及LDAP等協議。curl支援HTTPS認證,並且支援HTTP的POST、PU
Apache的配置詳解
詳解 ken 規則 符號連接 start 安裝 format str 訪問 Apache的配置由httpd.conf文件配置,因此下面的配置指令都是在httpd.conf文件中修改。 主站點的配置(基本配置) (1) 基本配置: ServerRoot "/mnt/soft
Linux——vim編輯器詳解二
linux——vim編輯器詳解 vim 十六、使用vim編輯多個文件用法: vim FILE1 FILE2 FILE3文件之間切換:末行模式下: :next 切換至下一個文件 :prev 切換至前一個文件 :last 切換至最後一個文件 :first 切換至第
HTTPS協議詳解(二):TLS/SSL工作原理
-c 基本 公鑰加密 工作方式 通信 使用 sha2 公開 原理 HTTPS協議的主要功能基本都依賴於TLS/SSL協議,本節分析TLS/SSL協議工作原理。 TLS/SSL的功能實現主要依賴於三類基本算法:散列函數 Hash、對稱加密和非對稱加密,其利用非對稱加密實
XSD詳解二 - 限定
ace enum 正則表達式 normal 開頭 hit 正則表達 個數字 使用 對內容的限定 限定(restriction)用於為 XML 元素或者屬性定義可接受的值。對 XML 元素的限定被稱為 facet。 假如 XML 元素的類型是 "xs:date",而其包含
MyBatis之Mapper XML 文件詳解(二)-sql和入參
java mybatis sql 參數 mapper sql這個元素可以被用來定義可重用的 SQL 代碼段,可以包含在其他語句中。它可以被靜態地(在加載參數) 參數化. 不同的屬性值通過包含的實例變化. 比如:<sql id="userColumns"> $
AppDomain 詳解二【轉】-C#中動態加載和卸載DLL
all created 新版本 odin generic reflect 可能 params 詳細 在C++中加載和卸載DLL是一件很容易的事,LoadLibrary和FreeLibrary讓你能夠輕易的在程序中加載DLL,然後在任何地方 卸載。在C#中我們也能使用Asse
web網站集群之企業級Nginx Web服務優化詳解(二)
監牢模式 優雅顯示 防盜鏈 非法解析 12 配置Nginx gzip壓縮實現性能優化 100k ---- 1s 90k 100k ---- 5s 10k gzip on; gzip_min_length 1k; gzip_buffers
python中常用模塊詳解二
digest cal alt a* bytes byte code 十六 負責 log模塊的講解 1 Python 使用logging模塊記錄日誌涉及四個主要類,使用官方文檔中的概括最為合適: 2 3 logger提供了應用程序可以直接使用的接口API;
4.Apache POI使用詳解
sele 中文大寫 文本 vertical HA model 例如 ndb mode 一.POI結構與常用類 1.POI介紹 Apache POI是Apache軟件基金會的開源項目,POI提供API給Java程序對Microsoft Office格式檔案讀和寫的功能。 .N
# 大型網絡構建-OSPF詳解二(特殊區域與虛鏈路)
大型網絡構建大型網絡構建-OSPF詳解二(特殊區域與虛鏈路) 什麽是ospf? OSPF(Open Shortest Path First開放式最短路徑優先)是一個內部網關協議(Interior Gateway Protocol,簡稱IGP),用於在單一自治系統(autonom
django模板templates詳解(二)
auth authent conf 轉換 decorator 連接 關系 ons VC 1 總體結構 ? Django是MTV結構,即:Model, Template, View Model:定義數據的存儲格式,並且提供了數據庫訪問的API。 View:定義那些數據被顯示,
nginx編譯模塊詳解(二)
通用 lib modules 兼容 conf 實現 pro 錯誤日誌 變量 nginx1.15.1配置: configure命令支持以下參數: --prefix=path 指定安裝目錄 --sbin-path=path 默認可執行文件的路徑。 --m
tomcat服務組件詳解(二)
logs 所有 servlet容器 force dmi manage 運行 nbsp 訪問 Tomcat的架構:頂級組件: 位於配置層次的頂級,並且彼此間有著嚴格的對應關系 連接器: 連接客戶端(可以是瀏覽器或Web服務器)請求至Servlet容器 容器