環境資訊中心特約記者 陳文姿報導
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準
居家、公司行號垃圾清運、廢棄物處理、大型家具回收,服務快速,包月及計重或計桶供客戶選擇,合法登記的清潔公司、廢棄物清除許可,專業技術人員及專業廢棄物清運車輛
使用Spring Bboot是快樂並且簡單的,不需要繁瑣的配置就能夠完成一套非常強大的應用。
Spring Boot 2.3.1 發佈於:2020/06/12,現在已經提交到 Spring 倉庫和 Maven 中央倉庫了。
這個版本包括 127 個 bug 修復、Spring Boot 文檔改進增強、依賴升級等,另外還新增了一些新特性:
•提供基於新的 Maven 坐標 com.oracle.database 對 Oracle JDBC driver 的依賴管理;
•優化 Spring Cloud 的 CachedRandomPropertySource 不能正確適配的問題;•限制使用定製的 YAML 類型;
•增強對 NoSuchMethodErrors 異常失敗分析,能显示基類從哪被加載的;•提供更佳的錯誤消息,如果 Docker 停止運行了;
•優化 SystemEnvironmentPropertyMapper 類;
•提供更佳的診斷信息,當構建 OCI 鏡像失敗時 Docker 響應的 500 錯誤;
•支持通過 alwaysUseFullPath=true 參數來配置 UrlPathHelper;•支持在 Elasticsearch URIs 中使用用戶信息;
•支持在 Spring WebFlux 框架中使用歡迎頁面;
這個小版本還增加了蠻多東西的,大家也沒有必要跟着版本走,可以根據需要進行升級。疫情也擋不住外國友人更新的熱情。
使用STS,可以去官方網站下載最新版。網站地址 https://Spring.io/tools/sts/ Spring Tool Suite™是基於eclipse開發的專門為Spring開發使用的工具包。
選擇Spring Starter Project,
輸入工程名 對應的Name 打包方式 對應的Packaging,可以選擇jar或者war的方式。
輸入組織名 對應的Group 輸入描述 對應的Description
輸入包名 對應的Package 點擊next,然後選擇web和mysql
這裏的版本用的是2.3.1 如果沒有本地maven庫或者私庫會下載很長時間。
進入 Chapter0301Application 添加
@RestController @SpringBootApplication public class Chapter0301Application { @RequestMapping("/") String home() { return "歡迎使用Spring Boot!"; } public static void main(String[] args) { SpringApplication.run(Chapter0301Application.class, args); } }
使用@RestController 相當於@Controller 和 @RequestBody。是Sspring Bboot 基於Sspring MVC的基礎上進行了改進, 將@Controller 與@ResponseBody 進行了合併形成的一個新的註解。 @EnableAutoConfiguration 作用 從classpath中搜索所有META-INF/spring.factories配置文件然後,將其中org.springframework.boot.autoconfigure.EnableAutoConfiguration key對應的配置項加載到spring容器 只有spring.boot.enableautoconfiguration為true(默認為true)的時候,才啟用自動配置 @EnableAutoConfiguration還可以進行排除,排除方式有2種,一是根據class來排除(exclude),二是根據class name(excludeName)來排除 其內部實現的關鍵點有
1.ImportSelector 該接口的方法的返回值都會被納入到spring容器管理中
2.SpringFactoriesLoader 該類可以從classpath中搜索所有META-INF/spring.factories配置文件,並讀取配置
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.1.RELEASE) 2020-06-23 13:30:11.611 INFO 9916 --- [ main] com.cloud.sky.Chapter0301Application : Starting Chapter0301Application on DADI-PC with PID 9916 (D:\java\microservice\chapter0301\target\classes started by Administrator in D:\java\microservice\chapter0301) 2020-06-23 13:30:11.614 INFO 9916 --- [ main] com.cloud.sky.Chapter0301Application : No active profile set, falling back to default profiles: default 2020-06-23 13:30:12.415 INFO 9916 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2020-06-23 13:30:12.423 INFO 9916 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-06-23 13:30:12.424 INFO 9916 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.36] 2020-06-23 13:30:12.512 INFO 9916 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-06-23 13:30:12.512 INFO 9916 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 830 ms 2020-06-23 13:30:12.665 INFO 9916 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-06-23 13:30:12.809 INFO 9916 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2020-06-23 13:30:12.818 INFO 9916 --- [ main] com.cloud.sky.Chapter0301Application : Started Chapter0301Application in 1.492 seconds (JVM running for 3.109) 2020-06-23 13:30:20.675 INFO 9916 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2020-06-23 13:30:20.676 INFO 9916 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2020-06-23 13:30:20.680 INFO 9916 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms
打開瀏覽器訪問 http://localhost:8080/ 可以得到如下頁面
構建的過程中遇到問題
[INFO] Scanning for projects... [ERROR] [ERROR] Some problems were encountered while processing the POMs: [FATAL] Non-parseable POM D:\java\apache-maven-3.1.1\repo\org\jetbrains\kotlin\kotlin-bom\1.3.72\kotlin-bom-1.3.72.pom: entity reference names can not start with character ')' (position: START_TAG seen ...ost,s="";function qs(n){var u=D.URL;var t=u.match(eval(\'/(\\?|#|&)... @1:243) @ D:\java\apache-maven-3.1.1\repo\org\jetbrains\kotlin\kotlin-bom\1.3.72\kotlin-bom-1.3.72.pom, line 1, column 243 @ [ERROR] The build could not read 1 project -> [Help 1] [ERROR] [ERROR] The project com.cloudskyme:chapter0301:0.0.1 (D:\java\microservice\chapter0301\pom.xml) has 1 error [ERROR] Non-parseable POM D:\java\apache-maven-3.1.1\repo\org\jetbrains\kotlin\kotlin-bom\1.3.72\kotlin-bom-1.3.72.pom: entity reference names can not start with character ')' (position: START_TAG seen ...ost,s="";function qs(n){var u=D.URL;var t=u.match(eval(\'/(\\?|#|&)... @1:243) @ D:\java\apache-maven-3.1.1\repo\org\jetbrains\kotlin\kotlin-bom\1.3.72\kotlin-bom-1.3.72.pom, line 1, column 243 -> [Help 2] [ERROR] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. [ERROR] Re-run Maven using the -X switch to enable full debug logging. [ERROR] [ERROR] For more information about the errors and possible solutions, please read the following articles: [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/ProjectBuildingException [ERROR] [Help 2] http://cwiki.apache.org/confluence/display/MAVEN/ModelParseException
修改maven默認源配置
我使用的是阿里的maven倉庫,國外的東西沒個代理還真麻煩。
<repositories>
<repository>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
<repository>
<id>sonatype-nexus-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
然後執行 mvn help:system
成功可以看到如下界面:
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※帶您來了解什麼是 USB CONNECTOR ?
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!
※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※教你寫出一流的銷售文案?
目錄
我們用golang做odbc驅動開發的任務並不多,隔段時間可能會來一個。每次開發會忘記如何配置數據源和對應的數據源鏈接參數配置。這裏做一個整理。
ODBC(Open Database Connectivity)是一組對數據庫訪問的標準API,其最大的優點是以統一的方式處理所有的數據庫。
JDBC(Java Database Connectivity)是Java與數據庫的接口規範,允許Java程序發送SQL指令並處理結果。比較常見JdbcTemplate
打開控制面板找到管理工具,當前目錄有兩個ODBC的配置工具。分別是:ODBC Data Sources (32-bit)、ODBC 數據源(64 位)。顧名思義一個是32位,一個是64位。在配置ACCESS數據源時需要選擇32位。
我們也可以直接在系統目錄下找到對應的可執行文件。
1)32位:%windir%\syswow64\odbcad32.exe
2)64位:%windir%\system32\odbcad32.exe
題外話:syswow64 目錄存放的是32位的程序,system32目錄存放的是64位的程序,在註冊dll的時候需要注意下。ITDragon 在接觸驅動開發之前一直都弄反了。這篇文章做了通俗易懂地解釋https://www.cnblogs.com/hbccdf/p/dllchecktoolandsyswow64.html
網上收集整理,不保證正確性,僅供參考。
| 數據庫 | 連接參數 |
|---|---|
| MySQL | driver={mysql};database=數據庫;uid=賬號;pwd=密碼; |
| MSSQL Server | driver={sql server};server=服務器;database=數據庫;uid=ITDragon;pwd=密碼; |
| Access | driver={microsoft access driver (*.mdb)};dbq=mdb文件全路徑;uid=ITDragon;pwd=密碼; |
| SQLite | driver={SQLite3 ODBC Driver};database=db文件全路徑 |
| PostgreSQL | driver={PostgreSQL ANSI};server=服務器;uid=賬號;pwd=密碼;database=數據庫; |
| DBase | driver={microsoft dbase driver (*.dbf)};driverid=277;dbq=dbf文件全路徑; |
| Oracle | driver={microsoft odbc for oracle};server=服務器;uid=ITDragon;pwd=密碼; |
| MS text | driver={microsoft text driver (* .txt; *.csv)};dbq=文件全路徑;extensions=asc,csv,tab,txt;PersistSecurityInfo=false; |
| Visual Foxpro | driver={microsoft Visual Foxpro driver};sourcetype=DBC;sourceDB=*.dbc;Exclusive=No; |
第一步:雙擊ODBC 數據源(64 位),可以選擇用戶DSN(系統只對當前用戶生效),也可以選擇系統DSN(能登錄當前系統的用戶都生效)
第二步:點擊添加,選擇事先安裝好的MySQL ODBC xx Driver 驅動後點擊完成。注意不同版本之間對某些sql語法的支持略有不同(之前吃過這個虧,我的環境有問題,客戶環境沒問題)。
第三步:完善基本鏈接信息後點擊Test,提示鏈接成功後點擊OK完成配置。
因為ODBC驅動配置已經將數據庫的連接地址、賬號、密碼、數據庫都已經配置完成,連接參數只需要指定驅動名稱即可:DSN=ITDragon_MySQL
Golang偽代碼:
import (
"database/sql"
_ "github.com/alexbrainman/odbc"
)
db, err := sql.Open("odbc", "DSN=ITDragon_MySQL")
if err != nil {
panic(err)
}
defer db.Close()
第一步:雙擊ODBC 數據源(64 位),可以選擇用戶DSN(系統只對當前用戶生效),也可以選擇系統DSN(能登錄當前系統的用戶都生效)
第二步:點擊添加,選擇SQL Server。這一項我ITDragon 並沒有手動安裝,應該是安裝SQL Server數據庫的時候自動安裝上去的。
第三步:鍵盤輸入需要連接的SQLServer服務器,如果是本機,就輸入計算機名。如果是遠程主機就需要輸入IP,Port 。不要點擊下拉框,會卡死。
第四步:選擇SQL Server驗證方式
第五步:選擇默認數據庫,也可以在寫sql語句時將表名的全路徑寫全(我ITDragon 習慣用寫全)
第六步:可以考慮修改SQL Server的系統消息語言,數據的加密,執行字符數據翻譯,修改日誌保存路徑等。也可以默認。
第七步:點擊完成,彈出“按照以下配置創建新的ODBC數據源”,點擊測試數據源,提示測試成功。點擊確定完成創建。
Golang偽代碼:
import (
"database/sql"
_ "github.com/alexbrainman/odbc"
)
db, err := sql.Open("odbc", "driver={sql server};server=DESKTOP-HKC2IA3;DSN=ODBCName;uid=xxx;pwd=xxx;")
if err != nil {
panic(err)
}
defer db.Close()
第一步:雙擊ODBC Data Sources (32-bit),而不是64位。可以選擇用戶DSN(系統只對當前用戶生效),也可以選擇系統DSN(能登錄當前系統的用戶都生效)
第二步:選擇Microsoft Access Driver (*.mdb)。點擊數據庫下發的選擇按照,選擇mdb文件,點擊確定完成配置。
我們其實可以不用配置Access的數據源,直接用DBQ指定mdb的文件路徑,再用pwd輸入密碼訪問。
Golang偽代碼:
import (
"database/sql"
_ "github.com/alexbrainman/odbc"
)
db, err := sql.Open("odbc", "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=全路徑.MDB;pwd=xx;")
if err != nil {
panic(err)
}
defer db.Close()
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※為什麼 USB CONNECTOR 是電子產業重要的元件?
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※台北網頁設計公司全省服務真心推薦
※想知道最厲害的網頁設計公司"嚨底家"!
※新北清潔公司,居家、辦公、裝潢細清專業服務
※推薦評價好的iphone維修中心
摘要:面對如何在現有的低版本的框架服務上,運行新版本的前端服務問題,華為雲前端推出了一種融合方案,該方案能讓獨立的Angular項目整體運行在低版本的框架服務上,通過各種適配手段,讓Angular項目也能獲取到外層框架服務的資源。
華為雲前端服務前期採用AngularJs作為框架技術棧,技術較為老舊,性能較差,在華為雲快速發展的今天,顯然不能滿足要求。因此我們必須要升級前端技術棧,使用Angular2+來承載我們的前端服務。GeminiDB作為新服務,也是數據庫乃至華為雲未來的重點服務,作為前端部分,必須在技術上使用最前沿的框架,以最大地提高用戶體驗。
但是技術棧的升級不是一蹴而就的,尤其是在華為雲,所有的雲服務必須在框架服務的底座上運行,而框架服務承載了所有的雲服務,如果要進行技術棧升級,必然是一個緩慢的過程。GeminiDB作為華為雲服務里的一員,也不可能脫離框架服務而存在。因此存在一個問題,就是如何在現有的低版本的框架服務上,運行新版本的前端服務。
為了解決以上問題,華為雲前端推出了一種融合方案,該方案能讓獨立的Angular項目整體運行在低版本的框架服務上,通過各種適配手段,讓Angular項目也能獲取到外層框架服務的資源。
底層項目使用webpack打包,打包后通過在index.html里引入businessAll.js文件,以該文件為入口啟動整個框架服務。
<script type="text/javascript" src="businessAll.js"></script>
在底層框架服務啟動后,再渲染出具體雲服務內容。
<div class="service-content-view" ui-view ng-animate="{enter:'fade-enter'}"></div>
Angular項目支持獨立運行,有單獨的index.html,也有單獨的main.ts入口。但是如果希望Angular項目運行在底層框架服務上,就必須把Angular項目看作是一個獨立的模塊,把項目整體引入到底層項目中。因此,我們可以預先把Angular項目編譯好,放到底層項目的一個目錄下。在運行底層項目時,在index.html里將Angular項目引進來,獨立運行。
<link rel="stylesheet" type="text/css" href="{底層項目中Angular項目的路徑}/styles.css" /> <script type="text/javascript" src="{底層項目中Angular項目的路徑}/runtime.js"></script> <script type="text/javascript" src="{底層項目中Angular項目的路徑}/polyfills.js"></script> <script type="text/javascript" src="{底層項目中Angular項目的路徑}/main.js"></script>
底層項目和Angular項目均能獨立,但是要讓兩者融合起來,會遇到以下幾個問題:
1.底層項目中如何渲染出Angular項目。
2.Angular項目依賴底層項目的資源,如何保證Angular項目在底層項目運行起來后再運行。
3.如何解決底層項目和Angular項目的路由衝突問題。
底層項目分為兩部分,一部分是底層框架服務,另一部分是具體雲服務。現在我們要做的是把老的雲服務項目替換成新的Angular項目,因此我們可以直接在渲染老的雲服務的地方替換成新的Angular項目的渲染容器。
<div class="service-content-view" ui-view ng-animate="{enter:'fade-enter'}"></div> <app-root></app-root>
底層框架服務對頁面渲染上做了一些體驗上的優化,因此必須保留原模板中的ui-view,使底層項目正常運行起來,實際上老的雲服務項目的渲染內容已經轉發到新的Angular項目上面。
底層框架服務給雲服務提供了很多公共變量與服務,這些變量和服務是各個雲服務必須要使用的,否則雲服務將不能正常運作。
對於Angular項目來說,要使用底層框架服務提供的內容,首先要求Angular項目在底層項目運行起來之後再運行。這裏採用Augular中的APP_INITIALIZER令牌來解決這個問題。APP_INITIALIZER是一個函數,在程序初始化的時候被調用。這裡在根模塊的providers中以factory的形式來配置。
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { AppInitService } from './services/app-init.service';
import { AppComponent } from "./app.component";
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [
AppInitService,
{
provide: APP_INITIALIZER,
useFactory: initializeApp,
deps: [AppInitService],
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
export function initializeApp(appInitService: AppInitService) {
return (): Promise<any> => {
return appInitService.Init();
};
}
在appInitService里,先獲取到底層框架的資源,再進行Angular項目的初始化。
import { Injectable } from '@angular/core';
@Injectable()
export class AppInitService {
constructor() {}
Init() {
return new Promise<void>((resolve, reject) => {
// 獲取到底層框架服務的資源
resolve();
});
}
}
底層項目使用的是AngularJs,Angular項目獲取底層框架服務提供的資源不能通過Angular的方式引入,因此需要藉助AngularJS的注入器獲取在底層框架中註冊的服務組件:
static get(inject: string): any { return (window as any).angular.element('html').injector().get(inject);} 如,要獲取 $rootScope: rootScope = (window as any).angular.element('html').injector().get(‘$rootScope’);
Angular項目本身有自己的路由,但是Angular項目是運行在底層框架之上的,Angular項目的路由將會被底層框架所攔截。因此,我們也需要在底層框架的項目中配置相同的路由,以免Angular項目中的有效路由被底層框架識導向為404。
Angular項目路由:
{ path: '', redirectTo: 'ng2app1', pathMatch: 'full' }, { path: 'ng2app1', loadChildren: './ng2app1/ng2app1.module#Ng2app1Module', }, { path: 'ng2app2', loadChildren: './ng2app2/ng2app2.module#Ng2app2Module', } 底層框架路由: var configArr = [ { name: 'ng2app1', url: '/ng2app1' }, { name: 'ng2app2', url: '/ng2app2' } ];
另外,由於底層項目使用的是hash路由,Angular項目中也要做相應的配置,默認是使用的是PathLocationStrategy,需要切換到hash模式。
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
...
providers: [
{
provide: LocationStrategy,
useClass: HashLocationStrategy
}
]
以上方案是在底層框架升級周期長的前提下的一個臨時方案,實際上還是存在着不少的問題。比如底層框架對於老的雲服務容器是有統一管理的,老的雲服務容器會針對不同的場景能夠自適應,而融合方案中的Angular項目則不能;每次啟動整個項目時,必須要預先編譯好裏面的Angular項目,再去啟動外層的底層框架,開發效率比較低。因此,後續GeminiDB服務應該在底層框架升級后,儘快適應到新的底層框架體系中,提高服務的可用性和穩定性。
點擊關注,第一時間了解華為雲新鮮技術~
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準
[Redis源碼系列]在Liunx安裝和常見API
為什麼要從Redis源碼分析
String底層實現——動態字符串SDS
Redis的雙向鏈表一文全知道
面試官:說說Redis的Hash底層 我:……(來自閱文的面試題)
hello,大家好,周五見了。前面幾周我們一起看了Redis底層數據結構,如動態字符串SDS,雙向鏈表Adlist,字典Dict,如果有對Redis常見的類型或底層數據結構不明白的請看上面傳送門。
今天我們來看下ZSET的底層架構,如果不知道ZSET是什麼的,可以看上面傳送門第一篇。簡單來說,ZSET是Redis提供的根據數據和分數來判斷其排名的數據結構。最常見的就是微信運動的排名,每個用戶對應自己的步數,每天晚上可以給出用戶的排名。
有小夥伴可能會想,如果是實現排名的話,各種排序方法都可以實現的,沒必要引入Redis的ZSET結構啊?
當然,如果是採用排序方法的話,是可以實現相同功能的,但是代碼裏面需要硬編碼,會添加工作量,還會提供代碼的Bug哦,哈哈哈。而且Redis的底層是C實現的,直接操作內存,速度也會比Java方法實現提升。
綜上,使用Redis的ZSET結構,好處多多。那話不多說,開始把。在正式開始之前,我們需要引入下跳躍表的概念,其是ZSET結構的底層實現。以下可能有點枯燥,我盡量說的簡單點哈。
對於數據量大的鏈表結構,插入和刪除比較快,但是查詢速度卻很慢。那是因為無法直接獲取某個節點,需要從頭節點開始,藉助某個節點的next指針來獲取下一節點。即使數據是有序排放的,想要查詢某個數據,只能從頭到尾遍歷變量,查詢效率會很低,時間複雜度為O(n)。
如果我們需要快速查詢鏈表有啥辦法呢?有同學說用數組存放,但是如果不改數據結構呢?
我們可以先想想在有序數組結構中有二分法,每次將範圍都縮小一半,這樣查詢速度提升了很多,那麼在鏈表中能不能也使用這種思想。
這就到了今天講的主角——跳躍表。(一點也生硬的引出概念)
先看下圖有序單向鏈表,存放了1,2,3,4,5,6,7這7個元素。
我們可以在鏈表中抽取部分節點,下圖抽取了1,3,5,7四個節點,也就是每兩個節點提取了一個節點到上級,抽取出來的叫做索引。
注意不是每次都能抽取到這麼完美,這其實就跟拋硬幣一樣,每個硬幣的正反兩面的概率是一樣的,都是1/2。當數據量小的時候,正反的概率可能差別較大。但是隨着數據量的加大,正反的概率越來越接近於1/2。類比過來是一個意思,每個節點的機會都是一樣的,要麼停留原級,要麼提取到上級,概率都是1/2。但是隨着節點數量的增加,抽取的節點越來越接近與1/2。
我們可以在鏈表中抽取部分節點,下圖抽取了1,5兩個節點,也就是每兩個節點提取了一個節點到上級,抽取出來的叫做索引。
我們假設要查找值為6的節點,先從三級索引開始,找到值為1的節點,發現比5小,根據值為1節點的next指針,找到值為5的節點,5後面沒有其他的三級索引啦。
於是順着往下找,到了二級索引,根據值為5的節點的next指針找到值為7的節點,發現比6小,說明要找到的節點6在此範圍內。
再接着到了一級索引位置,根據值為5的節點next指針指向值為6的節點,發現是想要查詢的數據,所以查詢過程結束。
根據上面的查詢過程(下圖的藍色連線),我們發現其採用的核心思想是二分法,不斷縮小查詢範圍,如果在上層索引找到區間,則順延深入到下一層找到真正的數據。
從上面的整個過程中可以看出,數據量小的時候,這種拿空間換時間,消耗內存方法的並不是最優解。所以Redis的zset結構在數據量小的時候採用壓縮表,數據量大的時候採用跳躍表。
像這種鏈表加多級索引的結構,就是跳躍表。這名字起的形象,過程是跳躍着來查詢的。
下圖簡單來說是對跳躍表的改進和再封裝,首先引入了表頭的概念,這與雙向鏈表,字典結構一樣,都是對數據的封裝,因為他們都是採用的指針,而指針必然導致在計算長度,獲取最後節點的數據問題上會產生查詢太慢的性能問題,所以封裝表頭是為了在這些問題上提升速度,浪費的只是添加,刪除等操作的時間,與此對比,是可以忽略的。
其次是引入管理所有節點的層數數組,我們可以看到有32層,即32個數組,這和後面的數據節點結構是一樣的。引入它是為了便於直接根據此數組的層數定位到每個元素。
再其次是數據節點的每個level都有層級和span(也就是下圖箭頭指針上的数字,其是為了方便統計兩個節點相距多少長度)。
最後就是數據節點的後退指針backward,引入目的是Level數組只有前指針,即只能指向下一個節點地址,而後退指針是為了能往回找節點。
上圖主要分為3大塊:(這邊大致看下就行,下面將對各模塊進行代碼詳細解釋)
主要包括四個屬性,分別是頭指針header,尾指針tail,節點長度length,所有節點的最大level。
header:指向跳躍表的表頭節點,通過這個指針地址可以直接找到表頭,時間複雜度為O(1)。
tail:指向跳躍表的表尾節點,通過這個指針可以直接找到表尾,時間複雜度為O(1)。
length:記錄跳躍表的長度,即不包含表頭節點,整個跳躍表中有多少個元素。
level:記錄當前跳躍表內,所有節點層數最大的level(排除表頭節點)。
其對象值為空,level數組為32層,目的是為了管理真正的數據節點。關於具體的level有哪些屬性放在數據節點來說。
主要包括四個屬性對象值obj,分數score,後退指針backward和level數組。每個數據的Level數組有多少層,是隨機產生的,這跟上面說過的跳躍表是一樣的。
成員對象obj:真正的實際數據,每個節點的數據都是唯一的,但是節點的分數可能相同。兩個相同分數的節點是按照成員對象在字典中的大小進行排序的,成員對象較小的節點會排在前面,成員對象較大的節點會排在後面。
分數score:各個節點中的数字是節點所保存的分數,在跳躍表中,節點按各自所保存的分數從小到大排列。
後退指針backward:用於從表尾向表頭遍歷,每個節點只有一個後退指針,即每次只能後退一步。
層級level:節點中用1,2,3等字樣標記節點的各個層,L1代表第一層,L2代表第二層,L3代表第三層,並以此類推。
typedef struct zskiplist { //表頭的頭指針header和尾指針tail struct zskiplistNode *header, *tail; //一共有多少個節點length unsigned long length; // 所有節點最大的層級level int level; } zskiplist;
//跳錶的具體節點 typedef struct zskiplistNode { sds ele; //具體的數據,對應張三 double score;//分數,對應70 struct zskiplistNode *backward;//後退指針backward //層級數組 struct zskiplistLevel { struct zskiplistNode *forward;//前進指針forward unsigned int span;//跨度span } level[]; } zskiplistNode;
redis關於跳躍表的API都定義在t_zset.c文件中。
千萬不要看到源碼分析就跑開了,一定要看哦。
創建空的跳躍表,其實就是創建表頭和管理所有的節點的level數組。首先,定義一些變量,嘗試分配內存空間。其次是初始化表頭的level和length,分別賦值1和0。接着創建管理所有節點的Level的數組,是調用zslCreateNode函數,輸入參數為數組大小宏常量ZSKIPLIST_MAXLEVEL(32),分數為0,對象值為NULL。(此為跳躍表得以實現重點)。再接着就是為此數組每個元素的前指針forword和跨度span初始化。最後初始化尾指針並返回值。
可以參照下面的圖解和源碼:
//創建一個空表頭的跳躍表 zskiplist *zslCreate(void) { int j; zskiplist *zsl; //嘗試分配內存空間 zsl = zmalloc(sizeof(*zsl)); //初始化level和length zsl->level = 1; zsl->length = 0; //調用下面的方法zslCreateNode,傳入的參數有數組長度ZSKIPLIST_MAXLEVEL 32 //分數0,對象值NuLL //這一步就是創建管理所有節點的數組 //並且設置表頭的頭頭指針為此對象的地址 zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,NULL); //為這32個數組賦值前指針forward和跨度span for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) { zsl->header->level[j].forward = NULL; zsl->header->level[j].span = 0; } //設置尾指針 zsl->header->backward = NULL; zsl->tail = NULL; //返回對象 return zsl; } zskiplistNode *zslCreateNode(int level, double score, sds ele) { zskiplistNode *zn = zmalloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel)); zn->score = score; zn->ele = ele; return zn; }
比如有下圖6個元素,需要插入值為趙六,分數為101的元素,我們大致想一想,大致的步驟包括找到要插入的位置,新建一個數據節點,然後調整與之相關的頭尾指針的level數組。那就看看redis咋做的,和我們想的一樣不一樣呢?
噔噔噔噔,答案揭曉。當然了大框架是相同的。
正文開始了:(先來圖片)
1.遍歷管理所有節點的level數組,從最大的level開始,即3,挨個對比值,如果有分數比他大的值或者分數相同,但是數據的值比他大,記錄到數組裡面,同時記錄跨度。
這樣說太抽象了。拿上圖舉個例子,從表頭的level即3開始,首先到張三的L3,發現分數70,比目標分數101小跳過,根據其前指針找到趙六的L3,發現分數102,比目標分數101大,將趙六L3記錄在待更新數組update中,同時記錄跨度span為4。接着到下一層,張三的L2層,發現分數70比目標分數101小跳過,根據前指針找到王五的L2,發現分數90,比目標分數101小跳過,根據前指針找到趙六的L2,發現分數102比目標分數101大,將趙六的L2記錄到待更新數組update中,同時記錄跨度span為2。最後到下一層,張三的L1層,邏輯和剛才一樣的,也是記錄趙六的L1層和跨度span為1。
2.為新節點隨機生成層級數level(通過位運算),如果生成的level大於目前level最大值3,則將將大於部分挨個遍歷,並將跨度等信息記錄到上面update表中。
比如,新節點生成的level為5,目前level最大值為3,說明這個節點只會有一個,並且跨越了之前的所有節點,那麼我們將從第四層和第五層都遍歷下,記錄到待更新數組update中。
3.準備工作都做好了,找到了該節點將插入到哪一位置,處於哪一層,每層對應的跨度是多少,下面就要新增數據節點了。把上兩步的信息都添加到新節點上,並且調整位置前後指針即可。
4.最後就是一些收尾工作,比如修改表頭的層級level,節點大小length和尾指針tail等屬性。
綜上,整個流程就已經結束了。可能看着有點複雜,可以對照下面代碼來。
//插入節點,輸入參數為 //zsl:表頭 //score:插入元素的分數score //ele:插入元素的具體數據ele zskiplistNode *zslInsert(zskiplist *zsl, double score, sds ele) { //使用update數組記錄每層待插入元素的前一個元素 zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x; //記錄前置節點與第一個節點之間的跨度,即元素在列表中的排名-1 unsigned int rank[ZSKIPLIST_MAXLEVEL]; int i, level; serverAssert(!isnan(score)); x = zsl->header; //從最大的level開始遍歷,從頂到底,找到每一層待插入的位置 for (i = zsl->level-1; i >= 0; i--) { /* store rank that is crossed to reach the insert position */ rank[i] = i == (zsl->level-1) ? 0 : rank[i+1]; //直接找到第一個分數比該元素大的位置 //或者分數與該元素相同但是對象的ASSICC碼比該元素大的位置 while (x->level[i].forward && (x->level[i].forward->score < score || (x->level[i].forward->score == score && sdscmp(x->level[i].forward->ele,ele) < 0))) { //將已走過元素的跨越元素進行計數,得到元素在列表中排名,或者是已搜尋的路徑長度 rank[i] += x->level[i].span; x = x->level[i].forward; } //記錄待插入位置 update[i] = x; } //隨機產生一個層數,在1到32之間,層數越高,生成的概率越低 level = zslRandomLevel(); //如果產生的層數大於現有的最高層數,則超出層數都需要初始化 if (level > zsl->level) { //開始循環 for (i = zsl->level; i < level; i++) { rank[i] = 0; //該元素作為這些層的第一個節點,前節點就是header update[i] = zsl->header; //初始化后這些層每層有兩個元素,走一步就是跨越所有元素 update[i]->level[i].span = zsl->length; } zsl->level = level; } //創建節點 x = zslCreateNode(level,score,ele); for (i = 0; i < level; i++) { //將新節點插入到各層鏈表中 x->level[i].forward = update[i]->level[i].forward; update[i]->level[i].forward = x; // rank[0]是第0層的前置節點P1(也就是底層插入節點前面那個節點)與第一個節點的跨度 // rank[i]是第i層的前置節點P2(這一層里在插入節點前面那個節點)與第一個節點的跨度 // 插入節點X與後置節點Y的跨度f(X,Y)可由以下公式計算 // 關鍵在於f(P1,0)-f(P2,0)+1等於新節點與P2的跨度,這是因為跨度呈扇形形向下延伸到最底層 // 記錄節點各層跨越元素情況span, 由層與層之間的跨越元素總和rank相減而得 x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]); // 插入位置前一個節點的span在原基礎上加1即可(新節點在rank[0]的后一個位置) update[i]->level[i].span = (rank[0] - rank[i]) + 1; } /* increment span for untouched levels */ for (i = level; i < zsl->level; i++) { update[i]->level[i].span++; } // 第0層是雙向鏈表, 便於redis常支持逆序類查找 x->backward = (update[0] == zsl->header) ? NULL : update[0]; if (x->level[0].forward) x->level[0].forward->backward = x; else zsl->tail = x; zsl->length++; return x; }
int zslRandomLevel(void) { int level = 1; while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF)) level += 1; return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL; }
擔心大家忘了這張圖,再粘貼一遍。如下圖,這部分邏輯比較簡單,就不寫了,具體參考代碼分析。
//得到節點的排名 //輸入參數為表頭結構zsl,分數score,真正的數據ele unsigned long zslGetRank(zskiplist *zsl, double score, sds ele) { zskiplistNode *x; unsigned long rank = 0; int i; //先獲取表頭的頭指針,即找到管理所有節點的level數組 x = zsl->header; //從表頭的level,即最大值開始循環遍歷 for (i = zsl->level-1; i >= 0; i--) { //如果找到分數小於目標分數的,排名加上其跨度 //或者分數相同,但是具體數據小於目標數據的,排名也加上跨度 while (x->level[i].forward && (x->level[i].forward->score < score || (x->level[i].forward->score == score && sdscmp(x->level[i].forward->ele,ele) <= 0))) { rank += x->level[i].span; x = x->level[i].forward; } //確保在第i層找到分值相同,且對象相同時才會返回排位值 if (x->ele && sdscmp(x->ele,ele) == 0) { return rank; } } return 0; }
該篇主要講了Redis的ZSET數據類型的底層實現跳躍表,先從跳躍表是什麼,引出跳躍表的概念和數據結構,剖析了其主要組成部分,進而通過多幅過程圖解釋了Redis是如何設計跳躍表的,最後結合源碼對跳躍表進行描述,如創建過程,添加節點過程,獲取某個節點排名過程,中間穿插例子和過程圖。
如果覺得寫得還行,麻煩給個贊,您的認可才是我寫作的動力!
如果覺得有說的不對的地方,歡迎評論指出。
好了,拜拜咯。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※帶您來了解什麼是 USB CONNECTOR ?
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!
※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※教你寫出一流的銷售文案?
目錄
二叉樹是一種常用的數據結構,更是實現眾多算法的一把利器。本文將通過建立一個圖書庫的實例對二叉樹中的常用類型:二分搜索樹(Binary Search Tree)進行底層原理的深入理解。
1 二分搜索樹是一顆二叉樹
2 二分搜索樹每個節點的左子樹的值都小於該節點的值,每個節點右子樹的值都大於該節點的值
3 任意一個節點的每棵子樹都滿足二分搜索樹的定義
/**
- 用二分搜索樹實現圖書庫--圖書類
- - @author zhuhuix
- @date 2020-06-23
*/
public class Books implements Serializable, Comparable {
// ISBN
private Long bookId;
// 作者
private String author;
// 分類
private String category;
// 書名
private String bookName;
// 定價
private BigDecimal bookPrice;
// 出版社
private String bookPublisher;
// 出版時間
private LocalDate bookDate;
// 當前數量
private Integer bookCount;
public Books(Long bookId, String bookName, String category, String author, BigDecimal bookPrice, String bookPublisher, LocalDate bookDate, Integer bookCount) {
this.bookId = bookId;
this.author = author;
this.category = category;
this.bookName = bookName;
this.bookPrice = bookPrice;
this.bookPublisher = bookPublisher;
this.bookDate = bookDate;
this.bookCount = bookCount;
}
public Books(Long bookId){
this.bookId= bookId;
}
// 通過ISBN號進行比較大小
@Override
public int compareTo(Object o) {
if (o instanceof Books) {
return this.getBookId().compareTo(((Books) o).getBookId());
} else {
return -1;
}
}
public Long getBookId() {
return bookId;
}
public Integer getBookCount() {
return bookCount;
}
public void setBookCount(Integer bookCount) {
this.bookCount += bookCount;
}
@Override
public String toString() {
return "{" +
"ISBN=" + bookId +
", 書名='" + bookName + '\'' +
", 作者='" + author + '\'' +
", 分類='" + category + '\'' +
", 價格=" + bookPrice +
", 出版社='" + bookPublisher + '\'' +
", 出版時間=" + bookDate +
", 當前數量=" + bookCount +
'}';
}
}
/**
* 用二分搜索樹實現圖書庫--二分搜索樹
*
* @author zhuhuix
* @date 2020-06-23
*/
public class BinarySearchTree {
// 結點
private Node root;
// 書的種類
private int bookSize;
// 書的總數量
private int bookCount;
public BinarySearchTree() {
this.root = null;
this.bookSize = 0;
this.bookCount = 0;
}
// 增加元素
public void add(Books data) {
this.root = addNode(this.root, data);
}
// 用遞歸方法實現結點的添加
private Node addNode(Node node, Books data) {
// 遞歸退出條件 書不存在拉加結點,並將結點數量加1
if (node == null) {
this.bookSize++;
this.bookCount += data.getBookCount();
return new Node(data);
}
if (node.data.compareTo(data) < 0) {
node.right = addNode(node.right, data);
} else if (node.data.compareTo(data) > 0) {
node.left = addNode(node.left, data);
} else if (node.data.compareTo(data) == 0) {
// 如果結點已存在,則將書的數量累加
this.bookCount += data.getBookCount();
node.getData().setBookCount(data.getBookCount());
}
return node;
}
// 用遞歸方法實現結點前序遍歷
public void traverse(Node node) {
if (node == null) {
return;
}
System.out.println(node.getData().toString());
traverse(node.left);
traverse(node.right);
}
// 用遞歸方法實現通過isbn查找圖書
public Books search(Long isbn) {
Node node = nodeSearch(this.root, new Books(isbn));
if (node != null) {
return node.getData();
} else {
return null;
}
}
private Node nodeSearch(Node node, Books books) {
if (node == null) {
return null;
}
if (books.compareTo(node.getData()) == 0) {
return node;
} else if (books.compareTo(node.getData()) < 0) {
return nodeSearch(node.left, books);
} else {
return nodeSearch(node.right, books);
}
}
public Node getRoot() {
return root;
}
// 返回書的種類數
public int getBookSize() {
return bookSize;
}
// 返回書的總數量
public int getBookCount() {
return bookCount;
}
// 私有內部類-樹結點
private class Node {
Books data;
Node left, right;
Node(Books data) {
this.data = data;
this.left = null;
this.right = null;
}
Books getData() {
return data;
}
}
}
/**
* 用二分搜索樹實現圖書庫
*
* @author zhuhuix
* @date 2020-06-23
*/
public class BookStore {
public static void main(String[] args) {
// 構建一棵二分搜索樹
BinarySearchTree bst = new BinarySearchTree();
// 將十大暢銷圖書加入二分搜索樹
bst.add(new Books(9787115428028L,"Python編程 從入門到實踐",
"編程語言與程序設計","埃里克·馬瑟斯",
BigDecimal.valueOf(61.40),"人民郵電出版社",
LocalDate.of(2017,07,01),1));
bst.add(new Books(9787115525963L,"說服力 工作型PPT該這樣做",
"辦公軟件","秦陽",
BigDecimal.valueOf(66.30),"人民郵電出版社",
LocalDate.of(2020,05,01),1));
bst.add(new Books(9787569222258L,"零基礎學Python(全彩版)",
"編程語言與程序設計","明日科技",
BigDecimal.valueOf(67.00),"吉林大學出版社",
LocalDate.of(2018,04,01),1));
bst.add(new Books(9787121388361L,"PS之光:一看就懂的Photoshop攻略(全彩)",
"圖形圖像/多媒體","馮注龍",
BigDecimal.valueOf(60.70),"电子工業出版社",
LocalDate.of(2020,06,01),1));
bst.add(new Books(9787302423287L,"機器學習",
"人工智能","周志華",
BigDecimal.valueOf(64.80),"清華大學出版社",
LocalDate.of(2016,01,01),1));
bst.add(new Books(9787111641247L,"深入理解Java虛擬機:JVM高級特性與最佳實踐(第3版)",
"編程語言與程序設計","周志明",
BigDecimal.valueOf(106.40),"机械工業出版社",
LocalDate.of(2019,12,01),1));
bst.add(new Books(9787115472588L,"鳥哥的Linux私房菜 基礎學習篇 第四版",
"操作系統","鳥哥",
BigDecimal.valueOf(93.00),"人民郵電出版社",
LocalDate.of(2018,10,01),1));
bst.add(new Books(9787115293800L,"算法(第4版)",
"編程語言與程序設計","Robert Sedgewick,Kevin Wayne",
BigDecimal.valueOf(66.30),"人民郵電出版社",
LocalDate.of(2012,10,01),1));
bst.add(new Books(9787115537973L,"數學之美 第三版",
"計算機理論、基礎知識","吳軍",
BigDecimal.valueOf(54.40),"人民郵電出版社",
LocalDate.of(2020,05,01),1));
bst.add(new Books(9787302255659L,"大話數據結構",
"編程語言與程序設計","程傑",
BigDecimal.valueOf(47.20),"清華大學出版社",
LocalDate.of(2011,06,01),1));
// 遍歷圖書庫
System.out.println("圖書庫新建:");
System.out.println("書的種類數:"+bst.getBookSize());
System.out.println("書的總數量:"+bst.getBookCount());
bst.traverse(bst.getRoot());
// 再次增加相同的書
bst.add(new Books(9787302255659L,"大話數據結構",
"編程語言與程序設計","程傑",
BigDecimal.valueOf(47.20),"清華大學出版社",
LocalDate.of(2011,06,01),1));
bst.add(new Books(9787115472588L,"鳥哥的Linux私房菜 基礎學習篇 第四版",
"操作系統","鳥哥",
BigDecimal.valueOf(93.00),"人民郵電出版社",
LocalDate.of(2018,10,01),1));
bst.add(new Books(9787115293800L,"算法(第4版)",
"編程語言與程序設計","Robert Sedgewick,Kevin Wayne",
BigDecimal.valueOf(66.30),"人民郵電出版社",
LocalDate.of(2012,10,01),1));
// 再次遍歷圖書庫
System.out.println("圖書庫同種圖書加入:");
System.out.println("書的種類數:"+bst.getBookSize());
System.out.println("書的總數量:"+bst.getBookCount());
bst.traverse(bst.getRoot());
// 根據ISBN號查找圖書
Books books =bst.search(9787115472588L);
if (books!=null) {
System.out.println("已找到該圖書:");
System.out.println(books.toString());
}
}
}
程序輸出如下:
圖書庫新建:
書的種類數:10
書的總數量:10
{ISBN=9787115428028, 書名='Python編程 從入門到實踐', 作者='埃里克·馬瑟斯', 分類='編程語言與程序設計', 價格=61.4, 出版社='人民郵電出版社', 出版時間=2017-07-01, 當前數量=1}
{ISBN=9787111641247, 書名='深入理解Java虛擬機:JVM高級特性與最佳實踐(第3版)', 作者='周志明', 分類='編程語言與程序設計', 價格=106.4, 出版社='机械工業出版社', 出版時間=2019-12-01, 當前數量=1}
{ISBN=9787115293800, 書名='算法(第4版)', 作者='Robert Sedgewick,Kevin Wayne', 分類='編程語言與程序設計', 價格=66.3, 出版社='人民郵電出版社', 出版時間=2012-10-01, 當前數量=1}
{ISBN=9787115525963, 書名='說服力 工作型PPT該這樣做', 作者='秦陽', 分類='辦公軟件', 價格=66.3, 出版社='人民郵電出版社', 出版時間=2020-05-01, 當前數量=1}
{ISBN=9787115472588, 書名='鳥哥的Linux私房菜 基礎學習篇 第四版', 作者='鳥哥', 分類='操作系統', 價格=93.0, 出版社='人民郵電出版社', 出版時間=2018-10-01, 當前數量=1}
{ISBN=9787569222258, 書名='零基礎學Python(全彩版)', 作者='明日科技', 分類='編程語言與程序設計', 價格=67.0, 出版社='吉林大學出版社', 出版時間=2018-04-01, 當前數量=1}
{ISBN=9787121388361, 書名='PS之光:一看就懂的Photoshop攻略(全彩)', 作者='馮注龍', 分類='圖形圖像/多媒體', 價格=60.7, 出版社='电子工業出版社', 出版時間=2020-06-01, 當前數量=1}
{ISBN=9787115537973, 書名='數學之美 第三版', 作者='吳軍', 分類='計算機理論、基礎知識', 價格=54.4, 出版社='人民郵電出版社', 出版時間=2020-05-01, 當前數量=1}
{ISBN=9787302423287, 書名='機器學習', 作者='周志華', 分類='人工智能', 價格=64.8, 出版社='清華大學出版社', 出版時間=2016-01-01, 當前數量=1}
{ISBN=9787302255659, 書名='大話數據結構', 作者='程傑', 分類='編程語言與程序設計', 價格=47.2, 出版社='清華大學出版社', 出版時間=2011-06-01, 當前數量=1}
圖書庫同種圖書加入:
書的種類數:10
書的總數量:13
{ISBN=9787115428028, 書名='Python編程 從入門到實踐', 作者='埃里克·馬瑟斯', 分類='編程語言與程序設計', 價格=61.4, 出版社='人民郵電出版社', 出版時間=2017-07-01, 當前數量=1}
{ISBN=9787111641247, 書名='深入理解Java虛擬機:JVM高級特性與最佳實踐(第3版)', 作者='周志明', 分類='編程語言與程序設計', 價格=106.4, 出版社='机械工業出版社', 出版時間=2019-12-01, 當前數量=1}
{ISBN=9787115293800, 書名='算法(第4版)', 作者='Robert Sedgewick,Kevin Wayne', 分類='編程語言與程序設計', 價格=66.3, 出版社='人民郵電出版社', 出版時間=2012-10-01, 當前數量=2}
{ISBN=9787115525963, 書名='說服力 工作型PPT該這樣做', 作者='秦陽', 分類='辦公軟件', 價格=66.3, 出版社='人民郵電出版社', 出版時間=2020-05-01, 當前數量=1}
{ISBN=9787115472588, 書名='鳥哥的Linux私房菜 基礎學習篇 第四版', 作者='鳥哥', 分類='操作系統', 價格=93.0, 出版社='人民郵電出版社', 出版時間=2018-10-01, 當前數量=2}
{ISBN=9787569222258, 書名='零基礎學Python(全彩版)', 作者='明日科技', 分類='編程語言與程序設計', 價格=67.0, 出版社='吉林大學出版社', 出版時間=2018-04-01, 當前數量=1}
{ISBN=9787121388361, 書名='PS之光:一看就懂的Photoshop攻略(全彩)', 作者='馮注龍', 分類='圖形圖像/多媒體', 價格=60.7, 出版社='电子工業出版社', 出版時間=2020-06-01, 當前數量=1}
{ISBN=9787115537973, 書名='數學之美 第三版', 作者='吳軍', 分類='計算機理論、基礎知識', 價格=54.4, 出版社='人民郵電出版社', 出版時間=2020-05-01, 當前數量=1}
{ISBN=9787302423287, 書名='機器學習', 作者='周志華', 分類='人工智能', 價格=64.8, 出版社='清華大學出版社', 出版時間=2016-01-01, 當前數量=1}
{ISBN=9787302255659, 書名='大話數據結構', 作者='程傑', 分類='編程語言與程序設計', 價格=47.2, 出版社='清華大學出版社', 出版時間=2011-06-01, 當前數量=2}
已找到該圖書:
{ISBN=9787115472588, 書名='鳥哥的Linux私房菜 基礎學習篇 第四版', 作者='鳥哥', 分類='操作系統', 價格=93.0, 出版社='人民郵電出版社', 出版時間=2018-10-01, 當前數量=2}
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※為什麼 USB CONNECTOR 是電子產業重要的元件?
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※台北網頁設計公司全省服務真心推薦
※想知道最厲害的網頁設計公司"嚨底家"!
※新北清潔公司,居家、辦公、裝潢細清專業服務
※推薦評價好的iphone維修中心
由於身處一家網絡公司,日常項目中涉及到的網絡概念較多,恰逢之後公司組織相關培訓。藉此機會,打算寫下一系列文章用於之后梳理並回顧。文章主要涉及 NA,NP 中所覆蓋的知識。由於網絡分為較多方向,如路由交換,無線,安全等。在今年,大綱正好有所改變,其中無線和路由交換放在一起合稱為企業架構。所以本系列文章以企業架構為主。
在網絡界,Cisco 證書一直被普遍認可,其中分為三個等級 NA,NP,IE. 對於開發人員來說,掌握 NA 水平一般即可,本系列文章會 NA 開始,到 NP 結束。NA 內容較為寬泛,其中涉及知識面較寬,但不深入,用於入門。NP 在 NA 基礎上,更加深入,涉及到更多的協議與概念。
話不多說,在閱讀本文後,應該了解以下內容:
先看一下網絡的組成組件:
主要分為 4 大類:
由此可見,網絡就是由上述設備組成,在其中進行數據產生,轉發的過程。在討論網絡時,一般討論的都是企業網絡,下面是常見的一張企業網絡的架構圖。
從圖中我們可以看到,網絡的大體架構由,終端設備,接入層設備(交換機,用於將設備接入),轉發層設備(路由器)和數據中心組成。舉例子來說,如果左下角的同學 A 想要和右上角的同學 B 同學通信,則需要經歷如下過程:
設備連入的端口,稱為接口,下面是常見的接口類型。
| 接口名稱 | 速度 |
|---|---|
| Ethernet | 10M |
| Fast Ethernet | 100M |
| GigabitEthernet | 1000M |
| 10GigabitEthernet | 10000M |
| 40GigabitEthernet | 40000M |
| 100GigabitEthernet | 1000000M |
| Serial – 串行口 |
在討論或者設計一個網絡架構是,往往會在如下的方面進行討論:
表示數據的發送速率,單位為比特每秒(b/s),意思為一秒鐘發送的比特數,因此帶寬又稱為比特率。(以太網: 10Mbps, 快速以太網:100Mbps)
在設計網絡架構時,要考慮到可拓展性,公司的人數會隨着時間增加。
數據傳輸和存儲的安全。
對流量進行分類整理,拿家庭具體,分類出訪問 QQ 的流量,訪問 P2P 的流量,然後對其進行限制設置上限,防止一個服務佔用過大的帶寬,造成其他服務無法正常訪問。
設備及搭建網絡的費用。
將一個物理設備虛擬化成多個虛擬設備,例如交換機,路由器等。
物理拓撲:實際設備之間的物理連接的布局,稱為物理拓撲。
物理之間拓撲的比較:
| 拓撲類型 | 優點 | |
|---|---|---|
| 總線拓撲 | 1. 所用電纜少 2. 結構簡單 3. 易於擴充 4. 布線方便 |
1. 傳輸距離有限,通信範圍受到限制 2.故障診斷和隔離較困難 3.所有數據經過總線傳送,不具有實時功能 4. 單點故障:所有 PC 不得不共享線纜,一個節點出錯,將影響整個網絡 |
| 環形拓撲 | 1. 增加或減少工作站時,僅需要簡單的連接操作 2. 電纜長度短 3. 傳輸延遲確定 |
1. 傳輸距離有限,通信範圍受到限制 2. 故障診斷和隔離困難 3. 節點過多時影響傳輸效率 4. 任意節點出現故障,整個網絡將癱瘓 |
| 星型拓撲-局域網較為常見 | 1. 集中控制,控制簡單 2. 故障診斷和隔離容易 3. 網絡延遲短 |
1. 中央節點的負擔較重,形成瓶頸 2. 各節點的分佈處理能力較低 3. 網絡共享能里較差 |
| 部分網狀拓撲-廣域網常見 | 1. 系統可靠性高,比較容易擴展 | 1. 結構複雜,每一結點都與多點進行連結 2. 因此必須採用路由算法和流量控制方法。 |
邏輯拓撲:以數據轉發的過程為側重,描述節點之間數據的轉發過程。
在網絡中提供服務的應用種類較多,對應對網絡的要求也一般不同,可大致分為如下幾類:
本篇內容中,多為網絡的基礎概念,方便大家入門,只需理解有個印象就好。接下來的內容,才是真正學習的網絡的開始。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※台北網頁設計公司這麼多該如何選擇?
※智慧手機時代的來臨,RWD網頁設計為架站首選
※評比南投搬家公司費用收費行情懶人包大公開
※幫你省時又省力,新北清潔一流服務好口碑
※回頭車貨運收費標準
摘錄自2019年9月29日中央社報導
瑞士即將在3週後舉行國會大選,主辦單位指出,約10萬人29日在瑞士首都伯恩(Bern)上街遊行,呼籲採取行動遏阻氣候變遷。
遊行由80個競選團體主辦,它們自稱是「氣候聯盟」(Climate Alliance)。伯恩警方未針對主辦單位估計的共襄盛舉人數發表評論,但警方發言人賈吉(Dominik Jaggi)告訴法新社,「這是伯恩近年來最大規模示威抗議之一」。
Bern, Switzerland
60,000 people— 350.org Europe (@350Europe)
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※帶您來了解什麼是 USB CONNECTOR ?
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!
※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※教你寫出一流的銷售文案?