北美車市回溫 F-英瑞 1 月營收創上市以來新高

北美 AM 市場汽車水箱龍頭 F-英瑞在北美車市持續回溫下,1 月營收為 4.7 億元,年增 16.41%,月增 29.11%,創上市來營收新高。公司今年將衝刺電動車空調系統,營運添翼,法人估計今年英瑞營收 2 位數成長。   F-英瑞指出,2014 年公司積極布局新產品,包括電動車空調系統、車用及重型機械用水箱 OEM 市場等,這些布局將在今年開始逐漸發酵,加上近年北美汽車市場回溫,有利 AM 市場成長,看好今年業績表現,目前正積極擘劃柬埔寨新廠,供應 2016 年後市場需求。   F-英瑞進一步表示,今年最大成長力道將來自於中國市場,其中在新產品部分,包括車用水箱、重型水箱及電動車空調系統等已經通過多家車廠認證,今年中國 OEM 營收可望較去年倍數成長。

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

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

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

深入淺出騰訊BERT推理模型–TurboTransformers

Overview

TurboTransformers是騰訊最近開源的BERT推理模型,它的特點就是一個字,快。本人用BERT(huggingface/transformers)在V100上做了測試,測試結果和官宣的基本一致:TurboTransformers的推理速度要比Pytorch快上1~4倍。

它之所以快,是因為它是專用於BERT的輕量級推理模型。

分層

不管是計算機的硬件、軟件,還是現在的深度學習,它們都遵循着一個很重要的設計思想–分層:

  • 用簡單的代碼(或電路)來實現一個基本功能組件。
  • 用幾個基本組件組合成一個功能更強的複雜組件。
  • 從簡單到複雜,像搭積木一樣,一層層地搭建出擁有很強功能的組件。

開發者只需要基於PyTorch的幾個基本組件就能搭建出BERT模型,而且這些組件本身對他們來說都是透明的。正因如此,PyTorch才越來越受到研究者青睞。

分層設計的優點很多,例如,可以簡化問題、降低創新門檻、加速開發等,但它的缺點也很明顯:

  • 流程固定化
  • 存在中間層延遲

深度神經網絡里有個經典套路:一個激活函數層後面緊跟着一個dropout層。PyTorch需要lanuch兩個GPU kernel程序來完成這兩步計算。

F.dropout(F.relu(x))

實際上,這兩項計算都是element-wise的,是可以合併成一個kernel的。但目前來說,不管是PyTorch,還是其他的通用訓練框架,它們都很少有提供這種融合計算的API。

至於中間層延遲,最經典的要屬“hello world”程序。雖然只有幾行代碼,但實際上要經過的中間層數根本數不過來。

你可以閱讀深入淺出PyTorch(算子篇)來了解下矩陣相乘這個最基本的計算在PyTorch里要經過多少个中間層。

分層展開

要想將程序的低延遲最大化,就需要把分層的代碼完全展開,並重構代碼。典型例子就是嵌入式系統,為了實現某種需求,它可以打破應用程序、程序庫、操作系統甚至是硬件設備的界限,打造一個軟硬件一體化產品。

這種分層展開的設計模式當然也有它的局限性:專用。由於高度定製化,它通常只能用於完成某個特定功能。低延遲和專用化是呈絕對的正相關的。

TurboTransformers就是採用這種設計:只實現BERT模型前向傳播所需要的算子,並融合那些可以合併的算子。

turbo.Tensor

首先,它用CUDA開發了一個輕量級的tensor計算庫,所謂的輕量級,指的是不用考慮反向傳播、稀疏矩陣等操作,只實現BERT前向傳播所必需的operator。

雖然tensor庫是用C++寫的,但考慮到python在AI開發中的地位,它用pybind11將C++ API暴露給前端的python Tensor類。

# turbo_transformers/python/pybind.cpp
 72   py::class_<core::Tensor>(m, "Tensor")                      
 73       .def_static("from_dlpack",
 74                   [](py::capsule capsule) -> std::unique_ptr<core::Tensor> {
 75                     auto tensor = (DLManagedTensor *)(capsule);
 76                     PyCapsule_SetName(capsule.ptr(), "used_tensor");
 77                     return absl::make_unique<core::Tensor>(tensor);
 78                   })
 79       .def("to_dlpack",
 80            [](core::Tensor &tensor) -> py::capsule {
 81              auto *dlpack = tensor.ToDLPack();                    
 82              return py::capsule(dlpack, "dltensor", DLPack_Capsule_Destructor);
 83            })
 84       .def("n_dim", &core::Tensor::n_dim)
 85       .def("shape", &core::Tensor::shape)

從預訓練模型(PyTorch)那遷移參數時,turbo.Tensor不能直接對接torch.Tensor,需要先將PyTorch的參數轉成dlpack格式, 再通過from_dlpack()將這些數據導入生成TurboTransformers tensor。除了dlpack之外,還支持*.npz文件格式。

turbo.xxxlayer

TurboTransformers用CUDA重構了Embedding、self-attention、intermediate、output、LayerNorm和pooler等layer。turbo.layer不僅代碼結構簡潔,overhead少,還合併了一部分算子。

這裏以intermediate layer為例,來分析這些算子的特點。

intermediate layer的實現比較簡單:一個Linear layer後面緊跟着一個gelu activation layer。

PyTorch的intermediate layer的會lanuch 3個kernel來完成這部分計算:

  • #1: y = input.matmul(weight)
  • #2: y = y + bias
  • #3: y = gelu(y)

由於#2和#3都是element-wise kernel,turbo把它們進行了融合–AddBiasAct(),相同的計算操作,只需要lanuch 2個kernel,計算速度當然更快。

和PyTorch一樣,turbo的MatMul算子也是調用cuBLAS來進行矩陣運算,而且turbo還啟用了Tensor Core來加速計算(CUBLAS_TENSOR_OP_MATH)。

總結

到此,本文基本上講清了TurboTransformers的速度優勢來源,由於篇幅所限,不能分析所有的算子。BERT的核心模塊是self-attention,如果想了解更多,可以閱讀深入淺出Transformer。

更多精彩文章,歡迎掃碼關注下方的公眾號 ~~ 歡迎關注和點贊,你的鼓勵將是我創作的動力

歡迎轉發至朋友圈,公眾號轉載請後台留言申請授權~

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

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

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

中國南海區域海嘯預警中心正式運作 預警時效達國際水準

摘錄自2019年11月6日香港01報導

據報,由中國國家海洋局承建的南中國海區域海嘯預警中心(South China Sea Tsunami Advisory Center,SCSTAC)昨(5)日起開始正式投入運作。

該中心的國際預警服務區域,包括南海、蘇祿海(Sulu Sea)和蘇拉威西海(Laut Sulawesi),覆蓋上述區域的主要地震俯衝帶,為南中國海周邊的中國、汶萊、柬埔寨、印尼、馬來西亞、菲律賓、新加坡、泰國和越南,以及香港與澳門提供全天候的地震海嘯監測預警服務。

預警中心使用由中國研發的新一代智慧化海嘯監測預警資訊處理平臺,海嘯預警時效由2015年的20至30分鐘縮短至8至10分鐘,達到國際先進水準。

而由日本承建的西北太平洋海嘯預警中心,目前已不再向南海區域提供臨時的海嘯預警服務。

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

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

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

工信部大力支持充電設施建設 中國最大充電設備展8月舉行

今年全國兩會期間,工信部部長苗圩表示,工信部將從今年開始,逐漸加大對各試點城市的充電基礎設施的建設支持力度,也希望各試點城市政府能夠出臺相應措施,使選擇新能源汽車客戶能夠“買得到車、充得上電”。

為宣傳健康出行理念,促進行業交流,推進我國充電設施建設,振威展覽集團聯合廣東省電源行業協會共同打造的中國最大充電設備展——第三屆上海國際充電站(樁)技術設備展覽會(EVSE2015)將於2015年8月26至28日在上海新國際博覽中心舉行。展會將吸引充電設施領域的200多家企業參展,集中展示我國充電設施領域的最新產品和技術,包括充電樁、充電機、充電櫃等充電設備,配電設備,濾波設備,充電站監控系統,分散式微電網,充電站智慧型網路專案規劃成果,儲能系統,動力電池及電池管理系統等。組委會介紹,展會官網免費參觀登記平臺已開通,需要參觀的企業單位和個人均可線上登記,享受現場綠色通道服務。

各地政府積極組團參加

發展新能源汽車產業將有力帶動地方產業升級,創造就業崗位,提高財政收入,所以很多地方已把新能源汽車產業列入戰略性新興產業。地方政府也樂於積極參加各地展會,宣傳推廣當地招商環境和政策,吸引投資。

作為國內充電設施領域最大的展會,現已經發展成為集政府、園區與企業形象展示,裝備展示與採購,技術研討,新品發佈,產業對接,金融投資,貿易洽談為主的大型交流平臺。今年,組委會加強了與各地政府部門的合作,包括上海市、合肥市、武漢市、成都市、南昌市、宜春市、莆田市、昆明市等,屆時上述政府部門將組織相關企業和園區參與展覽展示和招商推介,相關部門領導也將作為特邀嘉賓出席展會相關活動。

充電設備巨頭實力大比拼

據專家預計,今年我國充電設施市場規模將達到200億元,2016年400億元,到2020年將突破1000億元。隨著充電設施建設的加快,充電設備企業的競爭也越來越激烈,珠海泰坦、國電南瑞、科陸電子、動力源、特銳德、許繼電氣等國內巨頭紛紛加大力度開拓充電設施市場,並借助展會平臺加快對市場的宣傳和滲透。

在我國新能源汽車推廣及充電設施建設的浪潮中,華東地區已成為國內最大的市場,其市場容量一度占到全國的60%以上。華東地區已成為國內充電設備巨頭的主戰場,誰率先佔領華東市場誰就在未來的競爭中佔據了主動權。據悉,作為我國新能源領域的龍頭企業的珠海泰坦科技股份有限公司將攜系列充電樁、充電機、電源模組及充電系統解決方案,以54平米盛裝亮相EVSE2015,謀劃佈局華東市場。

此外,上海富電科技、蘇州舜唐新能源、深圳日億升、成都富川電子、上海埃士工業、北京基業達、億源動力、伊賽電子、北京維利通電氣等充電設備知名企業也將盛裝亮相本屆展會。EVSE作為我國最大的充電設備展,必將深刻影響我國充電設備市場格局,並推動我國充電設施建設健康、穩定、持續發展!
 

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

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

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

奧迪新電動跑車2018年推出:續航超500公里

根據外媒資訊,奧迪將開發多款純電動車和插電式混合動力車。電池動力的跨界車將以新一代發動機縱置模組化平臺MLB 2為基礎。首款基於MLB 2平臺衍生的產品是第二代奧迪Q7,該車將在今年下半年上市。   奧迪技術研發負責人烏爾裡奇•哈肯伯格(Ulrich Hackenberg)在日前奧迪年度大會上告訴媒體:「2018年上半年,我們將推出一款電池動力的運動型跑車,針對大型豪華車細分市場,續航里程超過500公里。該車將擁有全新、極具吸引力的外觀設計,這是我們特地為e-tron系列電動車和純電動車打造的設計。」   而去年,哈肯伯格曾表示,奧迪將推出續航里程280英里(約合45萬公尺)的純電動家用車型,車輛將擁有容納一個家庭的寬敞內部空間,於2017年前後發佈,將和特斯拉Model S電動車爭奪市場;預計將採用轎車風格車身,同時具備寬敞的內部空間,適合家用。   為了達到續航里程目標,新電動車車將採用奧迪最新一代電動馬達和電池,具有較高的能量密度。大眾汽車集團動力總成研發負責人Heinz-Jakob Neußer表示,新馬達較當前用於e-Golf電動車的型號效率高出5倍。 

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

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

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

印度空污如毒氣室 準媽媽護嬰避免外出

摘錄自2019年11月08日中央通訊社印度報導

挺著大肚子的戈卡維(Rachel Gokavi)把自己關在新德里家中,拚命保護即將出生的嬰孩免於有毒空氣危害——印度流產率和嬰孩死亡率飆高,被歸咎於有毒空氣。

在最近新德里一場產前課程,戈卡維和其他懷孕母親分享她們的無助和憤怒,因為每天必須呼吸有毒空氣。26歲的戈卡維告訴法新社:「我總是關閉陽台的門,並且盡量不要外出。我害怕在孩子誕生時會有呼吸問題。」由於空氣如此差,新德里市長最近把首都比擬為「毒氣室」。

在可預見的未來,空氣污染仍然看不到緩解。面對這個情況,醫生也別無選擇,只能建議例如戴口罩或者使用大多數人都買不起的家用空氣清淨機。

根據世界衛生組織統計,全球污染最嚴重的15個城市,有14個在印度境內。每年冬天農民焚燒作物殘梗產生的煙霧,加上工業及車輛排放的廢氣,讓印度北部各地城鎮變成煙霧籠罩的可怕地獄。

根據6月出版的政府研究報告,這種有毒混合物每年縮短100萬名印度人的壽命。報告也表示,空氣污染每年造成超過10萬名5歲以下小孩死亡。

醫生說,兒童呼吸有毒空氣的速度是大人的兩倍,因為兒童的肺比較小,這會造成小孩呼吸系統問題,甚至傷害腦部發育。聯合國兒童基金會(UNICEF)本週指出,證據顯示,青少年暴露在較嚴重空氣污染中,更容易出現心理健康問題。

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

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

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

特斯拉第 1 季交車破萬輛 年增 55%

美國電動車大廠特斯拉(Tesla Motors)今年第 1 季交車量突破 1 萬台,較去年同期暴增 55%,創下新高,今年全年銷量可望超越去年,但欲達成執行長穆斯克(Elon Musk)所設的今年交車 5.5 萬輛目標,恐怕還得加把勁。   特斯拉今年首季 Model S 交車量 10,030 台,比該公司初估的還高出 500 台,年增 55%。由此數據看來,今年 Model S 銷量很有希望大幅超越去年的 31,655 輛。   創辦人兼執行長穆斯克立下今年 5.5 萬台、2020 年前 50 萬台的交車目標,若能達成的話,特斯拉將在割喉競爭的汽車市場占有一席之地。

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

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

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

恕我直言你可能真的不會java第7篇:像使用SQL一樣排序集合

在開始之前,我先賣個關子提一個問題:我們現在有一個Employee員工類。

@Data
@AllArgsConstructor
public class Employee {

   private Integer id;
   private Integer age;   //年齡
   private String gender;  //性別
   private String firstName;  
   private String lastName;
}

你知道怎麼對一個Employee對象組成的List集合,先按照性別字段倒序排序,再按照年齡的倒序進行排序么?如果您不知道4行代碼以內的解決方案(其實是1行代碼就可以實現,但筆者格式化為4行),我覺得您有必要一步步的看下去。

一、字符串List排序

cities是一個字符串數組。注意london的首字母是小寫的。

List<String> cities = Arrays.asList(
        "Milan",
        "london",
        "San Francisco",
        "Tokyo",
        "New Delhi"
);
System.out.println(cities);
//[Milan, london, San Francisco, Tokyo, New Delhi]

cities.sort(String.CASE_INSENSITIVE_ORDER);
System.out.println(cities);
//[london, Milan, New Delhi, San Francisco, Tokyo]

cities.sort(Comparator.naturalOrder());
System.out.println(cities);
//[Milan, New Delhi, San Francisco, Tokyo, london]
  • 當使用sort方法,按照String.CASE_INSENSITIVE_ORDER(字母大小寫不敏感)的規則排序,結果是:[london, Milan, New Delhi, San Francisco, Tokyo]
  • 如果使用Comparator.naturalOrder()字母自然順序排序,結果是:[Milan, New Delhi, San Francisco, Tokyo, london]

同樣我們可以把排序器Comparator用在Stream管道流中。

cities.stream().sorted(Comparator.naturalOrder()).forEach(System.out::println);

//Milan
//New Delhi
//San Francisco
//Tokyo
//london

在java 7我們是使用Collections.sort()接受一個數組參數,對數組進行排序。在java 8之後可以直接調用集合類的sort()方法進行排序。sort()方法的參數是一個比較器Comparator接口的實現類,Comparator接口的我們下一節再給大家介紹一下。

二、整數類型List排序

List<Integer> numbers = Arrays.asList(6, 2, 1, 4, 9);
System.out.println(numbers); //[6, 2, 1, 4, 9]

numbers.sort(Comparator.naturalOrder());  //自然排序
System.out.println(numbers); //[1, 2, 4, 6, 9]

numbers.sort(Comparator.reverseOrder()); //倒序排序
System.out.println(numbers);  //[9, 6, 4, 2, 1]

三、按對象字段對List<Object>排序

這個功能就比較有意思了,舉個例子大家理解一下。

Employee e1 = new Employee(1,23,"M","Rick","Beethovan");
Employee e2 = new Employee(2,13,"F","Martina","Hengis");
Employee e3 = new Employee(3,43,"M","Ricky","Martin");
Employee e4 = new Employee(4,26,"M","Jon","Lowman");
Employee e5 = new Employee(5,19,"F","Cristine","Maria");
Employee e6 = new Employee(6,15,"M","David","Feezor");
Employee e7 = new Employee(7,68,"F","Melissa","Roy");
Employee e8 = new Employee(8,79,"M","Alex","Gussin");
Employee e9 = new Employee(9,15,"F","Neetu","Singh");
Employee e10 = new Employee(10,45,"M","Naveen","Jain");


List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);

employees.sort(Comparator.comparing(Employee::getAge));
employees.forEach(System.out::println);
  • 首先,我們創建了10個Employee對象,然後將它們轉換為List
  • 然後重點的的代碼:使用了函數應用Employee::getAge作為對象的排序字段,即使用員工的年齡作為排序字段
  • 然後調用List的forEach方法將List排序結果打印出來,如下(當然我們重寫了Employee的toString方法,不然打印結果沒有意義):
Employee(id=2, age=13, gender=F, firstName=Martina, lastName=Hengis)
Employee(id=6, age=15, gender=M, firstName=David, lastName=Feezor)
Employee(id=9, age=15, gender=F, firstName=Neetu, lastName=Singh)
Employee(id=5, age=19, gender=F, firstName=Cristine, lastName=Maria)
Employee(id=1, age=23, gender=M, firstName=Rick, lastName=Beethovan)
Employee(id=4, age=26, gender=M, firstName=Jon, lastName=Lowman)
Employee(id=3, age=43, gender=M, firstName=Ricky, lastName=Martin)
Employee(id=10, age=45, gender=M, firstName=Naveen, lastName=Jain)
Employee(id=7, age=68, gender=F, firstName=Melissa, lastName=Roy)
Employee(id=8, age=79, gender=M, firstName=Alex, lastName=Gussin)
  • 如果我們希望List按照年齡age的倒序排序,就使用reversed()方法。如:
employees.sort(Comparator.comparing(Employee::getAge).reversed());

四、Comparator鏈對List<Object>排序

下面這段代碼先是按性別的倒序排序,再按照年齡的倒序排序。

employees.sort(
        Comparator.comparing(Employee::getGender)
        .thenComparing(Employee::getAge)
        .reversed()
);
employees.forEach(System.out::println);

//都是正序 ,不加reversed
//都是倒序,最後面加一個reserved
//先是倒序(加reserved),然後正序
//先是正序(加reserved),然後倒序(加reserved)

細心的朋友可能注意到:我們只用了一個reversed()倒序方法,這個和SQL的表述方式不太一樣。這個問題不太好用語言描述,建議大家去看一下本文對應的視頻!

排序結果如下:

Employee(id=8, age=79, gender=M, firstName=Alex, lastName=Gussin)
Employee(id=10, age=45, gender=M, firstName=Naveen, lastName=Jain)
Employee(id=3, age=43, gender=M, firstName=Ricky, lastName=Martin)
Employee(id=4, age=26, gender=M, firstName=Jon, lastName=Lowman)
Employee(id=1, age=23, gender=M, firstName=Rick, lastName=Beethovan)
Employee(id=6, age=15, gender=M, firstName=David, lastName=Feezor)
Employee(id=7, age=68, gender=F, firstName=Melissa, lastName=Roy)
Employee(id=5, age=19, gender=F, firstName=Cristine, lastName=Maria)
Employee(id=9, age=15, gender=F, firstName=Neetu, lastName=Singh)
Employee(id=2, age=13, gender=F, firstName=Martina, lastName=Hengis)

歡迎關注我的博客,裏面有很多精品合集

  • 本文轉載註明出處(必須帶連接,不能只轉文字):字母哥博客。

覺得對您有幫助的話,幫我點贊、分享!您的支持是我不竭的創作動力! 。另外,筆者最近一段時間輸出了如下的精品內容,期待您的關注。

  • 《手摸手教你學Spring Boot2.0》
  • 《Spring Security-JWT-OAuth2一本通》
  • 《實戰前後端分離RBAC權限管理系統》
  • 《實戰SpringCloud微服務從青銅到王者》
  • 《VUE深入淺出系列》

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

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

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

阿拉斯加「平紀錄高溫+破紀錄大雪」出現同一天!

摘錄自2019年11月18日ETtoday綜合報導

今年入秋以來,美國阿拉斯加州氣候異常溫暖,當地最大城市安克拉治居民,近日竟在同一天內,先後經歷了創紀錄高溫與破紀錄降雪兩種截然不同的極端天氣型態!

位於安克拉治國際機場南側的美國國家氣象局(NWS)安克拉治辦公室,當天觀測到超過8.3英吋積雪,打破當地1958年以來的降雪新紀錄。奇怪的是,安克拉治市當天不止出現破紀錄降雪,同一天凌晨3時,當地還出現華氏45度(攝氏7.2度)氣溫,與1967創下的的同日最高溫紀錄持平。

NWS預報員德魯茲(Eric Drewitz)解釋,16日凌晨,一股東南風從海上吹來,為城市帶來溫暖空氣,雖著風勢減弱,氣溫也隨之下滑,並且降下硬幣大小的雪花。報導提到,阿拉斯加州今年秋天以來異常溫暖,10月下旬也曾出現破紀錄高溫,溫暖天氣一直延續到11月。在16日降下大雪以前,當地今年入冬第一場,也是唯一一場降雪出現在10月16日,但降雪量僅5分之1英吋(約0.5公分)。

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

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

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

因為我的一個低級錯誤,生產數據庫崩潰了將近半個小時

前言

halo,相信大家一定過了一個很開心的端午節吧,我看朋友圈裡各種曬旅遊,曬美食的,真是羡慕啊,不像我,感冒了只能在家擼文章。
當然,玩的多開心,節後上班就有多鬱悶,假日綜合征可不是說說而已。對此我想表達的是,沒事,不用鬱悶,來看我如何自爆家醜來讓你們開心下。

反常的sql語句

上周四午休時分,我正在工位上小憩,睡夢中彷彿看到了自己拿着李白在榮耀峽谷里大殺四方的情景,就在我剛拿完五殺準備帶領隊友推對面水晶的時候,一句慌亂急促的“糟了”把我從睡夢中驚醒。我眯開朦朧的雙眼,才發現剛才的發聲來源於我的組長庄哥,看到他在緊張的點開日誌系統查看日誌,我預感到有什麼不妙的事情發生,仔細一問才知道,原來就在我眯眼的期間,線上數據庫服務器的CPU被打滿,同時觸發了生產數據庫只讀延遲的限定時間並且發出告警,而且告警的過程持續了半個小時。

這讓我倒吸了一口涼氣,因為我們組做的系統很多都用的是同一個數據庫服務器,日用戶活躍量有好幾十萬,如果服務器崩潰了將會使所有的系統服務都不可用,於是我們趕緊通過sql日誌進行問題查找,最後排查出來是因為一張sql的高量查詢沒有走索引導致,日誌列表显示,這條sql語句的掃描行數達到了上百萬,基本就是全表掃描的情況,而且半個小時的時間查詢了達上萬次,每條sql查詢的耗時都在3000ms以上。我的天啊,難怪服務器會CPU打滿,這麼一條耗時的sql語句查詢量這麼大,數據庫的資源當然是直接就崩潰了,這是當時那條sql的查詢情況:

臨時處理

看了這條語句,我又倒吸一口涼氣,這不就是我寫的系統調用的sql語句嗎?完了,這回逃不掉了,真是人在睡夢裡,鍋從天上來。

當然,因為是我自己寫的sql,所以我一看就知道這條語句是有問題的。

根據我的代碼處理,這條sql的調用還少了個重要的參數user_fruit_id,這個參數沒有傳的話是不應該走這條sql查詢的,在我的設計里,該參數是數據表裡一個聯合索引的最左側字段,如果該字段沒有傳值的話,那麼索引就不會生效了。

KEY `idx_userfruitid_type` (`user_fruit_id`,`task_type`,`receive_start_time`,`receive_end_time`) USING BTREE

雖然定位到了sql語句,但是線上的問題刻不容緩,總不可能找出bug改完再上線吧,所以,我們只能做了一個臨時處理,就是在原來的表上多加了一個聯合索引,其實就是去掉了user_fruit_id 字段,讓這些高量的查詢都能走新的索引,就像下面這樣

KEY `idx_task_type_receive_start_time` (`task_type`,`receive_start_time`,`receive_end_time`,`created_time`) USING BTREE

加上索引后,sql的掃描行數就大幅度的降低了,重啟實例后就又能正常運行了。

最左匹配原則

那麼為什麼最左側的字段沒傳索引就不生效了,這是因為MySQL的聯合索引是基於“最左匹配原則”匹配的。

我們都知道,索引的底層是B+樹結構,聯合索引的結構也是B+樹,只不過鍵值數量不是一個,而是多個,構建一顆B+樹只能根據一個值來構建,因此數據庫依據聯合索引最左的字段來構建B+樹。

例如我們用兩個字段(name,age)這個聯合索引來分析,

圖片來源於林曉斌老師的《MySQL實戰45講》課程,

當我們在where條件中查找name為“張三”的所有記錄的時候,可以快速定位到ID4,並且查出所有包含“張三”的記錄,而如果要查找“張三,10”這一條特定的數據,就可以用 name = “張三” and age = 10 獲取,因為聯合索引的鍵值對是兩個,所以只要前面的name確定的情況下就可以進一步定位到具體的age記錄,但是如果你的查詢條件只有age的話,那麼索引就不會生效,因為沒有匹配最左邊的字段,後面所有的索引字段都不會生效,所以我之前寫的sql語句才會因為少了最左邊的user_fruit_id字段而走了全表掃描的查詢方式。

正常來說,假設一個聯合索引設計成(a,b)這樣的結構的話,那麼用a and b作為條件,或者a單獨作為查詢條件都會走索引,這種情況下我們就不要再為a字段單獨設計索引了。

但如果查詢條件裏面只有b的語句,是無法使用(a,b)這個聯合索引的,這時候你不得不維護另外一個索引,也就是說你需要同時維護(a,b)、(b) 這兩個索引。

找出Bug

雖然臨時做了處理,但問題並不算解決,很明顯是系統出現了bug才會有走這樣的查詢條件。因為是我自己寫的代碼,所以知道是哪條sql后我就馬上定位到了代碼里的具體方法,後來才發現是因為我對user_fruit_id字段的判空處理不生效所致。

因為該字段是從調用方傳過來的,所以我在方法參數里對該字段做了非空限制的註解,也就是javax包下的@NotNull,

public class GardenUserTaskListReq implements Serializable {

    private static final long serialVersionUID = -9161295541482297498L;

    @ApiModelProperty(notes = "水果id")
    @NotNull(message = "水果id不能為空")
    private Long userFruitId;
    /**以下省略*/
    .....................
}

雖然加上該註解來做非空校驗,但我卻沒有在參數加上另一個註解@Validated,該註解如果沒加上的話,那麼調用javax包下的校驗規則就都不生效,正確的寫法是在controller層方法的參數前面加上註解,

除此之外,因為user_fruit_id這個字段是另一張表的主鍵,我在代碼里也沒有對這張表是否存在這個id做查詢判斷,這樣一來,無論調用方傳什麼值過來都會直接觸發sql查詢,並且在不跑索引的情況下直接走全表掃描。

不得不說,這真是個低級錯誤,說真的,我對這個原因真是感到嘀笑皆非,再怎麼說也工作幾年了,怎麼還犯一些新手級別的錯誤呢,這臉打得真是讓我相當慚愧。

總結

雖然是低級錯誤,但造成的後果也算挺嚴重了,這次事件也讓我更加的警醒,在以後的開發工作中必須要遵守該有的原則,大概有這麼幾點:

1、不能相信調用端。重要的參數都要先做驗證,即使是非空值也需要做驗證,不符合條件的就要直接返回或拋異常,不能參与業務sql的查詢,否則頻繁的訪問也會對服務造成負擔。

2、sql語句要先做性能查詢。對於數據量大的表,建好索引后,所有的sql查詢語句要用explain檢測性能,並且根據結果來進一步優化索引。

3、代碼必須要review。之前我沒有放太大的精力在代碼的review上,雖說跟迭代排期的緊湊也有關係,但不管怎麼說,bug確實是我的疏忽造成的,尤其是像空值這種細小的錯誤在Java里可以說家常便飯。千里之堤毀於蟻穴,有時一個小bug很容易就引發整個系統的崩盤,這一次的問題也讓我更加深刻的認識到了review代碼的重要性,不管業務開發的工作量有多麻煩,這一步操作絕對不能忽視。

後續

知道了bug的原因,改完代碼當天就重新發布了,後來,庄哥告訴我說,為了以後讓組裡的其他人對此次問題有所警戒,讓我寫一篇問題記錄總結一下,我想了一下,這不是我的強項啊,但怎麼說也確實是自己的問題,還是老老實實的寫一下記錄好了。我本以為這樣就可以松一口氣了,可平哥 (組裡的一位大佬) 卻突然用詭異的眼神看着我,語重心長的說,上次xxx也因為線上出現問題寫了報告,你這一次估計也不能例外了,可能要一萬字以上。我瞬間就感覺一個雷劈到了我頭上,蒼天啊。。。。。。

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

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

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!