加州簽了! 2045年100%乾淨能源目標入法

環境資訊中心外電;姜唯 翻譯;林大利 審校;稿源:ENS

加州州長布朗10日簽署參議院100號法案(SB 100),將「100%乾淨電力」正式設立為法定目標。

繼提早四年達成「2020年減排13%、經濟成長26%」目標後,「SB 100」將使加州的再生能源比例標準更加積極,2025年必須達到50%電力由再生能源供應,2030年要達到60%,2045年實現零碳電網。

加州州長布朗簽署參議院100號法案(SB 100)。圖片來源:Office of the Governor

州長訂定碳中和目標  減碳不涉核電

為了確保全球暖化對策不只侷限於電業(佔加州溫室氣體排放量的16%),布朗還發布了一項行政命令,指示加州要在2045年實現碳中和,之後則要實現淨負排碳。

目前全球有20多個國家和40多個地方政府宣布,最晚要在本世紀中實現碳中和。

為了實現目標,加州將持續減少碳污染,同時增加森林、土壤和其他自然地景的碳儲存和空氣品質及公共衛生改善計畫,尤其是在該州受影響最嚴重的社區。

加州也將陸續實施一系列因應暖化的長期行動。上週,布朗簽署了另一項法案,禁止加州沿海進行新的聯邦海上石油鑽探活動,並宣布加州反對聯邦政府擴大加州公共土地上石油鑽探的計畫。1968年至今,加州都沒有開放沿海地區的新石油和天然氣租賃。

雖然加州政府定義的乾淨能源有三種,州政府在其網站上的指出,加州正在逐步淘汰核電,現階段也並不考慮新建核電廠。

減碳聯盟「Under2 Coalition」 規模跨六大洲、佔全球經濟四成

原本加州計畫於2020年達成減排13%、同時經濟成長26%,結果此目標提早四年達成。從2015到2016年,加州減排量大約等於減少240萬輛汽車上路,省下15億加侖的汽柴油燃料。

此外,布朗幫助建立全美和全球的減碳合作聯盟「Under2 Coalition」。該聯盟起源於加州與德國巴登-符騰堡州之間的合作關係,現在已納入橫跨六大洲的206個各級政府,共代表13億人口和30兆美元的GDP,相當於全球人口的17%和全球經濟的40%。

聯盟成員做出了一些重要承諾,包括減少相當於1990年水準80%至95%的溫室氣體排放,以及2050年加州每人每年碳排少於2公噸。

California Passes 100 Percent Clean Electricity Bill SACRAMENTO, California, September 10, 2018 (ENS)

Putting his stamp of approval on California’s global climate leadership, Governor Jerry Brown today signed Senate Bill 100, which sets a 100 percent clean electricity goal for the state. The governor also issued an executive order establishing a new target to achieve carbon neutrality – both by 2045.

With Governor Brown’s executive order, California establishes the most ambitious carbon neutrality commitment of the more than 20 countries and at least 40 cities, states and provinces planning to go carbon neutral by mid-century or sooner.

SB 100 advances the state’s existing Renewables Portfolio Standard, which establishes how much of the electricity system should be powered from renewable energy resources, to 50 percent by 2025 and 60 percent by 2030.

It also puts California on the bold path to implement a zero-carbon electricity grid by 2045.

To ensure California is combating global warming beyond the electric sector, which represents 16 percent of the state’s greenhouse gas emissions, the governor’s executive order directs the state to achieve carbon neutrality by 2045 and net negative greenhouse gas emissions after that.

The state will reach its goals with continued reductions of carbon pollution and increased carbon sequestration in forests, soils and other natural landscapes and programs focused on improving air quality and public health, especially in California’s most impacted communities.

These actions are the latest in a long series of actions by California to deal with the warming climate. Late last week, Governor Brown also signed legislation to block new federal offshore oil drilling along California’s coast and announced the state’s opposition to the federal government’s plan to expand oil drilling on public lands in California. The entirety of the state’s coast has been off-limits to new oil and gas leases for more than 30 years, and the state has not issued a lease for offshore oil or gas production since 1968.

The state has met its 2020 target four years early, reducing emissions 13 percent while growing the economy 26 percent.

From 2015 to 2016, emissions reductions were roughly equal to taking 2.4 million cars off the road, saving 1.5 billion gallons of gasoline and diesel fuel.

In addition, Governor Brown has helped establish and expand coalitions of partners across the nation and globe committed to curbing carbon pollution.

The Under2 Coalition, which originated from a partnership between California and the German state of Baden-Württemberg, now includes 206 jurisdictions on six continents that collectively represent 1.3 billion people and $30 trillion in GDP – equivalent to 17 percent of the global population and 40 percent of the global economy.

Members of the Under2 Coalition have made a number of key commitments, including reducing greenhouse gas emissions equivalent to 80 to 95 percent below 1990 levels or to less than two annual metric tons for each person in California by 2050.

※ 全文及圖片詳見:

作者

如果有一件事是重要的,如果能為孩子實現一個願望,那就是人類與大自然和諧共存。

於特有生物研究保育中心服務,小鳥和棲地是主要的研究對象。是龜毛的讀者,認為龜毛是探索世界的美德。

延伸閱讀

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

聚甘新

Chevrolet Bolt平價電動車投產、續航力近400公里

美聯社5日報導,通用汽車(General Motors)已開始在美國密西根州奧萊恩(Orion)鎮生產Chevrolet Bolt。這台續航力達238英里(383公里)的電動車建議零售價37,495美元起(註:最多可取得7,500美元的聯邦折抵稅額、扣除後入手價相當於29,995美元),今年底以前將於加州、奧勒岡州開賣,明年將擴及全美其他地區。根據凱利藍皮書(Kelley Blue Book)的統計,美國新車平均價格為34,000美元。特斯拉(Tesla Motors Inc.)200英里續航力、35,000美元(註:扣除聯邦折抵稅額前)Model 3電動車預計自2017年下半年開始交車。

IHS Markit汽車業分析師Stephanie Brinley指出,Bolt續航力遠高於美國平均來回通勤距離(40英里),但有時人們回家後可能忘了或沒有足夠時間進行充電,這是電動車主得多加費心的地方。美國目前使用中的電動車數量約23.5萬台,IHS預估Bolt開賣第一年銷售量逼近3萬台。美國去年電動車銷售量為10萬台,IHS預估年度銷售量將在2020年升至30萬台、2025年挑戰40萬台。

華爾街日報報導,通用汽車2015年10月宣布與LG電子結盟、後者將成為Chevrolet Bolt電動車的主要關鍵零件供應商。

英國金融時報8月報導,國際能源署(IEA)首席經濟學家Laszlo Varro指出,電動車目前對商品(原油)市場的影響力大約就像是10年前的太陽能一樣。他說,太陽能現在已是一個規模達數百億美元的市場、擁有龐大的影響力。Varro提到,電動車需達5千萬至1億台的規模、才能取代相當於100萬桶的石油日消費量。

IEA數據顯示,2009年全球40個國家合計僅有不到6千台的電動車、去年已升至120萬台。麥格理集團全球能源策略師Vikas Dwivedi指出,沙烏地阿拉伯對電動車的長期發展存有戒心,這可能就是它為何宣布將讓沙烏地阿拉伯國家石油公司(Saudi Aramco)初次公開發行(IPO)的原因之一。

CNNMoney去年底報導,石油輸出國組織(OPEC)發表的年度「世界石油展望(World Oil Outlook)」報告顯示,2040年高達94%的使用中車輛仍將是依靠石油燃料。OPEC報告顯示,除非出現重大技術性突破,否則在可預見的未來電動車將難以大幅取得市佔率。油國組織預估2040年僅有1%的車輛銷售量是來自純電動車款。

能源情報署(EIA)公布,截至2016年10月28日為止當週美國商用汽油庫存報2.238億桶、較去年同期高出3.9%。EIA公布的數據顯示,美國一般汽油每加侖零售均價10月31日報2.230美元,較一年前高出0.006美元。

(照片來源:。本文內容由 授權提供)

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

【其他文章推薦】

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

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

※想知道最厲害的網頁設計公司“嚨底家”!

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

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

聚甘新

BMW 2017年目標售出10萬輛電動車

德國媒體報導,汽車廠商BMW CEO Harald Krueger 在接受採訪時表示,電動車的時代即將到來,這一市場還有巨大的潛力,BMW 將在2017 年力爭把電動車的銷量提升到10 萬台,目前該公司2015 年電動車和混合動力車的銷量大約為6 萬台。

BMW CEO Harald Krueger 表示,該公司希望能夠在2017 年大幅提升電動車的銷量,至少提升六成,達到年銷量10 萬台。BMW 2016 年電動車和混合動力車的銷量合計大約為6 萬台,自2013 年發售電動車以來,BMW 電動車的雷軍銷量已經超過了10 萬台。

Harald Krueger 認為電動車的時代即將到來,這一市場還有很大的潛力,需求還沒有完全被發掘。

BMW 旗下唯一的純電動車車款i3 上市以來市場反響不如預期,2015 年i3 僅售出了2.5 萬台,為了提升這款產品的競爭力,BMW 將在2016 年的升級中把i3 系列電動車的續航里程提升50%。

在高階汽車市場中,BMW 的產品銷量已經落後於Benz,該公司希望在2025 年前將電動車和混合動力車的銷量提升到15%-25%。

(本文由《》授權提供。照片來源:)

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

聚甘新

Mybatis Generator逆向工程的使用

一、MyBatis Generator簡介

    MyBatis Generator(MBG)是MyBatis和iBATIS的代碼生成器。它將為所有版本的MyBatis以及版本2.2.0之後的iBATIS版本生成代碼。它將審查數據庫表(或許多表),並將生成可用於訪問表的構件。這減少了設置對象和配置文件以與數據庫表交互的初始麻煩。MBG尋求對簡單CRUD(創建,檢索,更新,刪除)的大部分數據庫操作產生重大影響。您仍然需要為連接查詢或存儲過程手動編寫SQL和對象代碼。MyBatis Generator將生成:

  • 與表結構匹配的Java POJO。這可能包括:

    • 一個匹配表的主鍵的類(如果有主鍵)

    • 一個匹配表的非主鍵字段的類(BLOB字段除外)

    • 包含表的BLOB字段的類(如果表具有BLOB字段)

    • 用於啟用動態選擇,更新和刪除的類

    這些類之間存在適當的繼承關係。請注意,生成器可以配置為生成不同類型的POJO層次結構 – 例如,如果您願意,可以選擇為每個表生成單個域對象。

  • MyBatis/iBATIS兼容的SQL Map XML文件。MBG為配置中的每個表上的簡單CRUD函數生成SQL。生成的SQL語句包括:

    • insert 插入

    • update by primary key  按主鍵更新

    • update by example (using a dynamic where clause)  通過條件更新(使用動態where子句)

    • delete by primary key  按主鍵刪除

    • delete by example (using a dynamic where clause)  按條件刪除(使用動態where子句)

    • select by primary key  按主鍵查詢

    • select by example (using a dynamic where clause)  按條件查詢(使用動態where子句)

    • count by example  按條件查詢記錄總數

    根據表結構的不同,這些語句有不同的變體(例如,如果表沒有主鍵,則MBG不會通過主鍵功能生成更新)。

    • 適當使用上述對象的Java客戶端類。Java客戶端類的生成是可選的。MBG將為MyBatis 3.x生成以下類型的Java客戶端:

      • 適用於MyBatis 3.x映射器基礎結構的映射器接口

MBG將為iBATIS 2.x生成以下類型的Java客戶端:

    • 符合Spring框架的DAO

    • 僅使用iBATIS SQL映射API的DAO。這些DAO可以生成兩種:通過構造函數或setter注入提供SqlMapClient。

    • 符合iBATIS DAO框架的DAO(iBATIS的可選部分,現在不推薦使用此框架,我們建議您使用Spring框架)

    MyBatis生成器設計為在迭代開發環境中運行良好,並且可以作為Ant任務或Maven插件包含在連續構建環境中。迭代運行MBG時需要注意的重要事項包括:

  1. 如果存在與新生成的XML文件同名的現有文件,MBG將自動合併XML文件。MBG不會覆蓋您對其生成的XML文件所做的任何自定義更改。您可以反覆運行它,而不必擔心會丟失對XML的自定義更改。MBG將替換先前運行中生成的任何XML元素。

  2. MBG不會合併Java文件,它可以覆蓋現有文件或使用不同的唯一名稱保存新生成的文件。如果對生成的Java文件進行更改並以迭代方式運行MBG,則必須手動合併更改。當作為Eclipse插件運行時 ,MBG可以自動合併Java文件。

二、MyBatis Generator使用

1、新建MBG的配置文件generatorConfig.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
 
 
    <!--導入屬性配置-->
    <properties resource="generator.properties"></properties>
    <!--指定特定數據庫的jdbc驅動jar包的位置-->
    <!--<classPathEntry location="${jdbc.driverLocation}"/>-->
 
    <context id="default" targetRuntime="MyBatis3">
 
        <!-- optional,旨在創建class時,對註釋進行控制,false生成註釋,true無註釋 -->
        <commentGenerator>
            <property name="suppressDate" value="false"/>
            <property name="suppressAllComments" value="false"/>
        </commentGenerator>
 
        <!--jdbc的數據庫連接 -->
        <jdbcConnection
                driverClass="${jdbc.driverClass}"
                connectionURL="${jdbc.connectionURL}"
                userId="${jdbc.userId}"
                password="${jdbc.password}">
        </jdbcConnection>
 
 
        <!--
         默認false,把JDBC DECIMAL 和 NUMERIC 類型解析為 Integer,
         為 true時把JDBC DECIMAL 和 NUMERIC 類型解析為java.math.BigDecimal
        -->
        <!-- 非必需,類型處理器,在數據庫類型和java類型之間的轉換控制-->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
 
 
        <!-- Model模型生成器,用來生成含有主鍵key的類,記錄類 以及查詢Example類
            targetPackage     指定生成的model生成所在的包名
            targetProject     指定在該項目下所在的路徑|指定生成到的工程名稱
        -->
        <javaModelGenerator targetPackage="com.test.model"
                            targetProject=".\src\main\java">
            <!-- 是否允許子包,即targetPackage.schemaName.tableName -->
            <property name="enableSubPackages" value="false"/>
            <!-- 是否對model添加 構造函數 true添加,false不添加-->
            <property name="constructorBased" value="false"/>
            <!-- 是否對類CHAR類型的列的數據進行trim操作 -->
            <property name="trimStrings" value="true"/>
            <!-- 建立的Model對象是否 不可改變  即生成的Model對象不會有 setter方法,只有構造方法 -->
            <property name="immutable" value="false"/>
        </javaModelGenerator>
 
        <!--Mapper映射文件生成所在的目錄 為每一個數據庫的表生成對應的SqlMapper文件 -->
        <sqlMapGenerator targetPackage="com.test.mapper"
                         targetProject=".\src\main\java">
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>
 
        <!-- 客戶端代碼,生成易於使用的針對Model對象和XML配置文件 的代碼
                type="ANNOTATEDMAPPER",生成Java Model 和基於註解的Mapper對象
                type="MIXEDMAPPER",生成基於註解的Java Model 和相應的Mapper對象
                type="XMLMAPPER",生成SQLMapper XML文件和獨立的Mapper接口
        -->
        <javaClientGenerator targetPackage="com.test.mapper"
                             targetProject=".\src\main\java" type="XMLMAPPER">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
 
        <!--需要映射的數據庫的表名-->
        <table tableName="t_userinfo" domainObjectName="UserInfo"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
    </context>
</generatorConfiguration>

2、新建generator.properties文件

jdbc.driverLocation=C:\\mysql-connector-java-5.1.43.jar
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.connectionURL=jdbc:mysql://localhost:3306/mybatis
jdbc.userId=root
jdbc.password=tiger

3、配置執行mybatis generator操作,這裡有兩種方式

第1種方式:如果使用maven項目就可以省去編寫Java啟動類,使用maven插件和配置文件pom.xml即可,插件啟動maven-generator,在pom.xml中添加maven-generator插件

<plugins>
    <!--myBatis逆向工程插件-->
    <plugin>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <version>1.3.2</version>
        <configuration>
            <verbose>true</verbose>
            <overwrite>true</overwrite>
            <configurationFile>${project.basedir}/src/main/resources/generatorConfig.xml</configurationFile>
        </configuration>
        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.35</version>
            </dependency>
        </dependencies>
    </plugin>
</plugins>

點擊mybatis-generator:generate就能執行mybatis generator了

第2種方式:

1、如果不是maven項目添加該mybatis-generator-core-1.3.2.jar,編寫main方法指向mybatis逆向工程,我給依賴粘貼到下面了

<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.3.2</version>
</dependency>

2、修改generatorConfig.xml文件,放開註釋的該配置

<classPathEntry location="${jdbc.driverLocation}"/>

3、然後編寫測試類執行

/**
 * 如果不是maven項目可以這樣生成
 */
public class MybatisGeneratorTest {
    public static void main(String[] args) throws InterruptedException, SQLException, IOException, InvalidConfigurationException, XMLParserException {
        List<String> warnings = new ArrayList<String>();
        //生成的java文件是否覆蓋
        boolean overwrite = true;
        //指定逆向工程配置文件
        //File configFile = new File("E:\\project\\mybatis-generator\\src\\main\\resources\\generatorConfig.xml");
        InputStream resourceAsStream = MybatisGeneratorTest.class.getClassLoader().getResourceAsStream("generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(resourceAsStream);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,callback, warnings);
        myBatisGenerator.generate(null);
    }
}

介紹完這兩種方式,查看數據表:

查看生成的實體類:


TIP:可以看出如果實體類想要遵循駝峰命名規範,數據庫表字段名設計需要用”_”來劃分

查看生成的文件信息:


TIP1:必須在<plugin></plugin>標籤里添加數據庫驅動,在其他地方添加無效,如果不添加會報找不到驅動錯誤,如過不在該插件添加數據庫依賴的話可以使用 <classPathEntry location=”${jdbc.driverLocation}”/> 來指定數據庫驅動位置。

TIP2:如果你在使用mybatis generator插件執行的時候報[ERROR] Failed to execute goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.2:generate (default-cli) on project mybatis-generator: <properties> resource generator.properties does not exist -> [Help 1]


儘管你的 <properties resource=”generator.properties”></properties>配置的沒有問題,但是還是找不到generator.properties,查看該配置,註釋掉


該配置會改變generatorConfig.xml中讀取generator.properties文件的默認路徑

TIP3:Mybatis Generator反向工程默認不會覆蓋生成的*.java文件。也可以設置覆蓋生成的*.java文件,在反向工程插件mybatis-generator-maven-plugin添加該配置<overwrite>true</overwrite>則會覆蓋生成的*.java文件,如圖


    Mybatis Generator不會覆蓋你的mapper.xml文件,MBG會合併追加到mapper.xml和你自定義的存在一起,但是如果你修改MBG第一次默認生成的SQL(MBG生成的CRUD),MBG會重新把自己生成的CRUD恢復默認,說白了,MBG只會覆蓋他自己生成的SQL,不會覆蓋你自定義的,你自定義的不變。。。如圖,他不會動你的自定義SQL,只會覆蓋Mybatis反向工程自己生成的SQL,前提MBG自動生成SQL語句的註釋要存在。


在最常見的用例中,MyBatis Generator(MBG)由XML配置文件驅動。配置文件告訴MBG

  • 如何連接到數據庫

  • 生成什麼對象,以及如何生成它們

  • 應使用哪些表生成對象

官方MBG配置文件詳解地址:http://mybatis.org/generator/configreference/xmlconfig.html

附帶一個MBG的中文配置文件詳解:https://www.jianshu.com/p/e09d2370b796

 

更多Mybatis逆向工程的使用參考:http://www.mybatis.org/generator/index.html


● XStream學習手冊

● 別在 Java 代碼里亂打日誌了,這才是正確的打日誌姿勢!

● 高可用Redis服務架構分析與搭建

● 8 種方案,幫你解決重複提交問題!請拿走

● IDEA 解決 Maven 依賴衝突的高能神器,這一篇夠不夠?

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

【其他文章推薦】

※超省錢租車方案

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

※回頭車貨運收費標準

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

FB行銷專家,教你從零開始的技巧

聚甘新

六、線程池(一)

線程池

通過建立池可以有效的利用系統資源,節約系統性能。Java 中的線程池就是一種非常好的實現,從 JDK1.5 開始 Java 提供了一個線程工廠 Executors 用來生成線程池,通過 Executors 可以方便的生成不同類型的線程池。

線程池的優點

  • 降低資源消耗。線程的開啟和銷毀會消耗資源,通過重複利用已創建的線程降低線程創建和銷毀造成的消耗。
  • 提高響應速度。當任務到達時,任務可以不需要的等到線程創建就能立即執行。
  • 提高線程的可管理性。線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。

常見的線程池

  • CachedThreadPool:可緩存的線程池,該線程池中沒有核心線程,非核心線程的數量為 Integer.max_value,就是無限大,當有需要時創建線程來執行任務,沒有需要時回收線程,適用於耗時少,任務量大的情況。
  • SecudleThreadPool:周期性執行任務的線程池,按照某種特定的計劃執行線程中的任務,有核心線程,但也有非核心線程,非核心線程的大小也為無限大。適用於執行周期性的任務。
  • SingleThreadPool:只有一條線程來執行任務,適用於有順序的任務的應用場景。
  • FixedThreadPool:定長的線程池,有核心線程,核心線程的即為最大的線程數量,沒有非核心線程
  • Executors.newFixedThreadPool()、Executors.newSingleThreadExecutor() 和 Executors.newCachedThreadPool() 等方法的底層都是通過 ThreadPoolExecutor 實現的。

ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        // maximumPoolSize 必須大於 0,且必須大於 corePoolSize
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
            null :
            AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

參數介紹:

  • corePoolSize

    • 線程池的核心線程數。在沒有設置 allowCoreThreadTimeOut 為 true 的情況下,核心線程會在線程池中一直存活,即使處於閑置狀態。
    • 如果設置為 0,則表示在沒有任何任務時,銷毀線程池;如果大於 0,即使沒有任務時也會保證線程池的線程數量等於此值。
    • 但需要注意,此值如果設置的比較小,則會頻繁的創建和銷毀線程,如果設置的比較大,則會浪費系統資源,所以需要根據自己的實際業務來調整此值。
  • maximumPoolSize

    • 線程池所能容納的最大線程數。當活動線程(核心線程+非核心線程)達到這個數值后,後續任務將會根據 RejectedExecutionHandler 來進行拒絕策略處理。
    • 官方規定此值必須大於 0,也必須大於等於 corePoolSize,此值只有在任務比較多,且不能存放在任務隊列時,才會用到。
  • keepAliveTime

    • 非核心線程閑置時的超時時長。超過該時長,非核心線程就會被回收。
    • 若線程池通過 allowCoreThreadTimeOut() 方法設置 allowCoreThreadTimeOut 屬性為 true,則該時長同樣會作用於核心線程,AsyncTask 配置的線程池就是這樣設置的。
  • unit

    • keepAliveTime 時長對應的單位。
  • workQueue

    • 表示線程池執行的任務隊列,當線程池的所有線程都在處理任務時,如果來了新任務就會緩存到此任務隊列中排隊等待執行。
    • 是一個阻塞隊列 BlockingQueue,雖然它是 Queue 的子接口,但是它的主要作用並不是容器,而是作為線程同步的工具,他有一個特徵,當生產者試圖向 BlockingQueue 放入(put)元素,如果隊列已滿,則該線程被阻塞;當消費者試圖從 BlockingQueue 取出(take)元素,如果隊列已空,則該線程被阻塞。
  • ThreadFactory

    • 線程的創建工廠,功能很簡單,就是為線程池提供創建新線程的功能。
    • 也可以自定義一個線程工廠,通過實現 ThreadFactory 接口來完成,這樣就可以自定義線程的名稱或線程執行的優先級了。
    • 通常在創建線程池時不指定此參數,它會使用默認的線程創建工廠的方法來創建線程,源代碼如下:
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        // Executors.defaultThreadFactory() 為默認的線程創建工廠
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }
    public static ThreadFactory defaultThreadFactory() {
        return new DefaultThreadFactory();
    }
    // 默認的線程創建工廠,需要實現 ThreadFactory 接口
    static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;
    
        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }
        // 創建線程
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon()) 
                t.setDaemon(false); // 創建一個非守護線程
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY); // 線程優先級設置為默認值
            return t;
        }
    }
    
  • RejectedExecutionHandler

    • 表示指定線程池的拒絕策略,當線程池的任務已經在緩存隊列 workQueue 中存儲滿了之後,並且不能創建新的線程來執行此任務時,就會用到此拒絕策略.
    • 它屬於一種限流保護的機制,這裡有四種任務拒絕類型:
      1. AbortPolicy: 不執行新任務,直接拋出異常,提示線程池已滿,涉及到該異常的任務也不會被執行,線程池默認的拒絕策略就是該策略。
      2. DisCardPolicy: 不執行新任務,也不拋出異常,即忽略此任務;
      3. DisCardOldSetPolicy: 將消息隊列中的第一個任務(即等待時間最久的任務)替換為當前新進來的任務執行,忽略最早的任務(最先加入隊列的任務);
      4. CallerRunsPolicy: 把任務交給當前線程來執行;
    /**
     * 線程池的拒絕策略
     */
    @Test
    public void test1() {
        // 創建線程池 核心線程為1,最大線程為3,任務隊列大小為2
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(1, 3, 10,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(2),
                new ThreadPoolExecutor.AbortPolicy() // 添加 AbortPolicy 拒絕策略
        );
    
    
        for (int i = 0; i < 6; i++) {
            poolExecutor.execute(() -> {
                System.out.println(Thread.currentThread().getName());
            });
        }
        
    }
    
    • 自定義線程池拒絕策略
    /**
     * 自定義線程池的拒絕策略
     * 實現接口 RejectedExecutionHandler
     */
    @Test
    public void test2() {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 3, 10,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(2),
                new RejectedExecutionHandler() {
    
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        // 業務處理方法
                        System.out.println("執行自定義拒絕策略");
                    }
                }
        );
    
        for (int i = 0; i < 6; i++) {
            executor.execute(() -> {
                System.out.println(Thread.currentThread().getName());
            });
        }
    
    }
    

線程池工作原理

線程池的工作流程要從它的執行方法 execute() 說起,源碼如下:

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    // 當前工作的線程數小於核心線程數
    if (workerCountOf(c) < corePoolSize) {
        // 創建新的線程執行此任務
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // 檢查線程池是否處於運行狀態,如果是則把任務添加到隊列
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        // 再出檢查線程池是否處於運行狀態,防止在第一次校驗通過後線程池關閉
        // 如果是非運行狀態,則將剛加入隊列的任務移除
        if (! isRunning(recheck) && remove(command))
            reject(command);
        // 如果線程池的線程數為 0 時(當 corePoolSize 設置為 0 時會發生)
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false); // 新建線程執行任務
    }
    // 核心線程都在忙且隊列都已爆滿,嘗試新啟動一個線程執行失敗
    else if (!addWorker(command, false)) 
        // 執行拒絕策略
        reject(command);
}

execute() VS submit()

  • execute() 和 submit() 都是用來執行線程池任務的,它們最主要的區別是,submit() 方法可以接收線程池執行的返回值,而 execute() 不能接收返回值。
  • sumbit 之所以可以接收返回值,是因為參數中可以傳遞:Callable task,而通過 callable 創建的線程任務有返回值並且可以拋出異常。
/**
 * execute VS sumbin
 * execute 提交任務沒有返回值
 * submit 提交任務有返回值
 */
@Test
public void test3() throws ExecutionException, InterruptedException {
    ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(20));
    // execute
    executor.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println("Hello, execute");
        }
    });

    // submit 使用
    Future<String> future = executor.submit(new Callable<String>() {
        @Override
        public String call() throws Exception {
            System.out.println("Hello, submit");
            return "submit success";
        }
    });
    System.out.println(future.get());
}
  • 它們的另一個區別是 execute() 方法屬於 Executor 接口的方法,而 submit() 方法則是屬於 ExecutorService 接口的方法。

線程池的使用:

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author xiandongxie
 */
public class ThreadPool {

    //參數初始化 返回Java虛擬機可用的處理器數量
//    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CPU_COUNT = 2;
    //核心線程數量大小
    private static final int corePoolSize = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    //線程池最大容納線程數
    private static final int maximumPoolSize = CPU_COUNT * 2 + 1;
    //線程空閑后的存活時長
    private static final int keepAliveTime = 30;

    //任務過多后,存儲任務的一個阻塞隊列
    BlockingQueue<Runnable> workQueue = new SynchronousQueue<>();

    //線程的創建工廠
    ThreadFactory threadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AdvacnedAsyncTask #" + mCount.getAndIncrement());
        }
    };

    //線程池任務滿載后採取的任務拒絕策略: 不執行新任務,直接拋出異常,提示線程池已滿
    RejectedExecutionHandler rejectHandler = new ThreadPoolExecutor.AbortPolicy();

    //線程池對象,創建線程
    ThreadPoolExecutor mExecute = new ThreadPoolExecutor(
            corePoolSize,
            maximumPoolSize,
            keepAliveTime,
            TimeUnit.SECONDS,
            workQueue,
            threadFactory,
            rejectHandler
    );

    public static void main(String[] args) {
        System.out.println("main start ..... \nCPU_COUNT = " + CPU_COUNT + "\tcorePoolSize=" + corePoolSize + "\tmaximumPoolSize=" + maximumPoolSize);
        
        ThreadPool threadPool = new ThreadPool();
        ThreadPoolExecutor execute = threadPool.mExecute;
        // 預啟動所有核心線程
        execute.prestartAllCoreThreads();

        for (int i = 0; i < 5; i++) {
            execute.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "\tstart..." + System.currentTimeMillis());
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "\tend..." + System.currentTimeMillis());
                }
            });
        }
        execute.shutdown();
        
        System.out.println("main end .....");
    }
}

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

【其他文章推薦】

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

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

※想知道最厲害的網頁設計公司“嚨底家”!

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

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

聚甘新

跨雲廠商部署 k3s 集群

原文鏈接:https://fuckcloudnative.io/posts/deploy-k3s-cross-public-cloud/

最近一兩年各大雲服務商都出了各種福利活動,很多小夥伴薅了一波又一波羊毛,比如騰訊雲 1C2G 95/年 真香系列,華為雲和阿里雲也都有類似的活動,薅個兩三台就能搭建一個 Kubernetes 集群。但是跨雲服務商搭建 Kubernetes 集群並不像我們想象中的那麼容易,首先就是原生的 Kubernetes 組件本身對資源的消耗量很大,而雲服務器的資源非常有限,經不起這麼大傢伙的折騰,對此我們可以選擇使用輕量級 Kubernetes 發行版:k3s

k3s 將安裝 Kubernetes 所需的一切打包進僅有 60MB 大小的二進制文件中,並且完全實現了 Kubernetes API。為了減少運行 Kubernetes 所需的內存,k3s 刪除了很多不必要的驅動程序,並用附加組件對其進行替換。由於它只需要極低的資源就可以運行,因此它能夠在任何 512MB 內存以上的設備上運行集群。

其實 k3s 的安裝非常簡單,分分鐘就能搞定,但對於公有雲來說,還是有很多坑的,比如內網不通、公網 IP 不在服務器上該咋辦?本文就為你一一解決這些難題,讓天下的雲羊毛都成為 k3s 的後宮!

1. 下載二進制文件

首先來解決第一個難題:k3s 二進制文件的下載。國內下載 GitHub 速度基本都是以幾個 kb 為單位,不忍直視,如果下載內容都是代碼,有很多辦法可以解決,比如通過碼雲中轉啊、直接通過 CDN 下載啊,什麼?你不知道可以通過 CDN 下載?好吧沒關係,現在我告訴你了:https://cdn.con.sh/。

但是上面的 CDN 並不能下載 release 里的內容,要想下載 release 里的內容,可以使用這個網站:https://toolwa.com/github/。打開網站,輸入 release 裏面的文件下載鏈接,點擊起飛即可加速下載。

當然,如果你會魔法上網的話,上面的所有花里胡哨的方法都可以無視,直接下載就好啦(本文選擇使用版本 v1.17.6+k3s1):

$ wget https://github.com/rancher/k3s/releases/download/v1.17.6+k3s1/k3s -O /usr/local/bin/k3s
$ chmod +x /usr/local/bin/k3s

需要在所有節點中下載上述二進制文件。

2. 升級內核

k3s 的默認網絡插件是 flannel,默認模式是 vxlan 模式,建議使用 wireguard 模式,原因不解釋了,不知道 wireguard 是啥的自己去搜一下。

wireguard 對內核的要求比較高,而 CentOS 7.x 的默認內核是不滿足要求的,需要升級內核(如果你的操作系統是 CentOS 7.x 的話)。步驟如下:

① 載入公鑰

$ rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org

② 升級安裝 elrepo

$ rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm

③ 載入 elrepo-kernel 元數據

$ yum --disablerepo=\* --enablerepo=elrepo-kernel repolist

④ 安裝最新版本的內核

$ yum --disablerepo=\* --enablerepo=elrepo-kernel install  kernel-ml.x86_64  -y

⑤ 刪除舊版本工具包

$ yum remove kernel-tools-libs.x86_64 kernel-tools.x86_64  -y

⑥ 安裝新版本工具包

$ yum --disablerepo=\* --enablerepo=elrepo-kernel install kernel-ml-tools kernel-ml-devel kernel-ml-headers -y

⑦ 查看內核插入順序

$ grep "^menuentry" /boot/grub2/grub.cfg | cut -d "'" -f2

CentOS Linux (3.10.0-1127.10.1.el7.x86_64) 7 (Core)
CentOS Linux (5.7.2-1.el7.elrepo.x86_64) 7 (Core)
CentOS Linux (0-rescue-96820b9851c24560b5f942f2496b9aeb) 7 (Core)

默認新內核是從頭插入,默認啟動順序也是從 0 開始。

⑧ 查看當前實際啟動順序

$ grub2-editenv list

saved_entry=CentOS Linux (3.10.0-1127.10.1.el7.x86_64) 7 (Core)

⑨ 設置默認啟動

$ grub2-set-default 'CentOS Linux (5.7.2-1.el7.elrepo.x86_64) 7 (Core)'

最後重啟檢查:

$ reboot
$ uname -r

注意:集群中的所有節點都需要升級內核。

3. 安裝 wireguard

內核升級了之後,就可以安裝 wireguard 了,也很簡單,步驟如下:

$ yum install epel-release https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
$ yum install yum-plugin-elrepo
$ yum install kmod-wireguard wireguard-tools

注意:集群中的所有節點都需要安裝。

4. 部署控制平面

下面就可以在控制節點上啟動控制平面的組件了,這裏我們選擇手動部署,這樣比較方便修改參數。先創建一個 Service Unit 文件:

$ cat > /etc/systemd/system/k3s.service <<EOF
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
Wants=network-online.target

[Install]
WantedBy=multi-user.target

[Service]
Type=notify
EnvironmentFile=/etc/systemd/system/k3s.service.env
KillMode=process
Delegate=yes
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=always
RestartSec=5s
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s \
    server \
    --tls-san <public_ip> \
    --node-ip <public_ip> \
    --node-external-ip <public_ip> \
    --no-deploy servicelb \
    --flannel-backend wireguard \
    --kube-proxy-arg "proxy-mode=ipvs" "masquerade-all=true" \
    --kube-proxy-arg "metrics-bind-address=0.0.0.0"
EOF
  • <public_ip> 替換成控制節點的公網 IP。
  • flannel 使用 wireguard 協議來跨主機通信。
  • kube-proxy 使用 ipvs 模式。

啟動 k3s 控制平面並設置開機自啟:

$ systemctl enable k3s --now

查看集群組件健康狀況:

$ kubectl get cs

NAME                 STATUS    MESSAGE   ERROR
scheduler            Healthy   ok
controller-manager   Healthy   ok

這裏的輸出沒有 etcd,因為 k3s 的默認數據存儲是 Sqlite,對於小型數據庫十分友好。Kubernetes 控制平面中發生的更改更多是與頻繁更新部署、調度 Pod 等有關,因此對於幾個節點的小型集群而言,數據庫不會造成太大負載,能省下不少資源,真香!

5. 加入計算節點

部署好控制平面之後,就可以加入計算節點了。首先在計算節點上創建 Service Unit 文件:

$ cat > /etc/systemd/system/k3s-agent.service <<EOF
[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
Wants=network-online.target

[Install]
WantedBy=multi-user.target

[Service]
Type=exec
EnvironmentFile=/etc/systemd/system/k3s-agent.service.env
KillMode=process
Delegate=yes
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=always
RestartSec=5s
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s agent \
    --node-external-ip <public_ip> \
    --node-ip <public_ip> \
    --kube-proxy-arg "proxy-mode=ipvs" "masquerade-all=true" \
    --kube-proxy-arg "metrics-bind-address=0.0.0.0"
EOF

環境變量文件 /etc/systemd/system/k3s-agent.service.env 中需要加入兩個環境變量:

  • K3S_URL : API Server 的 URL,一般格式為:https://<master_ip>:6443。其中 <master_ip> 是控制節點的公網 IP。
  • K3S_TOKEN : 加入集群所需的 token,可以在控制節點上查看 /var/lib/rancher/k3s/server/node-token 文件。

/etc/systemd/system/k3s-agent.service.env 內容如下:

K3S_URL=https://<master_ip>:6443
K3S_TOKEN=xxxxxxxx

啟動 k3s-agent 並設置開啟自啟:

$ systemctl enable k3s-agent --now

查看節點狀態:

$ kubectl get node

NAME         STATUS   ROLES    AGE     VERSION
blog-k3s01   Ready    master   3d6h    v1.17.6+k3s1
blog-k3s02   Ready    <none>   3d3h    v1.17.6+k3s1

6. 內網不互通的解決辦法

這裡會遇到一個問題,不同節點的 flannel 使用的是內網 IP 來進行通信,而我們的雲服務器是內網不互通的,而且公網 IP 也不在服務器上。可以看一下 node 的 annotations

$ kubectl get node blog-k3s02 -o yaml

apiVersion: v1
kind: Node
metadata:
  annotations:
    flannel.alpha.coreos.com/backend-data: '"xxxxx"'
    flannel.alpha.coreos.com/backend-type: extension
    flannel.alpha.coreos.com/kube-subnet-manager: "true"
    flannel.alpha.coreos.com/public-ip: 192.168.0.11
    ...

可以看到 flannel 給節點打的註解中的節點 IP 是內網 IP。要想讓 flannel 使用公網 IP 進行通信,需要額外添加一個註解 public-ip-overwrite,然後 flannel 會基於這個 IP 配置網絡。按照官方文檔的說法,如果你的 node 設置了 ExternalIP,flannel 會自動給 node 添加一個註解 public-ip-overwrite,但我不知道該如何給 node 設置 ExternalIP,乾脆就直接手動加註解吧:

$ kubectl annotate nodes <master> flannel.alpha.coreos.com/public-ip-overwrite=<master_pub_ip>
$ kubectl annotate nodes <node> flannel.alpha.coreos.com/public-ip-overwrite=<node_pub_ip>

加了註解之後,flannel 的 public-ip 就會被修改為公網 IP。然後在各個節點上重啟各自的 k3s 服務,查看 wireguard 連接狀況:

$ wg show flannel.1

interface: flannel.1
  public key: ONDgJCwxxxxxxxJvdWpoOKTxQA=
  private key: (hidden)
  listening port: 51820
  
peer: MKKaanTxxxxxxxV8VpcHq4CSRISshw=
  endpoint: <pub_ip>:51820
  allowed ips: 10.42.4.0/24
  latest handshake: 26 seconds ago
  transfer: 133.17 KiB received, 387.44 KiB sent
  persistent keepalive: every 25 seconds

可以看到通信端點被改成了公網 IP,大功告成!

7. metrics-server 問題解決

還有一個問題就是 metrics-server 無法獲取 cpu、內存等利用率核心指標。需要修改 metrics-server 的 manifests,使用以下命令在線編輯 metrics-server 的 manifests:

$ kubectl -n kube-system edit deploy metrics-server

然後加入以下執行參數后保存退出:

      -command:
        - /metrics-server
        - --kubelet-preferred-address-types=ExternalIP
        - --kubelet-insecure-tls

這樣就可以讓 metrics-server 使用公網 IP 來和 node 通信了。修改成功后就可以看到核心指標了:

$ kubectl top nodes
NAME         CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
blog-k3s01   193m         9%     886Mi           22%
blog-k3s02   41m          2%     1292Mi          32%

$ kubectl top pod -n kube-system
NAME                                      CPU(cores)   MEMORY(bytes)
coredns-848b6cc76f-zq576                  8m           14Mi
local-path-provisioner-58fb86bdfd-bzdfl   2m           9Mi
metrics-server-bdfc79c97-djmzk            1m           12Mi

到這裏跨雲服務商部署 k3s 基本上就大功告成了,下一篇文章將會教你如何打通家裡到雲上 k3s 的網絡,讓你家中所有設備都可以直接訪問 Pod IP、svc IP,甚至可以直接訪問 svc 域名,敬請期待。

Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12離線安裝包發布地址http://store.lameleg.com ,歡迎體驗。 使用了最新的sealos v3.3.6版本。 作了主機名解析配置優化,lvscare 掛載/lib/module解決開機啟動ipvs加載問題, 修復lvscare社區netlink與3.10內核不兼容問題,sealos生成百年證書等特性。更多特性 https://github.com/fanux/sealos 。歡迎掃描下方的二維碼加入釘釘群 ,釘釘群已經集成sealos的機器人實時可以看到sealos的動態。

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

聚甘新

這樣用技術,程序猿更幸福

作為久經職場而又富有責任心的猿外,每天上班的第一件事,便是連上生產服務器,top free ps 一頓命令熱身猛如虎,然後匯總出業務服務的狀態、系統指標等,看到一切正常,心裏才算踏實。

不知道有多少盡職盡責的朋友們,每天都重複的做着如此机械而又簡單的事情。說句實話,其實和机械狗沒啥區別。本着做事認真、追求極致的態度,那我們為什麼不能打造一款這樣的机械狗呢?

關注過猿外的朋友們都應該知道,在之前的文章中,猿外曾經提到過,守護服務的監控應用——看門狗。不錯,要打造的机械狗,就是看門狗。

接下來就給大家簡單聊一聊,看門狗的背景來源以及實現思路,希望能給正在尋找守護服務監控解決方案的朋友們,一點實現思路。下面的內容十分燒腦,請大家坐穩扶好。

1. 什麼是看門狗?

在由單片機構成的微型計算機系統中,由於單片機的工作,常常會受到來自外界電磁場的干擾,造成程序的跑飛,而陷入死循環,程序的正常運行被打斷,由單片機控制的系統無法繼續工作,會造成整個系統的陷入停滯狀態,發生不可預料的後果,所以出於對單片機運行狀態進行實時監測的考慮,便產生了一種專門用於監測單片機程序運行狀態的芯片,稱“看門狗”——摘自“百度百科”。

相信有不少朋友,看到上面一段非人話的描述,就想直接刪了此篇熊文,溜之大吉。大家,心莫慌,猿外再舉個貼近生活的栗子解釋一下。

猿外家養了一條 dog ,經常陪孩子玩,孩子時不時的撒一把狗糧給 dog;
如果孩子睡着,長時間未撒狗糧,dog 就主動把孩子叫醒;
繼續讓孩子撒狗糧,然後 dog 吃到孩子撒的狗糧,就高興的狂吠;
如果 dog 跑走了,孩子也不撒狗糧了,孩子也就可以睡覺了。

剝開栗子,內行看門道,外行看熱鬧,把上面內容翻譯一遍:

原話:猿外家養了一條 dog,經常陪孩子玩,孩子時不時的撒一把狗糧給 dog;
翻譯:存在兩個進程:子進程(應用服務)、父進程(守護進程),子進程和父進程兩個進程間一直保持心跳通訊;

原話:如果孩子睡着,長時間未撒狗糧, dog 就主動把孩子叫醒;
翻譯:子進程與父進程心跳通訊中斷,父進程則負責啟動子進程,完成子進程的服務守護;

原話:繼續讓孩子撒狗糧,然後 dog 吃到孩子撒的狗糧,就高興的狂吠;
翻譯:子進程與父進程實時通訊,父進程實時監控子進程的狀態,並實時進行報警通知;

原話:如果 dog 跑走了,孩子也不撒狗糧了,孩子也就可以睡覺了。
翻譯:父進程down了,子進程與父進程的通訊也就無法保持了,子進程也一併退出。

不知道朋友們通過上面的栗子剖析,對看門狗了解了多少呢?為了更清晰的給你們說清楚,猿外再給大家上個一目瞭然的圖吧。

如上圖所示,猿外主要把看門狗定位為:集服務守護、指標採集、日誌歸集、自動化報警於一體的監控系統。說白了,有了看門狗,媽媽再也不用擔心我的應用服務出問題了。

洋洋洒洒鋪墊這麼多,那到底該如何實現呢?

2. 如何實現?

猿外先給大家畫個腦圖,主要分五步走,希望朋友們跟着猿外的腳步,莫掉隊。

相信絕大部分朋友通過猿外的腦圖,已經對看門狗應用了解個八九不離十。猿外再稍微闡述一下:

實現方式:看門狗應用在實現過程中也走了一些彎路。剛開始技術選型的時候,考慮到看門狗應該對應用零侵入、低耦合,於是採用javaagent植入方式進行實現,但是萬萬沒想到的是開發、調試過程比較麻煩,一遇到問題,小夥伴就排查半天,在第一版上線后,猿外迅速帶領小夥伴,採用插件化方式進行第二版迭代。

服務守護:採用 J2SE 1.5 java.lang 包中新添加的 ProcessBuilder 類來完成子進程的啟動、停止、重啟(完成子服務的守護功能)。

指標採集:通過 JMX 方式連接子服務,獲取子服務的內存佔用、CPU 使用、線程數等指標。

日誌歸集:主要站在 flume 的肩膀上,集成到項目中並進行二次開發,存儲採用 elasticsearch。

報警通知:主要提供郵箱通知、QQ 通知、微信實時通知。

其中每個實現細節猿外就不再進行深入展開了,感興趣的朋友歡迎關注微信公眾號四猿外(si-yuanwai),後台留言進行交流。

羅里吧嗦,寫了這麼多。羅馬並非一日建成的,實現途中踩過的坑、吃過的苦頭,剎那間全部湧上心頭。不過看門狗應用,已經在生產上推廣使用,自上線以來還廣受好評,猿外現在每天來的第一件事,由原來的系統巡檢變成了沖咖啡,幸福指數陡然上升。

最後,猿外想說的是:簡單的事重複做,你就是專家;重複的事用心做,你就是贏家。沒錯,這話說的沒毛病,不過成為專家之餘,大家不妨稍做創新,看看有沒有可以用的技術輪子,說不定會改變机械的工作方式,提升工作效率,提高幸福指數呢。

歡迎大家關注我的公眾號:四猿外。
我準備了一些純手打的高質量PDF,有好友贊助的也有我自己的,大家可以免費領取:
深入淺出Java多線程、HTTP超全匯總、Java基礎核心總結、程序員必知的硬核知識大全、簡歷面試談薪的超全乾貨。
別看數量不多,但篇篇都是乾貨,看完的都說很肝。

領取方式:掃碼關注后,在公眾號後台回復:666

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

【其他文章推薦】

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

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

※想知道最厲害的網頁設計公司“嚨底家”!

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

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

聚甘新

測試人員遇到Android APP崩潰和無響應手足無措?,基於Python的Appium環境搭建合集

這2天,在測APP兼容性時,遇到APP奔潰閃退的情況。將問題反饋給開發后,開發自己調試后,沒有復現。由於又是遠程,base地不在一塊,我總不能把手機寄過去吧,那也太費事了。

所以就想到,提供明確的報錯日誌,讓開發定位問題,豈不是就很方便了,也解決了遠程的問題。

那如何抓取到Crash日誌呢,我又沒開發調試工具,也不可能在短時間內搭建一套開發環境。尋思答案后,最終得到了完美解決,且聽細細道來。

了解Crash

我們先來簡單了解下Crash:Crash,就是崩潰。anr(Application Not Responding — 程序無響應)是Crash的一種。程序正常運行中,可能會出現未捕獲到的異常,這就會造成崩潰。

常見Crash異常

NullPointerException  空指針

ClassCastException  類型轉換異常

IndexOutOfBoundsException  下標越界異常

ActivityNotFoundException Activity  未找到異常

IllegalStateException  非法狀態異常

ArrayIndexOutOfBoundsException  數組越界異常

SecurityException  安全異常

NoSuchMethodException  方法未找到異常

SQLException  操作數據庫異常

抓取奔潰和無響應日誌

對於開發人員來說,抓取日誌是很方便的,但對於測試人員來說,就不是太方便了。大多都是直接dos窗口下執行adb命令來抓取日誌,而每次都敲命令也是很麻煩。

所以通過adb程序與bat命令組合使用來抓取日誌,就要方便很多了,短短几秒鐘,可以輕鬆搞定日誌的抓取,期不期待。

環境準備

安裝JDK和ADB,這個安裝很簡單,可參見以前的博文,基於Python的Appium環境搭建合集。

bat文件製作

環境準備好后,就來寫bat文件了。

捕獲Crash異常的bat文件命令

命令參考如下,製作成logcat.bat文件,logcat.bat文件可以放置任意位置。注意:如果adb沒有配置到環境變量中,則需要將logcat.bat文件放到adb對應文件夾中。

@ECHO OFF
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"

SET timeStamp=%dt:~0,4%-%dt:~4,2%-%dt:~6,2%_%dt:~8,2%-%dt:~10,2%-%dt:~12,2%
SET mutID=_mut

@ECHO ON
adb logcat -v time > .\"%mutID%_%timeStamp%_logcat.log"

pause

上述命令實現原理:該工具的原理是bat文件調用adb工具,將手機運行日誌拉到本地,並將實時日誌也記錄到本地。

當手機需要重現Crash、或者某一段時間內已經發生過Crash,點擊我們製作的bat文件,logcat文件中的命令會將手機的logcat日誌拉下來並實時記錄,直到你關閉cmd窗口。

然後在拉下來的txt中尋找FATAL關鍵字,附近上下文即為Crash日誌。

捕獲ANR異常的bat文件命令

anr:全稱為Application Not Responding,意思為程序無響應。

命令參考如下,製作成anr.bat文件,anr.bat文件可以放置任意位置。注意:如果adb沒有配置到環境變量中,則需要將anr.bat文件放到adb對應文件夾中。

@ECHO OFF
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
SET timeStamp=%dt:~0,4%-%dt:~4,2%-%dt:~6,2%_%dt:~8,2%-%dt:~10,2%-%dt:~12,2%
SET mutID=_mut
@ECHO ON
adb pull data/anr/traces.txt traces_%timeStamp%.txt

實現原理與捕獲Crash異常是一樣的,只是該命令是針對發生anr的情況。

具體實踐

捕獲Crash異常具體用法:

①將android手機連接電腦,開啟開發者模式並允許usb調試;

②運行logcat.bat文件

③如果手機程序已經發生過crash,10秒后關閉cmd窗口;如果是想重現crash,則在手機端重現后即可關閉cmd窗口;

④在logcat.bat的同級目錄下會生成一份log文件,從文件中搜查FATAL關鍵字,便可找到崩潰代碼。

查看報錯日誌,報錯如下所示:

如上所示截圖,就是測試過程中,發生奔潰的日誌了,將日誌貼在bug里,既方便開發排查問題,又節約協作時間。

使用優點

使用bat文件捕獲日誌,有如下幾個有點:手機無需root;無需開發環境支持;方便保存、查找日誌;操作簡單。

以上就是捕獲報錯日誌的操作步驟了,希望對有需要的博友有所幫助。

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

聚甘新

中國大陸電動車價格遭砍,影響股價

韓國同意美國佈署薩德飛彈防禦系統之後,頻遭中國報復,之前韓國電動車電池商遭到鎖定,被踢出中國補助名單之外。近來北京又出新招,據傳中國電動車商可能要求電池供應商砍價35~40%,韓商更難獲利,電池大廠三星SDI (Samsung SDI) 聞訊一度重挫 4%。

嘉實全球贏家系統報價顯示,台北時間 19 日中午 11 點 26 分,三星SDI股價大跌 4.44%、報 107,500 韓圜。另一韓國電池廠 LG Chem 也挫低 1.29%、報 268,000 韓圜。

巴倫 (Barron’s) 18日報導,摩根士丹利(大摩)分析師Shawn Kim報告稱,中國高工產業研究院宣稱,部分中國電動車商要求電池業者,今年電池價格下砍35~40%。大摩中國分析師Jack Lu認為,中國電池商大砍價格之後,仍有可觀獲利,此一方案可望繼續推動,如此一來,或許會壓縮三星 SDI 毛利。

中國處處設限,電池大砍價,北京又打算把合格電池廠的生產門檻一口氣增至8GWh,韓商生存空間大受打壓。不只如此,三星SDI供應三星Galaxy S8電池的利多,市場也反應過頭。大摩估計S8對三星SDI營收貢獻只有 4~6%。

美國、南韓去(2016)年7月宣布在韓部署「薩德」(THAAD) 反導彈系統之後,中國就開始積極抵制南韓,車用電池大廠LG Chem、三星SDI (Samsung SDI)首當其衝。中國工信部(MIIT)最新公布的第五批新能源汽車推薦目錄中,將內建LG Chem、三星SDI電池的電動車全部剔除。也就是說,所有內建韓系電池的新能源車,都已不再符合北京政府的推薦標準。

Maeil Business News Korea、Business Korea等外電2日報導,在工信部最新列出的493款新能源車推薦名單當中,沒有一款內建LG Chem、三星SDI的車用電池。

巴倫 (Barron’s)、BusinessKorea報導,中國工信部去年11月22日發布《汽車動力電池行業規範條件》修正草案,有意把合格電池廠的生產門檻,從 0.2GWh 至 8GWh,等於一口氣提高 40 倍之多。這也是向廠商喊話,若不在中國生產,就別想做中國生意。

韓媒認為,北京當局此舉是要阻止韓商跨入中國市場,原因之一是要報復南韓和美國合作,佈建薩德 (THAAD) 飛彈防禦系統;另一可能是陸電池廠缺乏補助,政府排除外商競爭,保護本國產業。8GWh 電池產能可供13萬輛純電動車使用,當前 LG Chem 南京廠產能只夠5萬輛電動車使用,三星 SDI 西安廠則可供 4 萬輛電動車使用。據稱符合 8GWh 規定的業者只有兩家,其中之一是陸廠比亞迪 (BYD)。

(本文內容由權使用。圖片出處:Pixabay CC0)

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

【其他文章推薦】

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

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

※想知道最厲害的網頁設計公司"嚨底家"!

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

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

Gogoro 願景:6都 1 公里 1 換電站,觸角伸至屏東

智慧電動機車Gogoro 開賣至18 個月,總共賣出1 萬7000 台車,營運版圖也從一開始的雙北,研伸至高雄。在嶄新的2017 年開始之際,Gogoro 19日宣布新目標是「更廣、更密集的能源網路」,六大都會區電池交換站密度達平均每1 公里1 站,各縣市的次級鄉鎮市平均每8 至16 公里1 站,並將營運版圖延伸至屏東,讓使用者可以完成基隆屏東西部縱走,並在換電站密度不足的台南、高雄推出「家用充電試營運計畫 」。

 

Gogoro 2016 年表現及2017 年願景:

Gogoro 行銷總監陳彥揚表示,Gogoro 在開賣18 個月共賣出1 萬7000 台車,在2016 年賣出逾1 萬3000 台,這數字反應出台灣作為Gogoro 能源網路全球第一個試點國家,展現對於新科技、新能源、新移動方式的擁抱態度。由於已經將營運版圖延伸到整個西台灣,Gogoro 希望在2017 年Gogoro 電動機車的銷量能有倍數成長。

Gogoro 營運版圖從一開始的雙北,往北向基隆、往南向中南部延伸,2015 年底到新竹,2016 年5 月到台中、11月到台南、12 月到高雄。而換電站也累積至289 站點,光是雙北就累積有120 站,平均每800 公尺就有一站;在2017 年,Gogoro 的目標是六大都會區電池交換站密度達1 公里1 站, 各縣市的次級鄉鎮市平均每8 至16 公里1 站。

另一項值得關注的數字是,2016 年Gogoro 電動機車銷量13038 台,首度超越輕型電動機車銷量7881 台,來到黃金交叉。Gogoro 為125CC 汽油機車性能等級的電動機車,現在市面上的汽油機車有70%~80% 都在125 CC 以上,可見雙輪族對於125 CC 等級的機車有強大需求,而市面上性能唯一達到125 CC 等級的電動機車只有Gogoro,符合市場需求,因此Gogoro 有機會競爭汽油機車一年近80 萬台的銷售數量。

  • 賣出13000+ 台以上Gogoro 電動機車
  • 消費者騎乘Gogoro 總里程數4316 萬公里
  • 減少二氧化碳排放量397 萬公斤
  • 節省汽油205 萬公升
  • Gogoro 電動機車年銷量(13038 台)首度超越輕型電動機車(7881 台,即市面上Gogoro 以外的電動機車)

 

台南、高雄充電站密度不足,推出Gogoro 家用充電試營運計畫:

不過,目前部分地區換電站密度不足,尤其是剛進入的台南和高雄兩縣市的蛋白區。由於有換電站的地方才有Gogoro 的機車,但機車數量夠多才會有更密集的換電站,陳彥揚形容,這是個雞生蛋蛋生雞的困難問題,因此在剛跨入、換電站數量還不夠密集的台南和高雄兩縣市,Gogoro 推出「家用充電試營運計畫 」,以優惠的方案租給消費者家用充電器GoCharger,解決台南和高雄地區想購買Gogoro 機車、但是生活周遭換電站仍不足的消費者的充電問題,希望能夠增加消費者購車意願。

但「家用充電試營運計畫 」的租期只有6 個月,只是接軌期的替代方案,陳彥揚表示,換電站仍是Gogoro 的核心,也相信6 秒快速換電池對消費者來說絕對比充電方便,而Gogoro 今年上半年會優先布建台南、高雄換電站密度不足的區域。

 

Gogoro 家用充電試營運計畫活動辦法:

申請期間:1 月19 日至4 月20日

指定區域:2017 年度台南及高雄即將建置換電站之預定地區

試營運計劃期間優惠限定方案:

GoCharger® 標準座月租費NT$149(每月再贈送50 公里免費里程);

GoCharger® Plus 快充座月租費NT$249(每月再贈送50 公里免費里程)。

承租GoCharger® 智慧電池座須繳交押金NT$2,990,約滿歸還GoCharger® 智慧電池座時可領回。

活動網址:http://www.gogoro.com/tw/event/gocharger-beta/
 

(合作媒體:。圖片出處:)

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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