聯合國報告:疫情恐加深東南亞地區不平等

摘錄自2020年7月30日中央社報導

聯合國今天(30日)發布COVID-19對東南亞的影響報告(Policy Brief: The Impact of COVID-19 on South-East Asia)指出,武漢肺炎疫情加深東南亞的不平等現象,東南亞國家的政府應該把重點放在疫情對社會經濟的影響。疫情對政治、經濟和健康的影響,重擊社會底層人民,使他們失業且更加貧窮。

報告指出,東南亞要從疫情中復甦有四個關鍵領域,包括打擊不平等、消弭數位落差、綠化經濟並保持人權和良好的治理。

報告也進一步強調,在面對疫情時,東南亞國家以及他們的領導人在保障人權以及良好治理上具有重要的角色。領導人們應該多利用以社區為中心的組織、促進包容及團結,並挺身而出反對歧視。

土地利用
國際新聞
東南亞國家
疫情下的社會衝突
貧窮

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

【其他文章推薦】

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

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

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

※產品缺大量曝光嗎?你需要的是一流包裝設計!

垃圾也「三倍」? 研究:各國減塑政策來不及 2040年入海塑膠垃圾將增三倍

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

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

【其他文章推薦】

※教你寫出一流的銷售文案?

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

※回頭車貨運收費標準

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

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

蝴蝶效應!中日韓梅雨季重災情 歸因於北極異常高溫

摘錄自2020年8月4日自由時報報導

中日韓3國今年受梅雨季暴雨影響,接連發生重大災情,南韓媒體引述專家說法稱,今年梅雨季的強降雨災情與全球暖化下的北極異常高溫有關。

根據《韓聯社》報導,今年梅雨季比起往年為長,中國華中地區、長江流域爆發劇烈洪災,日本九州暴雨重災,南韓強降雨亦造成死亡災情,其根本原因就是全球持續暖化。

《韓聯社》引述專家所言指出,在全球暖化下,北極氣溫大幅升高導致積雪及冰層融化,暴露出的黃褐色地表加劇從陽光吸取熱能,讓當地空氣溫度飆升。在暖空氣影響下,原本從東向西流動的冷空氣轉而朝南北方向作用,進而移動至中日韓等國。

南韓氣象廳則認為,今年梅雨季偏長因素雖不能僅歸因在全球暖化,但確實是氣候變化造成。

氣候變遷
土地利用
國際新聞
中國
日本
韓國
北極
極端高溫
全球暖化
災害

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

【其他文章推薦】

※超省錢租車方案

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

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

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

垃圾危害海洋 日生研發魚不愛吃塑膠袋

摘錄自2020年8月3日公視報導

有一群日本高中生研發出可以自動分解,而且魚類不小心吃下去,也會吐掉的塑膠袋;預計再過一兩年,就能夠上市使用。

神奈川縣川崎市的「洗足學園高中」,有學生團體突發奇想,決定研發能在大自然中自行分解,卻又不會被魚類跟海龜吞食的塑膠袋,於是用「苯甲地那銨」進行實驗。

在大學跟贊助企業的協助下,學生團隊實驗製作出含有2%到20%「苯甲地那銨」的可自動分解塑膠袋。實驗後發現,只要有「苯甲地那銨」4%含量,就會讓魚類在吃進塑膠時,因為苦味而吐出。

目前這款塑膠袋,以能在海洋分解的材質製造,只要進入海洋,到完全自然分解,只需要1到2年時間。目前學生團隊,還在研究新成分,期盼降低製造費用,以便廣為商家使用。另外也將持續改善,塑膠袋完全分解前,苦味可能已經消失的缺點,進行修正。

海洋
污染治理
國際新聞
日本
海洋垃圾
海洋生物
廢棄物

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

【其他文章推薦】

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

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

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※教你寫出一流的銷售文案?

澳洲史上最慘野火 30億動物死亡、流離失所

摘錄自2020年8月3日公視報導

世界自然基金會最新的研究指出,有將近30億隻澳洲動物在先前的森林大火中喪命或是逃離家園,是原先估計的三倍。而為了拯救無尾熊,保育人員利用「紅外線無人機」,來進行追蹤。

不只是棲息地遭到破壞,無尾熊還得面臨汽車路殺、野狗攻擊、披衣菌感染等疾病,還有氣候變遷的威脅。國際自然保育聯盟IUCN已將無尾熊列入「易危物種」,澳洲6月一份國會調查報告指出,生長在澳洲東岸的無尾熊,恐怕到了2050年就會滅絕,而2019-2020年發生的澳洲野火加速了它的進程。

世界自然基金會WWF也認同,利用紅外線無人機追蹤無尾熊是一大突破。之後隨著技術提升、成本下降,將漸漸可以不分晝夜追蹤出無尾熊的蹤跡。

WWF委託澳洲數間大學的科學家研究,7月28日發佈的報告指出,2019到2020年的野火,不但是現代史上最慘烈的野火災難之一,更導致近30億隻動物死亡或是流離失所,是先前預估的三倍。其中包含1.43億隻哺乳類、24.6億隻爬蟲類、1.8億隻鳥類,以及5100萬隻蛙類。

生物多樣性
國際新聞
澳洲
大火
野火
山地
森林

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

【其他文章推薦】

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

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

※教你寫出一流的銷售文案?

※超省錢租車方案

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

※產品缺大量曝光嗎?你需要的是一流包裝設計!

亞馬遜大火頻率增 專家估9月達高峰

摘錄自2020年8月3日台灣醒報報導

亞馬遜大火燒不停,7月野火頻率增3成。根據巴西政府公布最新數字發現,今年7月當地亞馬遜地區發生森林大火次數增加將近3成。對此,專家認為預估今年9月將來到新高紀錄,從中也顯示巴西政府減少森林野火的努力效率並不佳。

據《BBC》報導,從巴西國家太空研究院編撰後的衛星照片可發現,7月發生森林大火次數為6,803起,相較去年同期增加28%。據《Fire Engineering》報導,巴西國家太空研究院也表示,今年7月觀察到6,803起亞馬遜雨林大火,去年則為5,318起。環保人士對此表達關切,因為8月通常是森林大火季節的開始,按照今年結果來看,去年超過3萬起大火的慘況今年恐怕又會重蹈覆轍。雖然波索納洛已在5月下令,要求軍方協助亞馬遜的環保活動,但專家表示,從這次結果來看,政府反應不僅沒有效率,而且今年乾季將比去年更容易出現火災。

聖保羅州立大學研究人員諾布雷表示,相較前幾年,毀林指數在7月之前依舊維持在高檔。他指出,「從截至7月的數據來看,我們可以斷言,政府減少大火與毀林的效率仍低。」德國前瞻永續研究院研究人員里特爾也認為,「從趨勢來看,今年會比2019年更乾燥,讓森林大火更容易蔓延開來。」

國際新聞
亞馬遜
森林野火

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

【其他文章推薦】

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

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

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

※產品缺大量曝光嗎?你需要的是一流包裝設計!

超市減塑有成 英格蘭一次性購物袋收費後 2019年用量下降59%

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

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

【其他文章推薦】

※教你寫出一流的銷售文案?

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

※回頭車貨運收費標準

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

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

全美中國可疑種子包裹化驗出爐 恐破壞在地生態

摘錄自2020年8月4日中央社報導

美國農業部(USDA)動植物健康檢查局副局長艾爾西(Osama El-Lissy)表示,截至7月29日止,已鑑定出芥菜、高麗菜、牽牛花、薄荷、鼠尾草、迷迭香、薰衣草等植物種子,另有木棉花、玫瑰種子。目前鑑定出的品種雖屬無害,但植物專家警告,外來種子有可能損害農作物。

美國哥倫比亞廣播公司新聞網(CBS News)報導,全美50州都有民眾通報收到可疑種子包裹。美國農業部已提醒民眾收到後千萬不要栽種,應立刻向當地的農政單位通報。德州農業廳長米勒(Sid Miller)呼籲民眾保持警覺,「那可能是細菌,也可能是病毒或某個外來種植物」。

維吉尼亞州的農業官員警告:「外來物種會造成環境浩劫,取代或破壞原生植物及昆蟲,嚴重損害農作物。降低外來物種入侵並大量繁殖的風險並減少相關管控成本,最有效的方法就是採取措施、預防入侵物種的引入。」

愛荷華州農業暨土地管理廳的種子檢驗官員普魯伊斯納(Robin Pruisner)表示,有通報指出種子上可能含有殺蟲或除黴劑,對農作物危害甚大。

生物多樣性
國際新聞
美國
種子
外來物種
入侵植物
外來種植物

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

【其他文章推薦】

※超省錢租車方案

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

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

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

玩轉華為物聯網IoTDA服務系列三-自動售貨機銷售分析場景示例

場景簡介

       通過收集自動售貨機系統的銷售數據,EI數據分析售貨銷量狀況。

        該場景主要描述的是設備可以通過MQTT協議與物聯網平台進行交互,應用側可以到物聯網平台訂閱設備側變化的通知,用戶可以在控制台或通過應用側接口創建數據轉發規則,把設備上報的屬性轉發給其他華為雲服務。

        核心知識點:產品模型、編輯碼插件、訂閱推送、屬性上報、MQTT協議、數據轉發規則。

場景流程

流程解釋:

        

  • 1、創建自動售貨機產品:物聯網平台以產品為粒度管理批量設備。用戶可以通過平台提供的API接口或控制台創建產品。

  • 2、上傳產品模型:產品模型是定義一種設備的基本屬性和命令。產品模型可以通過控制台,也可以導入公共產品庫的模型。該場景沒有編解碼插件,是因為設備是基於安卓操作系統開發的,能夠通過MQTT協議與平台進行交互。

  • 3、批量註冊自動售貨機設備:平台提供了應用側API接口可以註冊設備,也可以通過控制台批量註冊。註冊設備時獲取的設備ID,是設備側與平台交互的唯一標識。

  • 4、創建自動售貨機設備狀態變化的訂閱:售貨管理系統可以在平台創建設備變化的通知訂閱,需要把callback url即應用回調地址傳給平台,平台後續會推送通知到該url。

  • 5、設備建鏈:MQTT設備是指通過MQTT協議,不論是集成了華為IoT Device SDK,還是原生MQTT協議接入,只要是json數據格式傳輸給平台,平台就無需使用編解碼插件。如果是二進制上傳,則需要先做編解碼插件的開發。MQTT是長連接,需要先建鏈才能進行數據傳輸,可以通過安全加密方式8883端口接入(推薦),也可以通過非安全加密方式1883端口接入。

  • 6、推送自動售貨機設備激活通知:平台會根據之前應用訂閱的回調地址,把自動售貨機設備上線的通知類型通過HTTP/HTTPS推送回去。

  • 7、創建數據轉發規則:售貨管理系統可以通過API接口創建規則,也可以通過控制台創建,指定過濾指定的屬性,給指定的通道轉發數據。

  • 8、開通DIS通道/MRS服務:華為公有雲上有豐富的SaaS服務和PaaS服務,供您結合自己的業務需要進行組合使用。DIS服務提供高效採集、傳輸、分發能力,支持多種IoT協議,可以開通該服務,通過IoTDA規則引擎,把自動售貨機設備的數據轉發給DIS,然後再利用諸如MRS服務,實現自動售貨銷量狀況數據分析。

  • 9、自動售貨機屬性上報:設備側可以通過SDK或MQTT原生協議接入平台,屬性上報銷售信息。這裏值得注意的是,設備側上報的數據,是通過屬性上報,與消息上報最大的區別在於是否經過產品模型。屬性上報的內容與格式都要跟產品模型定義保持一致。具體概念介紹可以參閱“物模型”。

  • 10、按規則數據轉發:平台收到設備上報的屬性后,規則引擎會進行過濾(不論屬性還是消息,平台都會做規則過濾),把設定好的屬性值轉發到指定的DIS通道,然後再通過DIS的接口,由MRS去消費DIS的數據,實現對銷量的分析。

最佳實踐

場景說明

物聯網解決方案中,作為數據主體的“物”可能數量會非常大,產生的數據已經無法通過傳統的數據處理服務進行處理。如何分析與利用這龐大的物聯網設備數據對物聯網企業來說又是一個新的挑戰。

華為雲物聯網平台提供規則引擎能力,支持將數據上報的數據轉發至華為雲其他雲服務,可實現將海量數據通過數據接入服務(DIS)轉發至MapReduce服務(MRS),對數據進行處理后再由數據可視化服務(DLV)讀取數據呈現為可視化報表,實現數據的一站式採集、處理和分析。

在本示例中,我們實現下述場景:

自動售貨機每次銷售商品後上報銷售商品種類、數量、時間和所屬區域到物聯網平台,物聯網平台將數據通過數據接入服務轉發至MapReduce服務,MapReduce服務處理數據並寫為統計文件,數據可視化服務從統計文件讀取數據展現為四個維度的銷售報表。

創建MapReduce集群

創建集群,用於存儲和處理DIS轉儲的數據。

  1. 登錄華為雲官方網站,訪問MapReduce服務。

  2. 單擊“立即購買”,創建集群,以下配置僅為樣例。

    注:下圖以新版自定義購買界面為例,需要在“購買集群”界面點擊右上角的“點擊體驗新版”,然後選擇“自定義購買”。

參數名稱

說明

軟件配置

當前區域

保持默認。

集群名稱

自定義或保持默認。

集群版本

保持默認。

集群類型

分析集群。組件勾選Spark,系統會自動勾選Hive和Tez。“Hive使用外部數據源存儲元數據”保持關閉。

Kerberos認證

關閉。

用戶名

固定為“admin”不可修改。

密碼

自定義。

確認密碼

硬件配置

計費模式

按實際使用需求選擇,本示例中選擇“按需計費”。

網絡配置

全部保持默認。

實例

為節省實驗費用,可修改分析Core的實例數量為1,其餘保持默認值。密碼自定義。

高級配置均保持默認。

3.集群創建成功后,等待15到30分鐘,集群狀態變更為“運行中”則表示創建成功。

創建OBS桶

  1. 登錄華為雲官方網站,訪問對象存儲服務。

  2. 單擊“管理控制台”進入對象存儲服務管理控制台。

  3. 單擊頁面右上角的“創建桶”,根據需求選擇桶規格后,單擊“立即創建”。

創建數據接入通道和轉儲任務

創建通道並配置轉儲任務,實現將設備管理服務傳入DIS的數據轉發至MRS。

  1. 登錄華為雲官方網站,訪問數據接入服務。

  2. 單擊“立即購買”,購買接入通道,以下配置僅為樣例。

參數名稱

說明

區域

保持默認。

通道名稱

自定義或保持默認。

通道類型

保持默認值“普通”。

分區數量

按需填寫。

生命周期

源數據類型

選擇“JSON”。

自動擴縮容

保持關閉。

Schema開關

高級配置

保持默認。

3.通道購買成功后,進入DIS控制台接入管理 > 通道管理”頁面。

4.單擊需要查看的通道名稱,進入所選通道的管理頁面,選擇“轉儲管理”頁簽。

5.單擊“添加轉儲任務”按鈕。

6.在彈出的“添加轉儲任務”頁面配置轉儲相關配置項。

參數名稱

說明

源數據類型

默認為通道源數據類型

轉儲服務類型

選擇“MRS”。

任務名稱

自定義,如“iot_to_mrs”。

轉儲文件格式

選擇“Text”。

MRS集群

選擇已創建成功的MRS集群。

HDFS路徑

選擇轉儲文件要存儲的路徑,建議選擇“/user”。

轉儲文件目錄

自定義轉儲文件存放的文件夾名稱,本示例中為“temp”。

偏移量

選擇“最新”。

數據轉儲周期

本示例中修改為“60”。

數據臨時桶

選擇已創建的OBS桶。

數據臨時目錄

自定義,本示例中為“temp”。

7.單擊“立即創建”。

配置設備接入服務

在設備接入服務中創建產品模型、註冊設備並設置數據轉發規則,實現當設備上報數據時將數據轉發至DIS。

  1. 登錄華為雲官方網站,訪問設備接入服務。

  2. 單擊“立即使用”進入設備接入控制台。

  3. 單擊規則 > 創建規則 > 數據轉發”,首次創建對接到DIS服務的規則時,平台會根據對接的雲服務和區域彈出對應的雲服務訪問授權窗口。

4.單擊左側導航欄的“產品”,單擊右上角下拉框,選擇新建產品所屬的資源空間。

注:本文中使用的產品模型和設備僅為示例,您可以使用自己的產品模型和設備進行操作。

5.單擊右上角的“創建產品”,創建一個基於MQTT協議的產品,填寫參數后,單擊“確認”。

基本信息

產品名稱

自定義,如MQTT_Device

協議類型

選擇“MQTT”

數據格式

選擇“JSON”

廠商名稱

自定義

功能定義

選擇模型

請參考步驟6導入模型即可。

所屬行業

根據實際情況進行填寫。

設備類型

6.在功能定義頁面,單擊“上傳模型文件”,單擊Profile.zip,獲取產品模型文件樣例。

7.進入設備 > 設備註冊”頁面,單擊“註冊設備”,參考下錶填寫參數。

參數名稱

說明

所屬產品

選擇在步驟5中創建的產品。

設備標識碼

設備唯一物理標識,如IMEI、MAC地址等,用於設備在接入物聯網平台時攜帶該標識信息完成接入鑒權。

  • 原生MQTT設備:自定義,英文字母和数字的組合字符串。通過註冊成功後生成的“設備ID”(與設備標識碼一一對應)和“設備密鑰”接入平台。

  • NB-IoT設備、集成SDK的設備:NB-IoT設備上的IMEI或MAC地址。設備通過註冊時填寫的“設備標識碼”和“密鑰”接入平台。

設備名稱

自定義。

設備認證類型

選擇“密鑰”。

密鑰

設備密鑰,可自定義,不填寫物聯網平台會自動生成。

填寫完成后單擊“確定”,請注意保存註冊成功返回的“設備ID”和“設備密鑰”。

8.單擊左側導航欄的“規則”,單擊右上角的“創建規則”,選擇“數據轉發”。

9.填寫規則內容,規則名稱自定義,“數據類型”選擇“JSON”,轉發至“數據接入服務(DIS)”,“區域”選擇您開通OBS的區域,“通道”選擇您創建的桶,填寫完成后單擊“創建規則”。

配置數據可視化服務

配置數據可視化服務,新建數據報表視圖。

  1. 登錄華為雲官方網站,訪問數據可視化服務。

  2. 單擊“進入控制台”。

    注:若您未開通DLV服務,可單擊“體驗試用”獲取30天的基礎版免費試用。

  3. 訪問DLV控制台“我的大屏”頁面,新建一個大屏。

4.選擇空白模板,輸入大屏名稱后,單擊“創建大屏”。

5.單擊文本 > 標題”新增一個標題。

 

6.在右側“數據”面板修改靜態數據中“value”的值為“每日銷量”。

7.在大屏內拖動標題到左上角,並拉伸成合適的形狀。

8.單擊常用圖表 > 線狀圖”新增一個線狀圖報表。

9.拖動圖表到標題下面並拉伸成合適的形狀。

10.重複以上步驟再添加一個標題為“時間段銷量”柱狀圖,一個標題為“種類銷量”的餅狀圖,一個標題為“地區銷量”的區域排行圖,並根據自己的需要設置圖表的樣式。最終效果類似下圖。

11.單擊頁面右上角的返回按鈕退出編輯頁面。

 

驗證操作

1.首先控制設備上報10條數據。

  • 您可以使用配置設備接入服務時註冊的真實設備接入平台,上報數據。

  • 您也可以使用模擬器模擬設備上報數據,操作方法請參考通過MQTT.fx體驗設備接入。

    上報數據的樣例如下,請自行修改參數的取值模擬真實設備數據:

樣例1

{
	"msgType": "deviceReq",
	"data": [{
		"serviceId": "sales",
		"serviceData": {
			"category": "soda",
            "number": "1",
            "area": "SZLH",
            "timeStamp": "20190425T091157Z"
		}
	}]
}

上述樣例表示UTC時間2019年4月25日9點11分57秒深圳羅湖的自動販賣機銷售了一支蘇打飲料。

樣例2

{
	"msgType": "deviceReq",
	"data": [{
		"serviceId": "sales",
		"serviceData": {
			"category": "juice",
            "number": "2",
            "area": "SZFT"
            "timeStamp": "20190426T170005Z"
		}
	}]
}

上述樣例表示UTC時間2019年4月26日17點05秒深圳福田的自動販賣機銷售了兩支果汁飲料。

本文以上報下錶的數據為例。

category

number

area

timeStamp

soda

1

SZLH

20190425T091157Z

juice

1

SZFT

20190425T121511Z

sport

1

SZLH

20190425T172433Z

juice

2

SZFT

20190426T170005Z

soda

1

SZNS

20190426T190905Z

juice

1

SZNS

20190427T085959Z

juice

2

SZLH

20190427T111111Z

soda

3

SZFT

20190428T182215Z

sport

1

SZLH

20190429T205901Z

soda

1

SZLG

20190430T225045Z

2.登錄MRS管理控制台,選擇“集群列表 > 現有集群”,單擊集群名進入集群管理頁面。

3.單擊頁面上方的“文件管理”,再單擊“HDFS文件列表”,進入轉儲文件目錄(例如“temp”)查看是否存在轉儲的數據文件。

注:DIS會將數據合併轉發,所以此處的文件數量和上報的數據條數可能會不一致。

4.單擊頁面上方的“作業管理”,在“作業”頁簽中單擊“添加”,配置作業信息。本示例中創建一個spark類型的作業,實現分析設備上報數據,分別按日期、時間段、種類、區域統計銷量,將分析結果輸出為CSV文件並保存至OBS。

參數名稱

說明

作業類型

選擇“SparkSubmit”。

作業名稱

自定義,如“test”。

執行程序路徑

  1. 點擊下載jar包並上傳至OBS桶。

  2. 回到添加作業頁面,單擊“OBS”后單擊“瀏覽”選擇剛剛上傳的jar文件。

運行程序參數

左側選擇“–class”,右側輸入“com.huawei.bigdata.spark.examples.SalesStatistics”。

執行程序參數

輸入“AK SK inputpath outputpath”。

  • 其中AK SK填寫華為雲賬號的AK、SK,獲取方法可參考AK和SK的獲取方法。

  • inputpath填寫文件輸入路徑,在本樣例中為DIS的轉儲路徑,如“/user/temp”。

  • outputpath填寫文件輸出路徑,在本樣例中為已申請的OBS桶內的output文件夾(無需提前在OBS創建文件夾,MRS會自動創建),如“s3a://{OBS桶名稱}/output”。

服務配置參數

無需填寫。

配置完成后單擊“確定”啟動作業。

5.作業完成后,可在OBS桶內看到output文件夾,裏面有四個文件夾,每個文件夾內有一個“_SUCCESS”文件和一個“part”開頭的csv文件。

注:本實驗的樣例程序分析數據時會將UTC時間轉換為本地時間,因此數據分析結果中的日期與時間段數值會和上報時的數值不一致。

6.登錄華為雲官方網站,訪問數據可視化服務。

7.單擊“進入控制台”。

8.單擊“我的數據 > 新建數據連接” ,在“新建數據連接”頁面左側的數據庫類型中,選擇“CSV文件”,按照下錶的數據規劃填寫配置后單擊“確定”。重複本步驟建立4個數據連接。

參數名

說明

名稱

建立4個數據連接,分別命名為:

  • salesByDate

  • salesByTime

  • salesByCategory

  • salesByArea

Access Key

填寫華為雲賬號的AK、SK,獲取方法可參考AK和SK的獲取方法。

Secret Access Key

文件來源

選擇“OBS文件”。

文件路徑

4個連接分別選擇步驟5的output文件夾內和連接同名的文件夾內的csv文件。

9.返回“我的大屏”頁簽,單擊配置數據可視化服務時創建的大屏右下的編輯按鈕進入編輯頁面。

10.選中“每日銷量”表,在右側數據面板選擇數據類型為“CSV文件”,數據連接選擇步驟8添加的數據連接“salesByDate”。

11.根據響應數據的屬性名稱配置字段映射。

配置 “x”為 “saleDate”, “y”為 “saleNumber”。

12.選中“時間段銷量”表,在右側數據面板選擇數據類型為“CSV文件”,數據連接選擇步驟8添加的數據連接“salesByTime”。

13.根據響應數據的屬性名稱配置字段映射。

配置 “x”為 “saleTime”, “y”為 “saleNumber”。

14.選中“種類銷量”表,在右側數據面板選擇數據類型為“CSV文件”,數據連接選擇步驟8添加的數據連接“salesByCategory”。

15.根據響應數據的屬性名稱配置字段映射。

配置 “s”為 “category”, “y”為 “saleNumber”,並設置各個分類的名稱(本示例中為“soda”,“juice”,“sport”)和圖例的顏色。

16.選中“地區銷量”表,在右側數據面板選擇數據類型為“CSV文件”,數據連接選擇步驟8添加的數據連接“salesByArea”。

17.根據響應數據的屬性名稱配置字段映射。

配置 “num”為 “saleNumber”。

18.全部圖表配置完成后,單擊頁面右上角的可預覽報表,示例如下圖。

至此,通過該文檔的學習,您應該對自動售貨機銷售分析場景有了一定的了解。接下來,可以在系列後續文章中,可以學習到更多的物聯網業務場景。

添加華為IoT小助手(微信號:huawei-iot,回復“博客園”)獲取此物聯網免費學習課程。

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

※教你寫出一流的銷售文案?

曹工說JDK源碼(4)–抄了一小段ConcurrentHashMap的代碼,我解決了部分場景下的Redis緩存雪崩問題

曹工說JDK源碼(1)–ConcurrentHashMap,擴容前大家同在一個哈希桶,為啥擴容后,你去新數組的高位,我只能去低位?

曹工說JDK源碼(2)–ConcurrentHashMap的多線程擴容,說白了,就是分段取任務

曹工說JDK源碼(3)–ConcurrentHashMap,Hash算法優化、位運算揭秘

什麼是緩存雪崩

基本概念梳理

這個基本也是redis 面試的經典題目了,然而,網上不少博客對這個詞的定義都含糊不清,各執一詞。

主要有兩類說法:

  • 大量緩存key,由於設置了相同的過期時間,在某個時刻同時失效,導致此刻的查詢請求,全部湧向db,本來db的tps大概是幾千左右,結果湧入了幾十萬的請求,那db肯定直接就扛不住了

    這種說法下面,解決方案一般是,把過期時間增加一個隨機值,這樣,也就不會大批量的key同時失效了

  • 另外一種說法是,本來redis扛下了大部分的請求,但是,由於緩存所在的機器,發生了宕機。此時,緩存這台機器之間就連不上了,redis服務也掛了,此時,你的服務里,發現redis取不到,然後全都跑去查數據庫,那,就發生和前面一樣的情況了,請求全部湧向db,db無響應。

兩類說法,也不用覺得,這個對,那個不對,不過是一個技術名詞,當初發明這個詞的人,估計也沒想那麼多,結果傳播開來之後,就變成了現在這個樣子。

我們這裏主要採用下面那一種說法,因為下面這種說法,其實是已經包含了上面的情景。但是,下面這種場景,要複雜的多,因為redis此時就是一個完全不可信的東西了,你得想好,怎麼不讓它掛掉,那是不是應該部署sentinel、cluster集群?同時,持久化必須要開啟。

這樣呢,掛掉后,短暫的不可用之後,大概幾十s吧,緩存集群就恢復了,就又可用了。

同時,我們還得考慮,假設,現在redis掛了,我們代碼的降級策略是什麼?

大家發現redis掛了,首先,估計是會拋異常了,連接超時;拋了異常后,要直接拋到前端嗎?作為一個穩健的後端程序,那肯定是不行的,你redis掛了,數據庫又沒掛;好吧,那我們就大家一起去查數據庫。

結果,大量的查詢請求,就烏泱泱地跑去查庫了,然後,db卒。這個肯定不行。

所以,我們必須要控制的一點是,當發現某個key失效了,不是大家都去查庫,而是要進行 併發控制

什麼是併發控制?就是不能全部放過去查庫,只能放少部分,免得把脆弱的db打死。

併發控制,基本就是要爭奪去查庫的權利了,這一步,基本就是一個選舉的過程,可以通過搶鎖的方式,比如Reentrentlock,synchronized,cas也可以。

  1. 搶到鎖的線程,有資格去查庫,其他線程要麼被阻塞,要麼自旋

  2. 搶到鎖的線程,去查庫,查到數據后,將數據存放在某個地方,通知其他線程去取(如果其他線程被阻塞的話);或者,如果其他線程沒被阻塞,比如sleep 50ms,再去指定的地方拿數據那種,這種就不需要通知

    總之,如果其他線程要我們通知,我們就通知;不要我們通知,我們就不通知。

搶到鎖的線程,在構建緩存時,其他線程應該干什麼?

  1. 在while(true)里,sleep 50ms,然後再去取數據

    這種類似於忙等待,但是每次sleep一會,所以還不錯

  2. 將自己阻塞,等待搶到鎖的線程,構建完緩存后,來喚醒

  3. 在while(true)里,一直忙循環,期間一直檢查數據是否已經ok了,這種方案呢,要看裏面:檢查數據的操作,是否耗時;如果只是檢查jvm內存里的數據,那還好;否則的話,假設要去檢查redis的話,這種io比較耗時的操作的話,就不合適了,cpu會一直空轉。

本文採用的方案

主線程構建緩存時,其他線程,在while(true)里,sleep 一定時間,然後再檢查數據是否ready。

說了這麼多,好像和題目里的concurrenthashmap沒啥關係,不,是有關係的,因為,這個思路,其實就是來自於concurrentHashMap。

ConcurrentHashMap中,是怎麼去初始化底層數組的

在我們用無參構造函數,去new一個ConcurrentHashMap時,此時還不會去創建底層數組,這個是一個小優化。什麼時候創建數組呢,是在我們第一次去put的時候。

put的時候,會調用putVal。

其中,putVal代碼如下:

    transient volatile Node<K,V>[] table;

	final V putVal(K key, V value, boolean onlyIfAbsent) {
        if (key == null || value == null) throw new NullPointerException();
        int hash = spread(key.hashCode());
        int binCount = 0;
      	// 1
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
          	// 2
            if (tab == null || (n = tab.length) == 0)
                tab = initTable();
  • 1處,把field table,賦值給局部變量tab

  • 2處,如果tab為null,則進行initTable初始化

    這個2處,在多線程put的時候,是可能多個線程同時進來的。有併發問題。

我們接下來,看看initTable是怎麼解決這個問題的,畢竟,我們new數組,只new一次即可,new那麼多次,沒用,對性能有損耗。所以,這裏面肯定會多線程爭奪初始化權利的代碼。

	private transient volatile int sizeCtl;
	transient volatile Node<K,V>[] table;

	/**
     * Initializes table, using the size recorded in sizeCtl.
     */
    private final Node<K,V>[] initTable() {
        Node<K,V>[] tab;
      	int sc;
      	
      	// 0
        while ((tab = table) == null || tab.length == 0) {
          	// 1
            if ((sc = sizeCtl) < 0)
                Thread.yield(); // lost initialization race; just spin
          	// 2
            else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                try {
                  	// 3
                    if ((tab = table) == null || tab.length == 0) {
                      	// 4
                        int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                        @SuppressWarnings("unchecked")
                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                        table = tab = nt;
                        sc = n - (n >>> 2);
                    }
                } finally {
                  	// 5
                    sizeCtl = sc;
                }
                break;
              
            }// end if
          
        }// end while
        return tab;
    }
  • 1處,這裏把sizeCtl,賦值給局部變量sc。這裏的sizeCtl是一個很重要的field,當我們new完之後,默認這個字段,要麼為0,要麼為準備創建的底層數組的長度。

    這裏去判斷是否小於0,那肯定不滿足,小於0,會是什麼意思?當某個線程,搶到了這個initTable中的底層數組的創建權利時,就會把sizeCtl改為 -1。

    所以,這裏的意思是,看看是否已經有其他線程在初始化了,如果已經有了,則直接調用:

    Thread.yield();

    這個方法的意思是,暗示操作系統,自己準備放棄cpu;但操作系統,自有它自己的線程調度規則,所以,這個方法可能沒什麼效果;我們業務代碼,這裏一般可以修改為Thread.sleep。

    這個方法調用完成后,後續也沒有其他代碼,所以會直接跳轉到循環開始處(0處代碼),判斷table是否初始化ok了,如果沒有ok,則會繼續進來。

  • 2處,使用cas,如果此時,sizeCtl的值等於sc的值,就修改sizeCtl為 -1;如果成功,則返回true,進入3處

    否則,會跳轉到0處,繼續循環。

  • 3處,雖然搶到了控制權,但是這裏還是要再判斷一下,不然可能出現重複初始化,即,不加這一行,4處的代碼,會被重複執行

  • 4處開始,這裏去執行真正的初始化邏輯。

    // 
    int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
    @SuppressWarnings("unchecked")
    // 1
    Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
    // 2
    table = tab = nt;
    sc = n - (n >>> 2);
    

    這裏的1處,new數組;2處,賦值給field:table;此時,因為table 這個field是volatile修飾的,所以其他線程會馬上感知到。0處代碼就不會為true了,就不會繼續循環了。

  • 5處,修改sizeCtl為正數。

這裏說下,為啥要加3處的那個判斷。

現在,假設線程A,在初始化完成后,走到了5處,修改了sizeCtl為正數;而線程B,剛好執行1處代碼:

// 1
if ((sc = sizeCtl) < 0)

那肯定,1處就不滿足了;然後就會進到2處,cas修改成功,進行初始化。沒有3處判斷的話,就會重複初始化。

基於concurrentHashmap,實現我們的緩存雪崩方案

我這裏的方案,還是比較簡單那種,就是,n個線程同時爭奪構建緩存的權利;winner線程,構建緩存后,會把緩存設置到redis;其他線程則是一直在while(true)里sleep一段時間,然後檢查redis里的數據是否不為空。

這個方案中,redis掛了這種情況,是沒在考慮中的,但是一個方案,沒辦法立馬各方面全部到位,後續我再完善一下。

不考慮緩存雪崩的代碼

@Override
public Users getUser(long userId) {
    ValueOperations<String, Users> ops = redisTemplate.opsForValue();
  	// 1
    Users s = ops.get(String.valueOf(userId));
    if (s == null) {
        /**
         * 2 這裏要去查庫獲取值
         */
        Users users = getUsersFromDB(userId);
		// 3
        ops.set(String.valueOf(users.getUserId()),users);

        return users;
    }

    return s;
}

private Users getUsersFromDB(long userId) {
    Users users = new Users();

    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("spent 1s to get user from db");
    users.setUserId(userId);
    users.setUserName("zhangsan");

    return users;
}

直接看上面的1,2,3處。就是檢查、構建緩存,設置到緩存的過程。

考慮緩存雪崩的代碼

	// 1
	private volatile int initControl;

	@Override
    public Users getUser(long userId) {
        ValueOperations<String, Users> ops = redisTemplate.opsForValue();

        Users users;
        while (true) {
          	// 2
            users = ops.get(String.valueOf(userId));
            if (users != null) {
              	// 3 
                break;
            }
			
          	// 4
            int initControlLocal = initControl;
            /**
             * 5 如果已經有線程在進行獲取了,則直接放棄cpu
             */
            if (initControlLocal < 0) {
//                log.info("initControlLocal < 0,just yield and wait");
//                Thread.yield();
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    log.warn("e:{}", e);
                }
                continue;
            }


            /**
             * 6 爭奪控制權
             */
            boolean bGotChanceToInit = U.compareAndSwapInt(this,
                    INIT_CONTROL, initControlLocal, -1);
          	// 7
            if (bGotChanceToInit) {
                try {
                  	// 8
                    users = ops.get(String.valueOf(userId));
                    if (users == null) {
                        log.info("got change to init");
                        /**
                         * 9 這裏要去查庫獲取值
                         */
                        users = getUsersFromDB(userId);
                        ops.set(String.valueOf(users.getUserId()), users);
                        log.info("init over");
                    }
                } finally {
                  	// 10
                    initControl = 0;
                }

                break;
            }// end if (bGotChanceToInit)
        }// end while


        return users;
    }
  • 1處,定義了一個field,initControl;默認為0.線程們會去使用cas,修改為-1,成功的線程,即獲得初始化緩存的權利。

    注意,要定義為volatile,保證線程間的可見性

  • 2處,去redis獲取緩存,如果不為null,直接返回

  • 4處,如果沒取到緩存,則進入此處;此處,將field:initControl賦值給局部變量

  • 5處,判斷局部變量initControlLocal,是否小於0;小於0,說明已經有線程在進行初始化了,直接contine,繼續下一次循環

  • 6處,如果當前還沒有線程在初始化,則開始競爭初始化的權利,誰成功地用cas,修改field:initControl為-1,誰就獲得這個權利

  • 7處,如果當前線程獲得了權利,則進入8處,否則,會繼續下一次循環

  • 8處,再次去redis,獲取緩存,如果不為空,則進入9處

  • 9處,查庫,設置緩存

  • 10處,修改field:initControl為0,表示退出初始化

這裏的代碼,整體和hashmap中的initTable是一模一樣的。

如何測試

上面的方案,怎麼測試沒問題呢?我寫了一段測試代碼。

    ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100,
            60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000), new RejectedExecutionHandler() 	{
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            log.info("discard:{}",r);
        }
    });
	
	@RequestMapping("/test.do")
    public void test() {
      	// 0
        iUsersService.deleteUser(111L);

        CyclicBarrier barrier = new CyclicBarrier(100);

        for (int i = 0; i < 100; i++) {

            executor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        barrier.await();
                    } catch (InterruptedException | BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                    long start = System.currentTimeMillis();
                  	// 1
                    Users users = iUsersService.getUser(111L);
                    log.info("result:{},spent {} ms", users, System.currentTimeMillis() - start);
                }
            });
        }

    }

上面模擬100併發下,獲取緩存。

0處,把緩存刪了,模擬緩存失效

1處,調用方法,獲取緩存。

效果如下:

可以看到,只有一個線程拿到了初始化權利。

源碼位置

https://gitee.com/ckl111/all-simple-demo-in-work-1/tree/master/redis-cache-avalanche

總結

jdk的併發包,寫得真是有水平,大家仔細研究的話,必有收穫。

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

【其他文章推薦】

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

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

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

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案