打造最可靠的自動駕駛基礎架構

文章作者:莫璐怡 Pony.ai

編輯整理:Hoh Xil

內容來源:Pony.ai & DataFun AI Talk

出品社區:DataFun

注:歡迎轉載,轉載請在留言區留言。

導讀:本次分享的主題為打造最可靠的自動駕駛基礎架構。主要內容包括如何做 Pony.ai 自動駕駛系統的基礎架構,涉及到的技術困難,以及我們是如何克服的。

首先先了解下傳統互聯網公司的基礎架構:

數據基礎設施,會包括大規模的數據庫、分佈式的文件系統;

計算平台,可能會需要大量的服務器、大數據平台、容器的管理機制;

Web 服務管理,同時還會有各種各樣的 Web Service,不停的迭代來滿足新的業務發展。

這是傳統互聯網公司要做的事情,但是對於自動駕駛公司和 Pony.ai,在這樣的架構基礎上我們還會做哪些事情?

這是 Pony.ai 的基礎架構,包含了所有傳統互聯網公司要做的事情,除此之外,還需要做如下事情:

自動駕駛車載系統,如何支持各種各樣的AI技術、算法,如何控制車輛,這都依賴於自動駕駛車載系統來完成。

大規模仿真平台,Pony.ai 每天至少會跑 30W 公里的仿真測試(很多自動駕駛公司一年跑的里程可能只有百萬級別),這點對於自動駕駛測試來說非常重要。

車隊運營基礎平台,Pony.ai 要打造自己的移動出行服務,需要基礎平台來支持 Robotaxi 的運營。

可視化平台與人機接口,可視化平台是幫助我們了解系統到底是如何思考、運作的,或者當測試工程師做各種測試的時候都依賴於可視化平台;人機接口,自動駕駛車輛最終是要提供出行服務,是有乘客在裏面,這時會有一個可視化的界面,來告訴乘客車所感知的周圍環境,以及接下來的駕駛操作等等信息,同時還會提供人機交互的功能,讓乘客也能控制車輛,比如輸入目的地,或者需要停車等等。

Pony.ai 的目標是打造自動駕駛移動出行平台,我們希望可以在不同的城市,可以提供大規模自動駕駛車輛的運營,那麼我們的基礎架構會面臨以下挑戰:

車輛數量的增加,目前廣州已經有幾十輛車在進行測試,同時還在不停的增長着;

運營區域的擴大,剛開始只是在很小的區域進行測試,目前已經在幾百平方公里的區域進行測試;

數據量的增長,我們有很多的傳感器,以及車輛和運營區域的增加,都使得數據量的增長非常非常非常大;

工程師數量的增長,目前 Pony.ai 有廣深、北京、美國四個 office,工程師的數量每周都在增長,所以導致模塊數量和內部代碼的數量也在增長。

所有的這些增長都要求我們的技術棧是具有可擴展性的,來滿足快速增長所帶來的挑戰。

剛剛講了整個基礎架構,其中重要的一點就是車載系統,在講車載系統之前,先簡單介紹下自動駕駛系統:

傳感器及其他硬件:激光雷達、高分辨率攝像頭、毫米波雷達、GNSS/IMU、運算平台,我們可看到圖中標了不同的顏色,目前這些傳感器是通過 Supplier Partner 來得到的,我們自己不做傳感器,我們需要去購買他們的產品,但是購買之後需要做數據進一步的分析和整合,然後做後面的處理,然後對於運算平台除了 supplier 的一些應用外,我們自己也會做一些優化。傳感器主要要做的事情就是接收真實世界的數據,然後傳遞給 Pony.ai 自動駕駛系統中。

自動駕駛系統:首先,要做傳感器融合,進行時間同步,將多傳感器的數據融合在一起;然後是感知模塊,用來感知周圍的環境有什麼樣的障礙物和物體;接下來會進行行為預測,預測這樣的障礙物或物體之後的行為會是什麼樣的;然後才到我們的決策規劃模塊,按照之前的預測來決定之後車輛的動作,如急剎車、讓路、超車等動作;最後,就是我們的控制模塊,他會按照決策規劃模塊,告知我們的系統要怎麼做,然後決定怎麼踩剎車、油門,怎麼打方向盤。

車輛,我們本身是不造車的,所以車輛是由 OEM 提供的,但是整個控制的算法,是我們自研去做的。

除此之外,還有高精地圖與定位模塊,以及數據與系統架構(數據的處理,以及控制數據在不同模塊的流動)。

這裏介紹的是各個模塊,但最後把他們串聯起來,靠的是我們的自動駕駛軟件系統,這就是自動駕駛的車載系統。很多自動駕駛企業使用的是 ROS 的一套工業系統,而 Pony.ai 是從第一行代碼開始,寫了一套 PonyBrain,自研的多層次自動駕駛車載系統,最主要的做的事情有:

多模塊的調度運行,所有模塊的調度運行都是 Pony.ai 自己去做的。

模塊間的消息通信,如何把數據從激光雷達傳遞到傳感器融合的模塊,再把融合的結果放到感知模塊中,然後感知的數據怎麼告訴行為預測、決策規劃等等模塊,以及如何拿到高精地圖與定位的信息。

車載計算資源的分配與管理,對於自動駕駛來說反應速度是非常重要的,這就需要我們對內存、CPU、GPU 等有足夠的優化,做到定製化的車載計算資源分配與管理。

日誌記錄,同時我們需要完善的日誌記錄,我們所有的測試數據回來都需要一整套的 Pipeline 去做自動化的分析,然後幫我們評判出有意義的數據,給到測試工程師或者研發工程師,進行進一步的分析去使用,然後進一步提升我們的模型。

監控與報警,保證了我們自動駕駛的安全性。

車載系統的挑戰:

① 可靠性:車載系統必須足夠的可靠,不能有任何的內存泄露、代碼邏輯的錯位,這種都是零容忍的,一旦發生了這樣的事情,對整個自動駕駛系統來說是非常嚴重的事故,是有可能影響到安全性的,對於 Pony.ai 自動駕駛系統技術的發展來說,安全永遠是我們的第一位,所以所有影響安全性的事情,我們都是零容忍的,同時他也會影響車隊運營的效率;所以我們還需要系統監控與異常報警,一旦系統出現任何問題,我們需要及時提醒安全員,做出車輛接管的操作。

② 高性能:滿足模塊間通信的海量數據壓力,同時實現低延遲。

③ 靈活性:支持多種不同類型的計算資源的接入,以及不同類型模塊的接入,需要有靈活的系統來支持計算資源的高速迭代。

車載系統的實踐:

可靠性:

① 代碼質量要求高:對於可靠性來說我們有非常嚴格的 code review 和 unit test,相信這是在國內互聯網公司不太容易見到的一件事情,雖然會非常耗時,但是對可靠性的提升是有非常大的幫助的。

② 合理使用工具幫助發現問題:同時我們也會使用非常多的工具,如靜態分析、ASAN 等等,來做離線的分析,來保證系統的可靠性。

③ 多重系統可靠性檢查:包括系統啟動前校驗,系統運行時實時監控,系統運行后數據分析等。

④ 這是我們的持續集成與發布的平台:對於每一次代碼的修改,我們都會進行仿真測試;然後對於研發的迭代,我們每周會有 Release 版本的更新,保障版本的穩定性,同時,剛剛我們整個測試包括封閉,半封閉,高峰期的測試,整個測試流程怎麼持續集成與發布,也是保證系統可靠性的一種方法。

高性能:

① 合理的架構避免大數據拷貝等嚴重影響性能的邏輯。

② 依據模塊邏輯分配合適的計算資源,如內存、CPU、GPU 等。

③ 定期對整個系統 Profile 分析系統的性能瓶頸。

靈活性:

① 定義足夠通用的模塊公共接口。

② 定義足夠通用的消息通信接口。

為什麼需要仿真系統?因為仿真系統可以使得我們車還沒有上路的時候,就已經做了大規模的自動駕駛測試,無需路測和人力接入就可以評價系統的性能變化;由於沒有進行路測,不會引起路面事故;同時,仿真系統還提供了基於數據驅動快速迭代算法的可行性,新的算法可以先在仿真平台上做驗證,一些具體的指標和測試的信息都會在仿真平台上有所體現。

仿真系統數據的倆個不同來源:

① 支持真實路測收集的場景,我們的路測數據非常的多,數據回來之後,通過 Data Pipeline 自動更新這些有意義和有意思的場景,我們會根據當時的場景改動相應的模塊,然後會在仿真系統重跑當時的場景,來判斷新的方法是否 work;

② 支持人工和隨機生成的場景,這樣的一些仿真的場景,也是非常的重要的,因為雖然我們在做大規模的路測,但是不代表可以遇到所有的場景,很多場景無法在路測中收集到,這就需要我們通過人工去創造這樣的場景出來,給我們的系統一些樣本,來學習如何處理這樣的場景,保證我們新的 feature 在這樣的場景不會出現問題。

仿真平台的挑戰與實踐:

① 仿真結果的可靠性:首先仿真的結果必須是可靠的,如果不可靠,用它檢測出來的結果是沒有任何的意義的。整個仿真是在服務端模擬車載環境跑的,同時在服務端構建車輛動力學模型,保證測試的數據足夠可靠。

② 仿真數據的選擇與管理:當然我們會選擇合適的路測數據來幫助算法的迭代(這裏的選擇不是人工的選擇,是全自動化的選擇,幫我們在茫茫數據中挑選出有意義的數據);另外,我們還會規範的依據類別管理大規模的仿真數據,比如感知模塊的一些改動,到底需要測試哪些數據,才會更加的體現這個改動帶來多少影響,這裏我們會有內部的一個分類,我們不會對所有的數據進行無差別的仿真(這樣做意義不大)。

③ 仿真系統的性能:我們將整個仿真系統并行部署在分佈式計算平台中,這才可能滿足我們單天 30W 公里以上的仿真測試,並且這個數據還在不斷增長。

數據基礎架構:

數據是自動駕駛技術進步的核心驅動力,沒有數據,我們就看不到現在如此多的測試車輛在進行路測,數據本身有幾個重要的點:

① 如何存儲海量的數據,如何支持快速的訪問。

② 如何進行數據處理。

③ 如何進行數據同步,如何把不同區域、路測數據、車載數據同步到數據集中,如何讓不同辦公區的工程師都可以使用這些數據,對數據同步來說是一個很大的挑戰。

核心挑戰:

① 數據量大:我們有 PB 級別的數據,這裏只是以攝像頭為例,還包括其他傳感器數據,以及系統運作的中間數據等等。

② 數據屬性不同於互聯網數據:我們的數據由客戶端產生,有大量的傳感器數據、大量的模塊運行日誌,這與互聯網數據有本質的區別,所以對整個數據架構的要求也是不一樣的。

數據存儲的挑戰:

① 依據特定的使用場景設計合理的存儲格式的設計:以便於車載系統記錄、大規模數據分析(數據回來之後,需要有方法進行分析,找出有意義的數據)、部分數據訪問、文件系統存儲(如何高效的利用文件系統)等。

② 選擇合適的存儲系統:

針對冷/熱數據選擇不同方案

選擇高可用的存儲系統

選擇易於水平擴展,因為車輛規模是不停的在變大的,運營時間越來越長,數據的增長速度是遠超想象的,所以需要易於水平擴展的存儲系統。

控製成本,不能用過於昂貴的設備。

數據處理可以幫助收集性能指標,有 MPI(平均每次接管所需里程)、模塊運行效率、乘客舒適度體驗等,還有就是路測有趣場景的挖掘,如接管、急剎、感知算法識別、不合理的變道策略等用於模型訓練和仿真。

數據處理的挑戰:

① 減小數據採集到處理的全流程時間:如何以最快的速度把數據從車傳到中間處理系統,Data Pipeline 運行完之後,上傳到數據中心,這裏面我們做了非常多的工作。

② 依據不同類型數據處理任務選擇合適的處理系統:計算量要求比較高的我們選擇 CPU 密集型系統來處理;更多的會是車載的數據,我們會選擇 IO 密集型系統進行處理。

③ 通用的任務定義以支持靈活的添加新任務:幫我們檢測出來更多有意義的數據。

車隊運營基礎平台:

我們有一個 Pony Pilot 項目,在我們廣州所有的內部員工都可以使用,同時在北京和美國加州,也有同樣的服務已經上線,那麼支持這樣的服務,我們需要做哪些事情:

Fleet Control Center,車隊控制中心

Pony Pilot APP

Onboard system

各種各樣的 webapp,幫助我們觀察整個車隊的運營情況,幫助管理測試的車輛和人員。

車隊運營基礎平台的挑戰:

需要支持複雜需求變化的 web 框架,同時我們有大量的 web service 的部署與管理,這都需要我們去完善 web 服務通用組件,例如部署工具、日誌記錄平台隨時排查問題、監控平台保證所有 service 平台的高可容性。

容器與服務調度平台:

通過 Kubernetes 來幫我們做各種各樣的服務調度和集群支持。

可視化平台:

① 目標:方便人類理解無人車系統看到的世界

② 挑戰:首先,需要足夠的靈活,易於適配不同需求的工具;其次,需要有高性能的現實,如 3D 實時渲染的高效實現;最後,支持跨平台的可視化框架,如桌面系統、移動系統、Web 等多平台。

人機接口:

方便乘客使用的用戶界面,同時可以看到自動駕駛是如何了解世界,如何做決策,如何規劃之後的行為等等,給乘客更多的信息和信任。

總結:

① Pony.ai 的基礎架構工作包括:

傳統互聯網公司所需要解決的基礎架構挑戰。

自動駕駛技術特定的基礎架構挑戰。

② 在這裏工作你可以:

接觸自動駕駛系統的各個方面。

設計並實現滿足通用需求的單機和分佈式系統。

系統的保障自動駕駛技術的持續進步。

這是一個非常有意思的 team,裏面有很多有意思的工作,非常歡迎大家與我們一起來工作,推動整個自動駕駛的發展,謝謝大家!

歡迎關注DataFunTalk同名公眾號,收看第一手原創技術文章。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※小三通海運與一般國際貿易有何不同?

※小三通快遞通關作業有哪些?

Flutter 構建的 Mac 桌面應用上無法發出網絡?

在上一篇文章中我們分享了,如何開發桌面應用。在本章文章中,來解決一下為何在 Mac 中無法發出網絡情況的原因。

起因

事情​起因是這樣的:我總覺得寫一個 Demo 不足以體現我們開發同學的能力。直到最近,我發現了一個可以改善的小點,可幫助我們的測試同學提高測試效率。

大體情況就是在某天晚上,客戶端的一個小問題,需要進行驗證。但是呢,測試同學要做回歸測試,把所有的數據都重新創建了一遍。但是此過程用了很久,理論來說,應該十來分鐘搞定的事情。我就靜靜的在她身旁看着,內心捉急萬分,畢竟我想早點回家(睡覺,打遊戲,看電視)。最後晚上 11 點多打車回家,一路上我都在想,這個問題應該很快就能驗證好吧,為何要折騰這麼就呢?也許是流程真這麼長吧,那我們無法改變流程,那就做出能提升效率的工具吧。

次日,我把我的想法告訴了她,但是她說我們有自己的網頁工具,可以解決啊,只是現在沒時間創建腳本。隨後我擱置這個想法,但是這種提升效率的想法一直縈繞在我的心頭。

再然後,某天突然意識到,同樣是工具,大家都會使用順手好用的,幹嘛使用哪種傳統老土的工具呢?基於這一點,我開啟了新的探索。

我不僅要做客戶端的,還要做網頁的,更要做桌面應用(測試同學最關注)。我要體驗更好,不僅方便我自己測試,還要給所有的測試同學提供便利,減少加班是我的最終目的,哈哈哈。

想法有了,那就開始實施吧。之前遇到一個問題,一直沒解決,但是此刻必須解決了。那就是之前 Flutter 構建的 Mac 應用后,無法發出網絡請求。

在桌面應用無法發出請求?

添加 Dio 以後,會遇到這種情況:



提示,當前系統不支持該操作。

為何會有如此問題,在 Dio 上支持 Other,也就是支持 Mac ,Windows, Linux, 為何我們直接運行有錯誤呢?



具體原因

實際是因為 Mac 應用有沙箱限制,需要在對應文件中開啟即可。

<key>com.apple.security.network.client</key>
<true/>



添加以後,效果如下:


具體參考: https://github.com/google/flutter-desktop-embedding/issues/546

代碼示例:

import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

// Sets a platform override for desktop to avoid exceptions. See
// https://flutter.dev/desktop#target-platform-override for more info.
void _enablePlatformOverrideForDesktop() {
  if (!kIsWeb && (Platform.isMacOS || Platform.isWindows || Platform.isLinux)) {
    debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
  }
}

void main() {
  _enablePlatformOverrideForDesktop();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  String requestData = "";

  void _incrementCounter() {
    setState(() {
      _counter++;
      getHttp();
    });
  }

  void getHttp() async {
    try {
      Response response = await Dio().get("http://www.gdky005.com");
      requestData = response.toString();
      print(requestData);
    } catch (e) {
      print(e);
      requestData = e.toString();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            Container(
              height: 400,
              child: ListView(
                children: <Widget>[
                  Text(
                    '$requestData',
                  )
                ],
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

※小三通物流營運型態?

※快速運回,大陸空運推薦?

貫穿野生棲地 加州高鐵路段惹質疑

摘錄自2018年9月28日蘋果日報美國加州報導

美國加州高鐵動工興建以來,一直被工程延誤、造價飆升、以及市民告上法院反對計劃等事件所困擾。負責鐵路管理的加州高速鐵路局,周一就最新的南加州棕櫚谷(Palmdale)至柏本克(Burkbank)路線舉行公聽會,近百人到現場示威,對該項目潛在影響表達疑慮。

公聽會在洛杉磯郡Sun Valley進行,300多名對計劃存疑的聖費爾南多谷(San Fernando Valley)居民出席。在場的示威者向鐵路管理層,就新路線對地震斷層、野生動物過境點、地面震動、廢氣排放、貨車交通等各項影響提出質疑。一名與會者表示,簡報並未能消除她的疑慮。

當局上週透露,棕櫚谷至柏本克之間的首選路線,是原定計劃的修訂版。局方屬意這條全長38.6英里路徑,它的地下路段雖較其他版本多上25.2英里,卻是最簡單,興建最快和風險最低的選擇。

新路線將貫穿聖蓋博山(St. Gabriel Mountains)和鄰近的住宅區,並途經聖塔克拉利塔(Santa Clarita),但繞過Shadow Hills和Lake View Terrace,即原來最爭議最大的部分。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※小三通海運與一般國際貿易有何不同?

※小三通快遞通關作業有哪些?

球系統科學家Surendra Adhikari表示,研究團隊設計出一套地球自旋物理學電腦模型

球系統科學家Surendra Adhikari表示,研究團隊設計出一套地球自旋物理學電腦模型,加入20世紀大陸冰川(冰蓋)與海水平衡變化的所有數據,終於找出影響地軸飄移至關重要的第2個原因:格陵蘭島冰蓋大量融化。

目前地球上僅存的大陸冰川只剩下南極洲與格陵蘭島,南極冰蓋覆蓋範圍約1,400萬平方公里,隨著20世紀氣溫上升加劇,格陵蘭冰蓋至今已有約7,500億噸的冰融化進入海洋,這導致地球質量分佈發生變化,進而使地軸飄移。一旦南極冰蓋融化,全球海平面將上升61.1公尺;格陵蘭冰蓋則佔據格陵蘭島82%陸地面積,如果格陵蘭冰蓋融化,將導致海平面上升7.2公尺。這項研究明確顯示了人類活動正在改變地球的基本性質及運作方式。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

※小三通物流營運型態?

※快速運回,大陸空運推薦?

從 Gogoro 談起,點評台灣電動車產業與政策布局

電動車大廠特斯拉(Tesla)Model 3 於 2016 年 3 月預售開始後銷售勢如破竹,首周預購量突破 32.5 萬輛,造成產業界轟動,特斯拉高層戴爾穆德‧歐康納(Diarmuid O’Connell)於阿姆斯特丹參與電動車會議時表示,這波預購熱潮正向產業界發送訊息──電動車有極大市場需求。許多市場人士認為特斯拉已經到了「iPhone 時刻」,因為就預購與首發銷售數字比較,特斯拉 Model 3 在 2 天內預購數就達 23.2 萬輛,已經逼近初代 iPhone 在 2 天內銷售 27 萬支的成績,而在汽車史上則根本沒有可以相提並論的例子。拿「iPhone 時刻」來比擬 Model 3,可看出市場 Model 3 預售成績的驚豔轉變成期待:期望像 iPhone 啟動智慧型手機取代傳統手機的浪潮,就此讓電動車躍居主流,引爆換車巨大商機。

台灣產業界也對此風潮樂觀其成,近年來台灣電子產業鏈過度仰賴蘋果供應鏈,眼看就要隨著蘋果產品市場逐漸飽和而沉淪,如今特斯拉接到大量訂單後需要量產交貨,許多產業界人士認為台灣供應鏈最擅長規模量產、降低成本,可望在電動車零組件有新供應鏈成形。   談起特斯拉、台廠與台灣供應鏈,就不禁讓人聯想起台灣電動機車品牌 Gogoro。Gogoro 總部位於林口,其電動機車零組件除了電池與 Panasonic 合作以外,多數均由台廠供應鏈供應,而眾多歐美媒體將之譽為「二輪特斯拉」,與特斯拉相提並論。不過,相對於特斯拉不僅成為全球熱門話題,也同時成為台灣產業界注目的焦點,Gogoro 近來則似乎有點在國內媒體雷達上消失。  
Gogoro 立足台灣  打響國際知名度   儘管在國內關注熱度大不如首發之前,Gogoro 在國際舞台上倒是持續發聲。2015 年 10 月時,《富比士》(Forbes)評選 2015 年全球物聯網新創企業百強(Top 100 Internet Of Things Startups For 2015),台灣只有 Gogoro 唯一一家公司上榜,且位於前十之列的第 8 名。   2015 年 12 月,各國領袖及重量級企業雲集巴黎氣候峰會(COP21),台灣受限於 COP21 為聯合國活動,未能取得觀察員身分,官方代表無法參加,只能靠民間企業為國發聲,台達電與 Gogoro 受邀氣候峰會解決方案大展,台達電展出綠建築、Gogoro 展示電動機車與換電池站。Gogoro 也受邀參加 50 國、750 位代表與會的永續創新論壇,執行長陸學森成為 60 位登上論壇分享的代表之一。   Gogoro 之所以能有機會參與巴黎峰會,前駐法大使呂慶龍也助了一臂之力,呂慶龍曾經以台灣布袋戲向法國行銷台灣而聞名,卸任前更留下「大家忘掉呂大使也沒關係,只要記得台灣,我就算成功了」的名言。呂慶龍在 2015 年 10 月時參觀 Gogoro 信義區的體驗中心,認為十分適合向歐洲發展,之後積極協助安排,在短短 2 個月內讓 Gogoro 擠進巴黎氣候高峰會。無獨有偶,特斯拉執行長馬斯克在巴黎峰會期間,身為電動車產業領袖,也於 2015 年 12 月 2 日在巴黎第一大學發表演講,探討碳排放、氣候變遷,以及停用化石燃料等議題。

 
(Source:Gogoro)   2016 年 1 月的國際消費性電子大展(CES)上,Gogoro 也再度受邀於 Panasonic 展區設攤,因而成為唯一設展於 CES 主展館的台灣企業,Gogoro 在 Panasonic 展區的「鄰居」,正是也與 Panasonic 電池合作的特斯拉,展出其 Model S 電動車,這個因緣際會,使得 Gogoro 在國際大展場合上再度與特斯拉平起平坐,落實了前一年 CES 上多家歐美科技媒體將之比擬為「二輪特斯拉」的稱譽。  
順應全球綠能潮流  善用台灣供應鏈優勢   相對於特斯拉目前的絕頂風光,Gogoro 若拿來相提並論似乎有點失色,不過其實特斯拉也並非從開始就一帆風順,兩家企業的歷程,有許多有趣的比較之處。   首先,就資金面而言,特斯拉成立於 2003 年,至 2007 年,前 4 輪募資總計募得 1.05 億美元;Gogoro 於 2011 年成立,在 2015 年 11 月 13 日完成第二輪增資募得 1.3 億美元,投資者包括合作夥伴 Panasonic,總募資額達 1.8 億美元。也就是說,Gogoro 募資的速度與金額,其實還勝過特斯拉草創初期。   台灣企業往往資本規模遠小於歐美同業,更不用提新創企業的初期資本額只是其他產業的「百分之一」,但 Gogoro 卻能逆勢而行,取得超過特斯拉初期的資本,除了身為後進者,受惠於產業風向往電動車、電動機車發展的潮流更加明顯之外,也還有其產業鏈上的因素。兩公司之後的歷程證明,善用台灣供應鏈的確有其優勢。   特斯拉研發時程相當長,2008 年 5 月時,媒體甚至戲謔的推出「特斯拉死亡倒數時鐘」,因為特斯拉當時若得不到進一步的資金就要倒閉。其第一款電動車 Roadster 於 2008 年起出貨,至 2009 年 7 月才總算為公司帶來獲利。此後,特斯拉也一直以出貨延遲聞名,Roadster 本身就延遲 9 個月交貨,Model S 延遲超過 6 個月,Model X 更延遲超過 18 個月。   相對的,陸學森最初規劃 Gogoro 研發時程要到 2018 年才推出產品,但由於台廠供應鏈成熟,設計研發速度超前,在 2015 年就正式上市,此後出貨也相對順暢,至 2016 年 3 月 1 日累計銷售突破 6,000 輛,尚未有明顯的交貨延遲現象。相較之下,特斯拉第一款產品 Roadster 當年的總出貨量則不過 2,450 輛。

 
(Source:Gogoro)   從 Gogoro 經驗來看,台灣產業能取得的資金規模與國際相當,所在產業供應鏈的成熟度高,加上特斯拉的供應鏈想像空間,並搭上全球綠能風潮,電動車、電動機車相關產業是台灣有機會發展的產業。  
政策失靈  電動車、電動機車發展陷停滯   然而,目前國內電動車、電動機車產業發展,可說「聊勝於無」,電動機車直到 Gogoro 上市後引起正反兩方熱議,使得競爭者回應,能見度才逐漸提高。如中華車為了回應 Gogoro 的威脅,電動機車車款 EM50 推出電池續航力升級版新車;又因應 Gogoro 進軍家樂福,中華車也積極透過異業結盟加速多元化布局,可說是「有競爭才有進步」。   過去政府輔導電動車產業,被稱為越扶越倒,產業界耳語,抱怨一切政策都以裕隆為優先,但裕隆研發完全失敗後,電動車政策也跟著形同停擺,許多流言直指裕隆是國內發展電動車最大障礙。至今全台電動小客車掛牌數寥寥無幾,經濟部又轉向打算改為輔導電動中大型巴士,訂下 10 年 1 萬輛目標,目前已有許多台廠在全球市場出貨電動巴士,包括中國市場在內,但業者對回流經營台灣市場都表示興趣缺缺,指出政策上綁手綁腳,在國外經營得好好的,何必回國自找麻煩。   台灣車輛密集,若積極發展電動車、電動機車,市場潛力不小,結果產業鏈卻是期待美國的特斯拉來帶動供應鏈成形,可說是相當諷刺。另一方面,因為無法以電動車、電動機車取代汽機車污染源,又制定許多不切實際的政策打壓,尤其是針對機車族,造成許多民怨。  
解決空污問題  應以減少機車排放展開布局   2016 年 1 月 3 日,台北市長柯文哲帶頭對機車宣戰,下達三大狠招,就是要打擊機車沒得商量,包括要強力執行對機車停車格收費、增加自行車道來減少機車道消滅機車行駛空間,另外輔以調降公共運輸費率的「推力與拉力」來吸引機車族放棄機車,政策一出,全台北市機車族嘩然。   柯文哲的政策並非他的創見,事實上,幾十年來,上至中央交通部,一直到各縣市交通局,整個政府的一貫政策就是將機車視為眼中釘,想盡辦法消滅。以台北市而言,前任市長郝龍斌任內,以改造機車彎的名義,實質上大量減少機車停車格,也是消滅機車的一環。為何要消滅機車?其主要的因素之一:機車是重要的都市空氣污染排放源,尤其近年來民眾關切 PM2.5 問題,機車的排放更是遭放大檢視。   消滅機車是整個國家的既定政策,柯文哲只不過是「比較白目」把這個政策公開講出來而已。但是,這些制定政策的官員,卻從未站在民眾的角度思考為何生活中非機車不可,只想著用「推力與拉力」強逼民眾繳出更多的停車費、罰款,壓縮路權,讓民眾「騎不下去」,卻不知民眾是有非騎不可的苦衷,政策無法消滅機車,只是在製造人民的痛苦。   不過,機車污染問題也是貨真價實,以台北市環保局公布的數據,有 58% 的 PM2.5 來自於本地,其中又有 35% 的 PM2.5 來自於汽機車廢氣。在全台灣約 2,000 萬輛汽機車之中,機車佔了約 1,400 萬輛,其中高污染的二行程機車雖然逐年淘汰中,但即使是四行程機車,排放廢氣中 PM2.5 所佔比率也高達 86.5%,廢氣集中在道路上,使得機車騎士本身暴露於 PM2.5 的程度遠高於平均值,以台北市而言,PM2.5 平均值 19.6 μg/m3,但是台北都會區機車族暴露的 PM2.5 平均濃度高達 161.6 μg/m3,許多機車族因此會戴上口罩,但是很不幸的,PM2.5 小到連呼吸道中的纖毛都攔不住,口罩當然也沒有辦法過濾,戴上口罩只是純粹「求心安」。

 
(Source:台北市政府環保局。製圖:科技新報)   但民眾有使用機車的實際需求,如台北市巷弄多,公車不可能鑽進每個小巷,柯文哲市長試圖用腳踏車來填補「最後一哩」,卻忘了不是每個人都與他一樣有著能「一日雙塔」的腳力,此外更有載貨需求,用腳踏車要如何滿足?除非整個交通系統有革命性的改變,譬如小型無人車普及並結合分享服務,在那之前,台灣人就是需要機車,不可能予以打壓消滅。   唯一的辦法,不是消滅機車,而是消滅機車產生的污染,若機車能多數改為電動機車,自然沒有排氣中 PM2.5 對健康的威脅,那麼政府就不需千方百計消滅機車。事實上,包括 Gogoro 在內的各電動機車廠與各級政府相關部門討論電動車、電動機車相關規範事宜時,相關官員曾表示,若電動機車真能普及取代燃油機車,「那就不用打壓機車了」。  
跳脫產業侷限  成為智慧能源試金石   Gogoro 與特斯拉最大的相同點,或許在於對自己的定義都不只是車廠。特斯拉已經逐漸顯示其發展核心為 Gigafactory,也就是定位於以鋰電池為主的能源領域,Gogoro 則自始就強調其願景為「更自主更智慧的個人能源使用方式」。   由於 Gogoro 採用換電站方式運行,現已有 177 座 GoStation 電池交換站,未來更將加速拓展新城市擴充布站據點,期望達成一公里一站的目標。若日後換電站能遍布各處,城市電網與換電站之間又能彼此聯繫智慧調控,將可在供電緊繃時減緩換電站中充飽電池的速度,在電力有餘裕的時候加速充電,以達需求反應調節的效果,更進一步,則可能利用換電站中的電池做為分散式能源儲存資源使用。

 
▲ 目前所有 GoStation 電池交換站(含興建中)的服務範圍(點選查看互動地圖)。   台灣未來積極發展綠能、智慧電網,若已有多家同樣以換電站方式運行的電動車、電動機車民間企業,建立廣布的分散式能源儲存資源,將可望節省可觀的建置時間與預算。發展電動車、電動機車產業,不僅可為供應鏈找出路,減少 PM2.5 污染問題,也能對未來先進智慧能源系統發展有所助益。   然而,台灣的發展狀態可說相當尷尬,目前國內電動機車的銷售主要由 Gogoro 帶動,3 月時 Gogoro 宣布在重點城市市佔率高達 92%,但是即使是 Gogoro,與傳統機車銷售量相比較,也還是小巫見大巫,尚未發揮取代傳統機車的作用。   而政府在各政策之間向來缺乏完整的整體思惟與彼此配套,在針對機車與污染相關政策的時候也一樣,2015 年 12 月,立院通過行政院函請審議的貨物稅條例第 12 條之 5 條文修正草案,其重點是希望以減稅優惠補貼,來促進民眾汰換 6 年以上老舊汽車或 4 年以上老舊機車,只要民眾報廢或出口符合條件的中古汽機車,可在購買新車時享貨物稅減稅優惠,汽車減 5 萬元、機車減 4 千元。   這個方案是因為行政院想以消費刺激經濟,又認為老舊汽機車排氣的空污較嚴重,因此鼓勵舊換新,單獨來看立意尚佳,但考慮到政府也正在希望推動電動車、電動機車,以更徹底的減少交通空污,政府一邊計劃發展電動車、補貼電動機車,卻又一邊補貼汽油車與機車,兩個策略的方向彼此抵消,施政可說毫無整體性可言。   過去政府對於電動車、電動機車的政策只能以「七零八落」形容,對機車則是一味打壓,訴諸「推力與拉力」,很少思考如何給機車族民眾一條替代出路;而新政府即將往綠能、智慧電網的世界潮流發展,產業界則殷殷尋求下一個供應鏈商機,這數個重大需求結合起來,若能形成跨部會政策一同推動,整合法規、政策補貼與稅制彼此配合,同時解決多個需求,將可事半功倍。反之,若還是像過去,政府各單位本位主義各自為政,你打壓你的機車,我把電動車「扶倒」,那麼將同樣一事無成。   特斯拉風風光光,台灣產業界固然羨慕,但我們不應只是對著可能的供應鏈商機流口水,而是該趁此機會,全盤檢討國家政策:當電動車來到「iPhone 時刻」,該如何跟上這股商機,並以此對國家全面性的發展有所助益?新政府與其區分「五大創新產業」,其實跨部會、跨領域、跨產業、跨議題的通盤思考,或許對高效率的施政更有幫助。  
參考資料:

(首圖來源:  CC BY 2.0)

(本文授權轉載自《》─〈〉)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※小三通海運與一般國際貿易有何不同?

※小三通快遞通關作業有哪些?

Tesla年產50萬電動車牛皮吹太大,供應商坦承沒把握

特斯拉(Tesla)計畫在2018年大規模量產平價電動車Model 3,時程較原先計畫提早兩年,雖然展現特斯拉執行長穆斯克(Elon Musk)強大企圖心,但也飽受專家質疑,甚至特斯拉旗下供應商對於是否能達成目標也沒把握。   Model 3已開放預定,特斯拉目前累計收到37.3萬輛的訂單、預計2017年底開始交車。但外界所不知道的是,供應商是在三個月之前才被告知增產計畫提前,相關準備作業是否先完成令人質疑。據路透社引述知情人事消息報導指出,特斯拉最新計畫把2017年Model 3產出規模提高兩倍至10萬輛,2018年更將達成40萬輛的產出水平。   穆斯克4月28日曾在財報法說會上對分析師誇下海口,2018年整體產出規模(含Model S、Model X、Model 3)將來到50萬輛,是去年的十倍,也較預設時程快了兩年。不過Model 3設計目前還要等到6月才定案,距初次量產僅剩13個月。   電動車零組件何其多,且缺一不可,特斯拉如何在短時間內搞定供應商、備齊所有零組件,雖然並非完全不可能,但挑戰難度絕對相當高,這也考驗穆斯克的管理協調能力。值得一提的是,北美目前僅有少數汽車產線有年產50萬輛的能力,且背後都有幾十年經驗的車廠在運籌帷幄。   (本文內容由授權使用;首圖來源: CC BY 2.0)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

※小三通物流營運型態?

※快速運回,大陸空運推薦?

PowerMock學習(三)之Mock局部變量

編寫powermock用例步驟:

  • 類上面先寫這兩個註解@RunWith(PowerMockRunner.class)、@PrepareForTest(StudentService.class)
  • 先模擬一個假對象即studentdao方法中的局部變量
  • 用無參的方式new對象
  • 再模擬這個對象被調用時,是否有返回,有返回值給出默認值,沒有用doNothing()
  • 驗證有返回值使用assertEquals即可,無返回值使用Mockito.verify驗證

實際案例

接着上一篇文章中的代碼,修改下service中的代碼,這次我不通過構造器注入Dao,在方法中new一個StudentDao,創建一個名為StudentNewService的類。

具體示例代碼如下:

package com.rongrong.powermock.service;

import com.rongrong.powermock.dao.StudentDao;

/**
 * @author rongrong
 * @version 1.0
 * @date 2019/11/17 21:13
 */
public class StudentNewService {


    /**
     * 獲取學生個數
     * @return返回學生總數
     */
    public int getTotal() {
        StudentDao studentDao = new StudentDao();
        return studentDao.getTotal();
    }

    /**
     * 創建學生
     * @param student
     */
    public void createStudent(Student student) {
        StudentDao studentDao = new StudentDao();
        studentDao.createStudent(student);
    }
}

針對上面修改部分代碼,進行單元測試,以下代碼有採用傳統方式測試和採用powermock方式進行測試,具體代碼如下:

package com.rongrong.powermock.service;

import com.rongrong.powermock.dao.StudentDao;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

/**
 * @author rongrong
 * @version 1.0
 * @date 2019/11/20 21:42
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest(StudentNewService.class)
public class TestNewStudentService {

    /**
     * 傳統方式測試
     */
    @Test
    public void testGetStudentTotal() {
        StudentNewService studentNewService = new StudentNewService();
        int total = studentNewService.getTotal();
        assertEquals(total, 10);
    }

    /**
     * @desc測試有返回值類型 採用powermock進行測試獲取學生個數
     */
    @Test
    public void testGetStudentTotalWithPowerMock() {
        //先模擬一個假對象即studentdao方法中的局部變量
        StudentDao studentDao = PowerMockito.mock(StudentDao.class);
        try {
            //這句話我按照英文理解就是,我用無參的方式new了一個StudentDao對象
            PowerMockito.whenNew(StudentDao.class).withNoArguments().thenReturn(studentDao);
            //再模擬這個對象被調用時,我們默認假定返回10個證明調用成功
            PowerMockito.when(studentDao.getTotal()).thenReturn(10);
            //這裏就是service就不用再說了
            StudentNewService studentNewService = new StudentNewService();
            int total = studentNewService.getTotal();
            assertEquals(total, 10);
        } catch (Exception e) {
            fail("測試失敗了!!!");
            e.printStackTrace();
        }

    }

    /**
     * @desc測試的無返回值類型 採用powermock進行測試創建學生
     */
    @Test
    public void testCreateStudentWithPowerMock() {
        //先模擬一個假對象即studentdao方法中的局部變量
        StudentDao studentDao = PowerMockito.mock(StudentDao.class);
        try {
            //這句話我按照英文理解就是,我用無參的方式new了一個StudentDao對象
            PowerMockito.whenNew(StudentDao.class).withNoArguments().thenReturn(studentDao);
            Student student = new Student();
            //這句話註釋與否都能運行通過,也就是我只能判斷他是否被調用
            //PowerMockito.doNothing().when(studentDao).createStudent(student);
            //這裏就是service就不用再說了
            StudentNewService studentNewService = new StudentNewService();
            studentNewService.createStudent(student);
            Mockito.verify(studentDao).createStudent(student);
        } catch (Exception e) {
            fail("測試失敗了!!!");
            e.printStackTrace();
        }

    }

}

運行上面的測試用例,會發現第一個失敗,後面兩個都運行成功,即有返回值和無返回值類型的測試(void類型)。

 

 

注意:對於無返回值類型的測試,只能驗證其是否被調用,這裏還請注意。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※小三通海運與一般國際貿易有何不同?

※小三通快遞通關作業有哪些?

併發編程-硬件加持的CAS操作夠快么?

Talk is cheap

CAS(Compare And Swap),即比較並交換。是解決多線程并行情況下使用鎖造成性能損耗的一種機制,CAS操作包含三個操作數——內存位置(V)、預期原值(A)和新值(B)。如果內存位置的值與預期原值相匹配,那麼處理器會自動將該位置值更新為新值。否則,處理器不做任何操作。無論位置V的值是否等於A, 都將返回V原有的值。

CAS的含義是”我認為V的值應該是A,如果是,那我將V的值更新為B,否則不修改並告訴V的值實際是多少“

Show you my code

在單線程環境中分別使用無鎖,加鎖以及cas進行十組5億次累加運算,然後打印出平均耗時。

 /**
 * cas對比加鎖測試
 *
 * @author Jann Lee
 * @date 2019-11-21 0:12
 **/
public class CasTest {

    @Test
    public void test() {
        long times = 500_000_000;
        // 記錄耗時
        List<Long> elapsedTime4NoLock = new ArrayList<>(10);
        List<Long> elapsedTime4Synchronized = new ArrayList<>(10);
        List<Long> elapsedTime4ReentrantLock = new ArrayList<>(10);
        List<Long> elapsedTime4Cas = new ArrayList<>(10);

        // 進行10組試驗
        for (int j = 0; j < 10; j++) {
            // 無鎖
            long startTime = System.currentTimeMillis();
            for (long i = 0; i < times; i++) {
            }
            long endTime = System.currentTimeMillis();
            elapsedTime4NoLock.add(endTime - startTime);

            // synchronized 關鍵字(隱式鎖)
            startTime = endTime;
            for (long i = 0; i < times; ) {
                i = addWithSynchronized(i);
            }
            endTime = System.currentTimeMillis();
            elapsedTime4Synchronized.add(endTime - startTime);

            // ReentrantLock 顯式鎖
            startTime = endTime;
            ReentrantLock lock = new ReentrantLock();
            for (long i = 0; i < times; ) {
                i = addWithReentrantLock(i, lock);
            }
            endTime = System.currentTimeMillis();
            elapsedTime4ReentrantLock.add(endTime - startTime);

            // cas(AtomicLong底層是用cas實現)
            startTime = endTime;
            AtomicLong atomicLong = new AtomicLong();
            while (atomicLong.getAndIncrement() < times) {
            }
            endTime = System.currentTimeMillis();
            elapsedTime4Cas.add(endTime - startTime);
        }

        System.out.println("無鎖計算耗時: " + average(elapsedTime4NoLock) + "ms");
        System.out.println("synchronized計算耗時: " + average(elapsedTime4Synchronized) + "ms");
        System.out.println("ReentrantLock計算耗時: " + average(elapsedTime4ReentrantLock) + "ms");
        System.out.println("cas計算耗時: " + average(elapsedTime4Cas) + "ms");

    }

    /**
     * synchronized加鎖
     */
    private synchronized long addWithSynchronized(long i) {
        i = i + 1;
        return i;
    }

    /**
     * ReentrantLock加鎖
     */
    private long addWithReentrantLock(long i, Lock lock) {
        lock.lock();
        i = i + 1;
        lock.unlock();
        return i;
    }

    /**
     * 計算平均耗時
     */
    private double average(Collection<Long> collection) {
        return collection.stream().mapToLong(i -> i).average().orElse(0);
    }
}

從案例中我們可能看出在單線程環境場景下cas的性能要高於鎖相關的操作。當然,在競爭比較激烈的情況下性能可能會有所下降,因為要不斷的重試和回退或者放棄操作,這也是CAS的一個缺點所在,因為這些重試,回退等操作通常用開發者來實現。

CAS的實現並非是簡單的代碼層面控制的,而是需要硬件的支持,因此在不同的體系架構之間執行的性能差異很大。但是一個很管用的經驗法則是:在大多數處理器上,在無競爭的鎖獲取和釋放的”快速代碼路徑“上的開銷,大約是CAS開銷的兩倍。

為何CAS如此優秀

硬件加持,現代大多數處理器都從硬件層面通過一些列指令實現CompareAndSwap(比較並交換)同步原語,進而使操作系統和JVM可以直接使用這些指令實現鎖和併發的數據結構。我們可以簡單認為,CAS是將比較和交換合成是一個原子操作。

JVM對CAS的支持, 由於Java程序運行在JVM上,所以應對不同的硬件體系架構的處理則需要JVM來實現。在不支持CAS操作的硬件上,jvm將使用自旋鎖來實現。

CAS的ABA問題

cas操作讓我們減少了鎖帶來的性能損耗,同時也給我們帶來了新的麻煩-ABA問題。

在線程A讀取到x的值與執行CAS操作期間,線程B對x執行了兩次修改,x的值從100變成200,然後再從200變回100;而後在線程A執行CAS操作過程中並未發現x發生過變化,成功修改了x的值。由於x的值100 ->200->100,所以稱之為ABA的原因。

魔高一尺道高一丈,解決ABA的問題目前最常用的辦法就是給數據加上“版本號”,每次修改數據時同時改變版本號即可。

Q&A

在競爭比較激烈的情況下,CAS要進行回退,重試等操作才能得到正確的結果,那麼CAS一定比加鎖性能要高嗎?

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※小三通海運與一般國際貿易有何不同?

※小三通快遞通關作業有哪些?

jwt 實踐應用以及特殊案例思考

JSON Web Token 是 出的一份標準,使用 JSON 來傳遞數據,用於判定用戶是否登錄狀態。

jwt 之前,使用 session 來做用戶認證。

以下代碼均使用 javascript 編寫。

  • 原文鏈接:

session

傳統判斷是否登錄的方式是使用 session + token。

token 是指在客戶端使用 token 作為用戶狀態憑證,瀏覽器一般存儲在 localStorage 或者 cookie 中。

session 是指在服務器端使用 redis 或者 sql 類數據庫,存儲 user_id 以及 token 的鍵值對關係,基本工作原理如下。

在服務器端使用 sessions 存儲鍵值對

const sessions = {
  "ABCED1": 10086,
  "CDEFA0": 10010
}

每次客戶端請求帶權限數據時攜帶 token,在服務器端根據 token 與 sessions 獲取 user_id, 完成認證過程

function getUserIdByToken (token) {
  return sessions[token]
}

如果存儲在 cookie 中就是經常聽到的 session + cookie 的登錄方案。其實存儲在 cookie,localStorage 甚至 IndexedDB 或者 WebSQL 各有利弊,核心思想一致。

關於 cookie 以及 token 優缺點,在 中有討論。

如果不使用 cookie,可以採取 localStorage + Authorization 的方式進行認證,更加無狀態化

// http 的頭,每次請求權限接口時,需要攜帶 Authorization Header
const headers = {
  Authorization: `Bearer ${localStorage.get('token')}`
}

推薦一個前端的存儲庫 ,使用 IndexedDB,WebSQL 以及 IndexedDB 做鍵值對存儲。

無狀態登錄

session 需要在數據庫中保持用戶及token對應信息,所以叫 有狀態。

試想一下,如何在數據庫中不保持用戶狀態也可以登錄。

第一種方法: 前端直接傳 user_id 給服務端

缺點也特別特別明顯,容易被用戶篡改成任意 user_id,權限設置形同虛設。不過思路正確,接着往下走。

改進: 對 user_id 進行對稱加密

服務端對 user_id 進行對稱加密后,作為 token 返回客戶端,作為用戶狀態憑證。比上邊略微強點,但由於對稱加密,選擇合適的算法以及密鑰比較重要

改進: 對 user_id 不需要加密,只需要進行簽名,保證不被篡改

這便是 jwt 的思想:user_id,加密算法和簽名組成 token 一起存儲到客戶端,每當客戶端請求接口時攜帶 token,服務器根據 token 解析出加密算法與 user_id 來判斷簽名是否一致。

Json Web Token

jwt 根據 Header,Payload 以及 Signature 三個部分由 . 拼接而成。

Header

Header 由非對稱加密算法和類型組成,如下

const header = {
  // 加密算法
  alg: 'HS256',
  type: 'jwt'
}

Payload

Payload 中由 以及需要通信的數據組成。這些數據字段也叫 Claim。

Registered Claim 中比較重要的是 "exp" Claim 表示過期時間,在用戶登錄時會設置過期時間。

const payload = {
  // 表示 jwt 創建時間
  iat: 1532135735,

  // 表示 jwt 過期時間
  exp: 1532136735,

  // 用戶 id,用以通信
  user_id: 10086
}

Signature

Signature 由 Header,Payload 以及 secretOrPrivateKey 計算而成。secretOrPrivateKey 作為敏感數據存儲在服務器端,可以考慮使用 vault secret 或者 k8s secret

對於 secretOrPrivateKey,如果加密算法採用 HMAC,則為字符串,如果採用 RSA 或者 ECDSA,則為 PrivateKey。

// 由 HMACSHA256 算法進行簽名,secret 不能外泄
const sign = HMACSHA256(base64.encode(header) + '.' + base64.encode(payload), secret)

// jwt 由三部分拼接而成
const jwt = base64.encode(header) + '.' + base64.encode(payload) + '.' + sign

從生成 jwt 規則可知客戶端可以解析出 payload,因此不要在 payload 中攜帶敏感數據,比如用戶密碼

校驗過程

在生成規則中可知,jwt 前兩部分是對 header 以及 payload 的 base64 編碼。

當服務器收到客戶端的 token 后,解析前兩部分得到 header 以及 payload,並使用 header 中的算法與 secretOrPrivateKey 進行簽名,判斷與 jwt 中攜帶的簽名是否一致。

帶個問題,如何判斷 token 過期?

應用

由上可知,jwt 並不對數據進行加密,而是對數據進行簽名,保證不被篡改。除了在登錄中可以用到,在進行郵箱校驗,圖形驗證碼和短信驗證碼時也可以用到。

圖形驗證碼

在登錄時,輸入密碼錯誤次數過多會出現圖形驗證碼。

圖形驗證碼的原理是給客戶端一個圖形,並且在服務器端保存與這個圖片配對的字符串,以前也大都通過 session 來實現。

可以把驗證碼配對的字符串作為 secret,進行無狀態校驗。

const jwt = require('jsonwebtoken')

// 假設驗證碼為字符驗證碼,字符為 ACDE,10分鐘失效
const token = jwt.sign({}, secrect + 'ACDE', { expiresIn: 60 * 10 })

const codeImage = getImageFromString('ACDE')

// 給前端的響應
const res = {
  // 驗證碼圖片的 token,從中可以校驗前端發送的驗證碼
  token,
  // 驗證碼圖片
  codeImage,
}

短信驗證碼與圖形驗證碼同理

郵箱校驗

現在網站在註冊成功後會進行郵箱校驗,具體做法是給郵箱發一個鏈接,用戶點開鏈接校驗成功。

// 把郵箱以及用戶id綁定在一起
const code = jwt.sign({ email, userId }, secret, { expiresIn: 60 * 30 })

// 在此鏈接校驗驗證碼
const link = `https://example.com/code=${code}`

無狀態 VS 有狀態

關於無狀態和有狀態,在其它技術方向也有對比,比如 React 的 stateLess component 以及 stateful component,函數式編程中的副作用可以理解為狀態,http 也是一個無狀態協議,需要靠 header 以及 cookie 攜帶狀態。

在用戶認證這裏,有無狀態是指是否依賴外部數據存儲,如 mysql,redis 等。

案例

思考以下幾個關於登錄的問題如何使用 session 以及 jwt 實現,來更加清楚 jwt 的使用場景

當用戶註銷時,如何使該 token 失效

因為 jwt 無狀態,不保存用戶設備信息,沒法單純使用它完成以上問題,可以再利用數據庫保存一些狀態完成。

  • session: 只需要把 user_id 對應的 token 清掉即可
  • jwt: 使用 redis,維護一張黑名單,用戶註銷時把該 token 加入黑名單,過期時間與 jwt 的過期時間保持一致。

如何允許用戶只能在一個設備登錄,如微信

  • session: 使用 sql 類數據庫,對用戶數據庫表添加 token 字段並加索引,每次登陸重置 token 字段,每次請求需要權限接口時,根據 token 查找 user_id
  • jwt: 假使使用 sql 類數據庫,對用戶數據庫表添加 token 字段(不需要添加索引),每次登陸重置 token 字段,每次請求需要權限接口時,根據 jwt 獲取 user_id,根據 user_id 查用戶表獲取 token 判斷 token 是否一致。另外也可以使用計數器的方法,如下一個問題。

對於這個需求,session 稍微簡單些,畢竟 jwt 也需要依賴數據庫。

如何允許用戶只能在最近五個設備登錄,如諸多播放器

  • session: 使用 sql 類數據庫,創建 token 數據庫表,有 id, token, user_id 三個字段,user 與 token 表為 1:m 關係。每次登錄添加一行記錄。根據 token 獲取 user_id,再根據 user_id 獲取該用戶有多少設備登錄,超過 5 個,則刪除最小 id 一行。
  • jwt: 使用計數器,使用 sql 類數據庫,在用戶表中添加字段 count,默認值為 0,每次登錄 count 字段自增1,每次登錄創建的 jwt 的 Payload 中攜帶數據 current_count 為用戶的 count 值。每次請求權限接口時,根據 jwt 獲取 count 以及 current_count,根據 user_id 查用戶表獲取 count,判斷與 current_count 差值是否小於 5

對於這個需求,jwt 略簡單些,而使用 session 還需要多維護一張 token 表。

如何允許用戶只能在最近五個設備登錄,而且使某一用戶踢掉除現有設備外的其它所有設備,如諸多播放器

  • session: 在上一個問題的基礎上,刪掉該設備以外其它所有的token記錄。
  • jwt: 在上一個問題的基礎上,對 count + 5,並對該設備重新賦值為新的 count。

如何显示該用戶登錄設備列表 / 如何踢掉特定用戶

  • session: 在 token 表中新加列 device
  • jwt: 需要服務器端保持設備列表信息,做法與 session 一樣,使用 jwt 意義不大

總結

從以上問題得知,如果不需要控制登錄設備數量以及設備信息,無狀態的 jwt 是一個不錯的選擇。一旦涉及到了設備信息,就需要對 jwt 添加額外的狀態支持,增加了認證的複雜度,此時選用 session 是一個不錯的選擇。

jwt 不是萬能的,是否採用 jwt,需要根據業務需求來確定。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置,台北網頁設計,各種案例分享

※小三通物流營運型態?

※快速運回,大陸空運推薦?

哈雷五年內推出電動機車

經典重型機車品牌哈雷終於將正式邁向電動車行列?媒體報導,哈雷高級副總裁Sean Cumming在受訪時透漏,哈雷將在五年內推出一款貨真價實的哈雷電動機車。

《癮科技》報導哈雷曾在2014年以Project LiveWire為名推出一款電動機車原型車,行駛續航力只有96公里左右;續航力差強人意的原因是,為了兼顧車體的美觀而無法安裝體積過於龐大的電池。

Sean Cumming在受訪時表示,公司會在五年內推出電動機車,但並未透漏更多細節。由於哈雷機車車體較大,或許就能安裝電容量更大的電池;未來電池的能量密度也會更高,續航力問題也許能獲得解決。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

※小三通海運與一般國際貿易有何不同?

※小三通快遞通關作業有哪些?