【asp.net core 系列】12 數據加密算法

0. 前言

這一篇我們將介紹一下.net core 的加密和解密。在Web應用程序中,用戶的密碼會使用MD5值作為密碼數據存儲起來。而在其他的情況下,也會使用加密和解密的功能。

常見的加密算法分為對稱加密和非對稱加密。所謂的對稱加密是指加密密鑰和解密密鑰是同一個,非對稱加密是值加密密鑰和解密迷藥不同。而我們常應用在保存用戶登錄密碼這個過程中的MD5本質上並不是加密算法,而是一種信息摘要算法。不過MD5盡量保證了每個字符串最後計算出來的值都不一樣,所以在密碼保存中常用MD5做為保密值。

1. 常見對稱加密算法

對稱加密算法,簡單的說就是加密和解密使用相同的密鑰進行運算。對於大多數加密算法,解密和加密是一個互逆的運算。對稱加密算法的安全性取決於密鑰的長度,密鑰越長越安全。當然,不建議使用過長的密鑰。

那麼,我們來看看常見的對稱加密算法有哪些吧,以及C#該如何實現。

1.1 DES 和 DESede 算法

DES算法和DESede算法(又稱三重DES算法) 統稱DES系列算法。DES全稱為Data Encryption Standard,即數據加密標準,是一種使用密鑰加密的塊算法。而DESede就是針對同一塊數據做三次DES加密。這裏就不對原理做過多的介紹了,來看看.net core里如何實現DES加/解密吧。

在Utils項目里,創建目錄Security

在Security目錄下,創建DESHelper類:

namespace Utils.Security
{
    public class DesHelper
    {
        
    }
}

加密解密實現:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Utils.Security
{
    public static class DesHelper
    {
        static DesHelper()
        {
            DesHandler =  DES.Create("DES");
            DesHandler.Key = Convert.FromBase64String("L1yzjGB2sI4=");
            DesHandler.IV = Convert.FromBase64String("uEcGI4JSAuY=");
        }

        private static DES DesHandler { get; }

        /// <summary>
        /// 加密字符
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string Encrypt(string source)
        {
            try
            {
                using (var memStream = new MemoryStream())
                using (var cryptStream = new CryptoStream(memStream, DesHandler.CreateEncryptor(DesHandler.Key, DesHandler.IV),
                    CryptoStreamMode.Write))
                {
                    var bytes = Encoding.UTF8.GetBytes(source);
                    cryptStream.Write(bytes, 0, bytes.Length);
                    cryptStream.FlushFinalBlock();
                    
                    return Convert.ToBase64String(memStream.ToArray());
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return null;
            }
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string Decrypt(string source)
        {
            try
            {
                using (var mStream = new MemoryStream(Convert.FromBase64String(source)))
                using (var cryptoStream =
                    new CryptoStream(mStream, DesHandler.CreateDecryptor(DesHandler.Key, DesHandler.IV), CryptoStreamMode.Read))
                using (var reader = new StreamReader(cryptoStream))
                {
                    return reader.ReadToEnd();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return null;
            }
        }
    }
}

每次調用DesHandler = DES.Create("DES"); 都會重新獲得一個DES算法實現實例,這樣每次獲取的實例中Key、IV這兩個屬性的值也會發生變化。如果直接使用會出現這次加密的數據下次就沒法解密了,為了減少這種情況,所以代碼處手動賦值了Key、IV這兩個屬性。

1.2 AES 加密算法

AES算法(Advanced Encryption Standard)也就是高級數據加密標準算法,是為了解決DES算法中的存在的漏洞而提出的算法標準。現行的AES算法核心是Rijndael算法。當然了,這個不用太過於關心。我們直接看看是如何實現吧:

同樣,在Security目錄創建一個AesHelper類:

namespace Utils.Security
{
    public static class AesHelper
    {
        
    }
}

具體的加解密實現:

using System;
using System.IO;
using System.Security.Cryptography;

namespace Utils.Security
{
    public static class AesHelper
    {
        static AesHelper()
        {
            AesHandler = Aes.Create();
            AesHandler.Key = Convert.FromBase64String("lB2BxrJdI4UUjK3KEZyQ0obuSgavB1SYJuAFq9oVw0Y=");
            AesHandler.IV = Convert.FromBase64String("6lra6ceX26Fazwj1R4PCOg==");
        }

        private static Aes AesHandler { get; }

        public static string Encrypt(string source)
        {
            using (var mem = new MemoryStream())
            using (var stream = new CryptoStream(mem, AesHandler.CreateEncryptor(AesHandler.Key, AesHandler.IV),
                CryptoStreamMode.Write))
            {
                using (var writer = new StreamWriter(stream))
                {
                    writer.Write(source);
                }   
                return Convert.ToBase64String(mem.ToArray());
            }
            
        }

        public static string Decrypt(string source)
        {
            var data = Convert.FromBase64String(source);
            using (var mem = new MemoryStream(data))
            using (var crypto = new CryptoStream(mem, AesHandler.CreateDecryptor(AesHandler.Key, AesHandler.IV),
                CryptoStreamMode.Read))
            using (var reader = new StreamReader(crypto))
            {
                return reader.ReadToEnd();
            }
        }
    }
}

2. 常見非對稱加密算法

非對稱加密算法,指的是加密密鑰和解密密鑰並不相同。非對稱加密算法的秘鑰通常成對出現,分為公開密鑰和私有密鑰。公開密鑰可以以公開的形式發給數據交互方,而不會產生泄密的風險。因為非對稱加密算法,無法通過公開密鑰推算私有密鑰,反之亦然。

通常,非對稱加密算法是用公鑰進行加密,使用私鑰進行解密。

2.1 RSA算法

RSA算法是標準的非對稱加密算法,名字來源是三位發明者的姓氏首字母。RSA公開密鑰密碼體制是一種使用不同的加密密鑰與解密密鑰,“由已知加密密鑰推導出解密密鑰在計算上是不可行的”密碼體制 。其安全性取決於密鑰的長度,1024位的密鑰幾乎不可能被破解。

同樣,在Utils.Security下創建RSAHelper類:

namespace Utils.Security
{
    public static class RsaHelper
    {
        
    }
}

具體實現:

using System;
using System.Security.Cryptography;

namespace Utils.Security
{
    public static class RsaHelper
    {
        public static RSAParameters PublicKey { get; private set; }
        public static RSAParameters PrivateKey { get; private set; }

        static RsaHelper()
        {
            
        }

        public static void InitWindows()
        {
            var parameters = new CspParameters()
            {
                KeyContainerName = "RSAHELPER" // 默認的RSA保存密鑰的容器名稱
            };
            var handle = new RSACryptoServiceProvider(parameters);
            PublicKey = handle.ExportParameters(false);
            PrivateKey = handle.ExportParameters(true);
        }

        public static void ExportKeyPair(string publicKeyXmlString, string privateKeyXmlString)
        {
            var handle  = new RSACryptoServiceProvider();
            handle.FromXmlString(privateKeyXmlString);
            PrivateKey = handle.ExportParameters(true);
            handle.FromXmlString(publicKeyXmlString);
            PublicKey = handle.ExportParameters(false);
        }
        public static byte[] Encrypt(byte[] dataToEncrypt)
        {
            try
            {
                byte[] encryptedData;
                using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
                {
                    RSA.ImportParameters(PublicKey);
                    encryptedData = RSA.Encrypt(dataToEncrypt, true);
                }

                return encryptedData;
            }
            catch (CryptographicException e)
            {
                Console.WriteLine(e.Message);
                return null;
            }
        }

        public static byte[] Decrypt(byte[] dataToDecrypt)
        {
            try
            {
                byte[] decryptedData;
                using (var rsa = new RSACryptoServiceProvider())
                {
                    rsa.ImportParameters(PrivateKey);
                    decryptedData = rsa.Decrypt(dataToDecrypt, true);
                }
                return decryptedData;
            }
            catch (CryptographicException e)
            {
                Console.WriteLine(e.ToString());
                return null;
            }
        }
    }
}

因為RSA的特殊性,需要預先設置好公鑰和私鑰。C# 支持多種方式導入密鑰,這裏就不做過多介紹了。

3. 信息摘要算法

這種算法嚴格意義上並不是加密算法,因為它完全不可逆。也就是說,一旦進行使用該類型算法加密后,無法解密還原出數據。當然了,也正是因為這種特性常常被用來做密碼的保存。因為這樣可以避免某些人拿到數據庫與代碼后,可以簡單反推出用戶的密碼。

3.1 MD5算法

最常用的信息摘要算法就是MD5 加密算法,MD5信息摘要算法(英語:MD5 Message-Digest Algorithm),一種被廣泛使用的密碼散列函數,可以產生出一個128位(16字節)的散列值(hash value),用於確保信息傳輸完整一致。

原理不解釋,我們看下如何實現,照例現在Security下創建MD5Helper:

namespace Utils.Security
{
    public static class Md5Helper
    {
        
    }
}

具體實現:

using System.Security.Cryptography;
using System.Text;

namespace Utils.Security
{
    public static class Md5Helper
    {
        private static MD5 Hanlder { get; } = new MD5CryptoServiceProvider();

        public static string GetMd5Str(string source)
        {
            var data = Encoding.UTF8.GetBytes(source);
            var security = Hanlder.ComputeHash(data);
            var sb = new StringBuilder();
            foreach (var b in security)
            {
                sb.Append(b.ToString("X2"));
            }

            return sb.ToString();
        }
    }
}

4 總結

這一篇簡單介紹了四種常用的加密算法的實現,當然最常用的就是 MD5,因為這個是大多數系統用來做密碼保存的加密算法。

更多內容煩請關注我的博客《高先生小屋》

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

【其他文章推薦】

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

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

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

※幫你省時又省力,新北清潔一流服務好口碑

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

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

也來聊聊 HTTPS.

前言: 網上聊 HTTPS 的文章已經數都數不過來了吧,厚着臉皮,整理下讀書筆記,結合平常項目的實踐,也來聊聊 HTTPS。

一、為什麼需要 HTTPS?

眾所周知,HTTP 協議具有無連接、不可靠、盡最大努力的特點,這也為 HTPP 協議帶來信息竊聽或身份偽裝等安全問題。主要體現在幾個方面:

  • 通信使用明文(不加密),內容可能會被竊聽。
  • 不驗證通信方的身份,因此有可能遭遇偽裝。
  • 無法證明報文的完整性,所以有可能已遭篡改。

那要如何做到防止竊聽保護信息呢?最為普及的就是加密技術。

  • 通信的加密:用 SSL(Secure Socket Layer,安全套接層)或 TLS(Transport Layer Security,安全層傳輸協議)建立安全通信線路之後,就可以在這條線路上進行 HTTP 通信了。與 SSL/TLS 組合使用的 HTTP 就是 HTTPS,通常 HTTP 直接和 TCP 通信,當使用 SSL 時,則演變成先與 SSL 通信,再由 SSL 和 TCP 通信了,所以 HTTPS 並不是一種新的協議。
  • 內容的加密: 對 HTTP 協議傳輸的內容本身加密,即把 HTTP 報文里所含的內容進行加密處理。

SSL 協議最初是由瀏覽器開發商網景通信公司率先倡導的,開發過 SSL3.0 之前的版本。IETF 以 SSL3.0 為基準,后又制定了 TLS1.0、TLS1.1 和 TLS1.2。TSL 是以 SSL為原型開發的協議,有時會統一稱該協議為 SSL。當前主流的版本是 SSL3.0 和 TLS1.0。

SSL 不僅提供加密處理,而且還使用了一種被稱為證書的手段,可用於確定通信方。

二、HTTPS 怎麼來保障通信安全的?

HTTPS 具有加密、認證以及完整性保護的功能。

1. 加密

客戶端和服務端想要進行安全的通信,首先想到的就是對通信雙方的內容進行加密處理。客戶端利用“密鑰”加密內容,服務端利用“密鑰”解密內容,反之亦然。這種方式稱為對稱(共享密鑰)加密。

對稱加密客戶端和服務端的“密鑰”是一致的,因此,客戶端和服務端之間的“密鑰”傳輸不可避免,如果“密鑰”在傳輸途中被盜用,那麼加密處理就沒有意義了。

那麼如何保護“密鑰”的傳輸安全呢?實踐的思路是非對稱(公開密鑰)加密,服務端擁有 公鑰(public key)+ 私鑰(private key)的密鑰對,公鑰任何人都可以獲取,私鑰只保存在服務端。以下是 SSL 建立安全通信線路的過程。

  1. 服務端將公鑰傳輸給客戶端。
  2. 客戶端通過公鑰加密“密鑰”(客戶端生成)得到一個加密串並傳輸給服務端。
  3. 服務端根據私鑰解密加密串得到“密鑰”。
  4. 雙方通過“密鑰”加密傳輸。

非對稱加密“密鑰”的方式很好的保障了“密鑰”的安全傳輸,因為即使傳輸過程中加密串被盜用了,由於盜用者沒有私鑰信息,也無法得到加密串中的“密鑰”信息。

HTTPS 採用對稱(共享密鑰)加密和非對稱(公開密鑰)加密兩者並用的混合加密機制。之所以要這麼複雜,是因為非對稱加密的處理速度相較於對稱加密要慢,因此,我們一般在交換“密鑰”環節使用非對稱加密,之後的建立通信交換報文階段則使用對稱加密方式。

2. 認證

遺憾的是,非對稱加密傳輸“密鑰”的方式仍然有缺陷,那就是無法證明服務器公鑰本身就是貨真價實的公鑰。比如,接收到某台服務器的公鑰,如何證明公鑰就是原本預想的那台服務器發行的公鑰呢?或許在公鑰傳輸途中,真正的公鑰已經被攻擊者替換掉了。

計算機科學領域的任何問題都可以通過增加一個間接的中間層來解決。

這裏我們引入的中間層就是数字證書認證機構(CA,Certificate Authority),数字證書認證機構處於客戶端與服務器雙方都可信賴的第三方機構的立場上,以下是数字證書認證機構的業務流程。

  1. 服務器的運營人員向数字證書認證機構提出公開密鑰的申請。
  2. 数字證書認證機構在判明提出申請者的身份之後,會對已申請的公開密鑰做数字簽名,然後分配這個已簽名的公開密鑰,並將該公開密鑰放入公鑰證書。
  3. 服務器將公鑰證書下發給客戶端。
  4. 客戶端使用公鑰證書的公開密鑰,對那張證書上的数字簽名進行驗證,一旦驗證通過,客戶端便可明確兩件事:一,認證服務器的公開密鑰的是真實有效的数字證書認證機構頒發的。二,服務器的公開密鑰是值得信賴的。

HTTPS 中還可以使用客戶端證書,以客戶端證書進行客戶端認證,證明服務器正在通信的對方始終是預料之內的客戶端,其作用跟服務器證書如出一轍。

使用 OpenSSL 這套開源程序,每個人都可以構建一套屬於自己的認證機構,從而自己給自己頒發服務器證書,但該服務器證書在互聯網上不可作為證書使用,因為個人並不是可信任的三方機構。

3. 完整性保護

基於 SSL 進行 HTTP 通信時,應用層發送數據會附加一種叫做 MAC(Message Authentication Code)的報文摘要,MAC 能夠查知報文是否遭到篡改,從而保護報文的完整性。

三、HTTPS 的通信過程

CBC 模式(Cipher Block Chaining)又名密碼分組鏈接模式。在此模式下,將前一個明文塊加密處理后和下一個明文塊做 XOR 運算,使之重疊,然後再對運算結果做加密處理。 對第一個明文塊做加密時,要麼使用前一段密文的最後一塊,要麼利用外部生成的初始向量(initial vector, IV)。

四、HTTPS 的缺點?

處理速度上,由於 HTTPS 還需要做服務器、客戶端雙方加密及解密過程,因此會消耗 CPU 和內存等硬件資源。

通信上,和單純 HTTP 通信相比,SSL 通信會消耗部分網絡資源。

綜上所述,相較於 HTTP 通信來說,HTTPS 通信速度會變慢。針對速度變慢這一問題,並沒有根本性的解決方案,我們會使用 SSL 加速器這種(專用服務器)硬件來改善該問題。 該硬件為 SS通信專用硬件,相對軟件來講,能夠提高數倍 SSL 的計算速度。

另外,SSL 證書的費用開銷也是使用 HTTPS 的考慮因素之一(阿里雲/騰訊雲有免費的 SSL 證書可以申請使用)。

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

【其他文章推薦】

新北清潔公司,居家、辦公、裝潢細清專業服務

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

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

※超省錢租車方案

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

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

蓄意污染亞馬遜雨林 雪佛龍在厄瓜多憲法法庭敗訴

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

美國雪佛龍(Chevron)公司的世紀污染訴訟案,有了最新進展。厄瓜多憲法法庭稍早駁回了雪佛龍對95億美元污染判決的最終上訴,認定該公司蓄意將數十億加侖的有毒油廢料傾倒在亞馬遜熱帶雨林的原民土地上。

長達151頁的判決書中,以8比0一致判定原告原民團體勝訴,並駁回了雪佛龍的所有說法,例如雪佛龍自己也是詐欺受害者,以及厄瓜多法院對此案無管轄權等都遭到駁回。

前油田運營商德士古(後被雪佛龍收購)蓄意將數十億加侖的有毒油廢料傾倒在亞馬遜熱帶雨林。圖片來源:Caroline Bennett / Rainforest Action Network

環境集體訴訟案 第四次獲勝

厄瓜多憲法法院僅審理憲法問題,是厄瓜多第三大上訴法院,也是該國第四個維持2011年判決結果的法院,連同厄瓜多最高民事法庭和國家法院一致裁定雪佛龍須做出鉅額賠償。

這個針對雪佛龍公司的集體訴訟案,判決書於7月11日發布,原告是守護亞馬遜陣線(Frente de Defensa de la Amazonia),代表厄瓜多亞馬遜北部地區80個原民和農民社區的草根團體。

該訴訟最初由約3萬名熱帶雨林村民於1993年在紐約聯邦法院提出,被告是前油田運營商德士古(Texaco,已被雪佛龍公司收購)。2001年雪佛龍公司接受厄瓜多具有管轄權後,一名美國聯邦法官將此案移交給厄瓜多法院。

「這個判決是厄瓜多人民20年來為了爭取環境正義,對抗世界級污染者、流氓企業的再一次巨大勝利,」環保金人獎得主、1993年訴訟案起草者楊澤(Luis Yanza)表示。他目前也是守護亞馬遜陣線的主席。

楊澤說:「在雪佛龍開始賠償厄瓜多人民前,任何國家都不應該與雪佛龍做生意。」

致癌油廢料污染 雪佛龍八年拖延纏訟

厄瓜多首席律師薩拉查(Patricio Salazar)表示,「司法已認定雪佛龍非法攻擊代表原住民社群的律師,而不是根據是非來訴訟。雪佛龍現在極有可能必須全額支付賠償金,因為它在法律上和道德上都有義務這樣做。」

厄瓜多初審法院依據105份技術證據報告,在2011年判決該公司致癌油廢料污染了1500平方英里的亞馬遜土地。但是八年來,雪佛龍以拖延戰術因應訴訟。

生活在熱帶雨林中的數千人,包括許多原住民,已經死於癌症,而成千上萬的人必須忍受這場世界級的公衛災難。

代表厄瓜多村民的美國律師唐齊格(Steven Donziger)。圖片來源:Steven Donziger

拒支付賠償金 村民仍沒有醫療

收受雪佛龍公司400口油井特許使用費的厄瓜多政府,沒有給受害者太大幫助。

哈佛大學畢業,代表厄瓜多村民的美國律師唐齊格(Steven Donziger)曾走訪受影響地區數十次,他表示受影響地區並沒有醫療服務,許多人甚至一次醫生都沒看,也沒接受任何治療就死於癌症。

「雪佛龍在厄瓜多引發了一場史無前例的人道主義危機。再不清除污染,未來幾年將有數萬人死亡。全世界都必須關注,雪佛龍的股東和管理層必須立即採取行動,解決這個日益嚴重的問題。」唐齊格說。

雪佛龍多年來一直拒絕支付判決賠償金,目前連本帶利已經來到120億美元(約新台幣1361億元)。

雪佛龍公司人員甚至威脅原民,若繼續堅持訴訟,他們可和原告「終身纏訟」。

卡普蘭法官 採信偽證風波

這份最新判決也是對美國紐約南區地方法院法官卡普蘭(Lewis A. Kaplan)的重大打擊。

2014年,這位具有爭議性的法官僅憑一位承認收賄的雪佛龍證人的假證詞便裁定,厄瓜多最高法院對雪佛龍提出的95億美元賠償判決是透過欺詐和脅迫手段取得。卡普蘭拒絕讓公正的事實調查員陪審團參與,也拒絕考量任何有關雪佛龍污染厄瓜多環境的證據。

但新事證顯示,雪佛龍支付厄瓜多前法官格拉(Alberto Guerra)大筆賄款之後,卡普蘭的判決被推翻。雪佛龍幫助格拉一家搬到美國後,格拉承認在雪佛龍律師的指導下作偽證。

卡普蘭僅憑格拉的偽證做出判決,也是全世界唯一做出有利雪佛龍判決的法官。

「出於省錢的錯誤營運決策」 法庭定調蓄意污染

基於比卡普蘭所能取得更完整的證據,17名厄瓜多法官作出有利厄瓜多村民的判決。12名加拿大法官,包括該國最高法院,也針對多個技術性問題作出有利厄瓜多村民的判決。

厄瓜多憲法法庭強調,雪佛龍污染環境造成嚴重後果不是意外造成,而是處心積慮為公司和股東省錢的運營決策,加上20年來蓄意拖延的額外罪行所導致。

厄瓜多原告也在加拿大法院取得了幾項上訴勝利,他們在加國蒐集雪佛龍資產,以迫使其遵守厄瓜多的判決。

Chevron Defeated in Ecuador’s Constitutional Court QUITO, Ecuador, July 31, 2018 (ENS)

In a benchmark pollution case, Ecuador’s Constitutional Court has rejected Chevron’s final appeal of a $9.5 billion pollution judgment that found the company deliberately dumped billions of gallons of toxic oil waste onto Indigenous lands in the Amazon rainforest.

Photo: Caroline Bennett / Rainforest Action Network

The unanimous 8-0 decision, issued in a 151-page document published July 11, was a total victory for the Indigenous groups that brought the case and a rejection of all of Chevron’s claims.

The Court rejected Chevron’s allegations that it was victimized by fraud, and the court threw out the company’s claim that Ecuadorian courts had no jurisdiction over the matter.

Ecuador’s Constitutional Court, which deals only with Constitutional issues, is the third major appellate court in Ecuador and the fourth court overall in the country to uphold the trial-level decision against Chevron, which was issued in 2011. Ecuador’s highest civil court, the National Court of Justice, has ruled unanimously to affirm the judgment against Chevron.

The class action case against Chevron was spearheaded by the Frente de Defensa de la Amazonia, the Amazon Defense Front, a grassroots group representing 80 Indigenous peoples and farmer communities in Ecuador’s northern Amazon region.

The case was originally filed in 1993 in federal court in New York against the former oil field operator Texaco, now part of Chevron Corporation, on behalf of an estimated 30,000 rainforest villagers. But in 2001 a U.S. federal judge moved it to Ecuador’s courts at Chevron’s request after the company accepted jurisdiction there.

“This decision is another huge victory for the people of Ecuador in their historic two-decade battle for environmental justice against the world’s worst corporate polluter and rogue operator,” said Luis Yanza, a Goldman Prize winner who initiated the lawsuit against Chevron in U.S. federal court in 1993, and serves as president of the Frente de Defensa de la Amazonia, Amazon Defense Front.

“No country should ever do business with Chevron until the company first pays for the harm it caused to the people of Ecuador,” Yanza said.

Patricio Salazar, the lead Ecuadorian lawyer on the case, said, “Justice has prevailed over Chevron’s illegal attempts to engage in constant attacks on lawyers who defend the Indigenous communities rather than litigate in good faith on the merits. It is now highly likely that Chevron will pay every last dollar of the judgment against it, as it is legally and ethically obligated to do.”

After eight years of proceedings slowed by Chevron’s strategy of deliberate delay, Ecuador’s trial court relied on 105 technical evidentiary reports to find in 2011 that the company poisoned a 1,500 square mile area of the Amazon with carcinogenic oil waste.

Thousands who live in the rainforest, including many Indigenous peoples, have died of cancer while tens of thousands must endure what is one of the world’s worst ongoing public health catastrophes.

Photo: Jonathan McIntosh / Rainforest Action Network

Ecuador’s government, which received royalties from Chevron’s operation of 400 well sites, has been of little help to the victims. Medical care in the affected region is non-existent, and many people perish from cancer without even visiting a doctor and after receiving no treatment, said Steven Donziger, the Harvard educated U.S. legal representative of the Ecuadorian communities, who has taken dozens of trips to the affected area.

“Chevron has caused a humanitarian crisis in Ecuador of epic proportions that is ongoing to this day,” he said. “Tens of thousands of people will die in the coming years if nothing is done to clean up the pollution. The world must pay attention and Chevron shareholders and management must act immediately to address this worsening problem.”

Chevron has refused for years to pay the Ecuador judgment, now worth $12 billion with interest. Company officials have threatened the Indigenous groups with a “lifetime of litigation” if they persist.

The latest Ecuadorean court decision is also a major blow to controversial Judge Lewis A. Kaplan, a judge of the U.S. District Court for the Southern District of New York.

In 2014, Judge Kaplan ruled that the $9.5 billion Lago Agrio judgment leveled against Chevron by Ecuador’s highest court, was obtained by way of fraud and coercion.

Kaplan relied on false testimony from an admittedly corrupt Chevron witness to find that the Ecuador judgment was procured by fraud. Kaplan refused to seat a jury of impartial fact finders, and he refused to consider any evidence of Chevron’s environmental contamination in Ecuador.

But Kaplan’s decision was disproven after evidence emerged that Chevron paid large sums to Alberto Guerra, a former Ecuadorian judge booted from the bench after he admitted taking bribes. Guerra was moved with his family by Chevron to the United States and later admitted lying on the stand after being coached for 53 days by Chevron lawyers headed by Randy Mastro at Gibson Dunn.

Kaplan based his core findings largely on Guerra’s false testimony. And Kaplan remains the only judge in the world to have ruled in favor of Chevron.

Seventeen Ecuador judges, who had access to a fuller evidentiary record than Kaplan, ruled in favor of the affected communities. Twelve judges from Canada, including the country’s entire Supreme Court, have also ruled in favor of the Ecuadorians on various technical issues.

The Ecuador decision confronts Chevron on the brutal human consequences of both its original environmental crimes, which the Court emphasizes were not the result of an accident, but rather of deliberate operational decision-making designed to save money and enrich the company’s shareholders and executives, and the additional offense of its two-decade campaign of distraction and delay.

The Ecuadorian plaintiffs also have picked up several appellate victories in Canadian courts as they attempt to collect Chevron assets in that country to force compliance with the Ecuador judgment.

※ 全文及圖片詳見:

作者

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

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

延伸閱讀

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

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

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

※台北網頁設計公司全省服務真心推薦

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

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

不能放任蜜蜂死 法國禁五款類尼古丁農藥

摘錄自2018年8月10日中央社報導

法國政府為遏止蜜蜂持續大量死亡,公告自9月1日起禁用五種含類尼古丁的農藥。

法國於2016年實施生物多樣性法規,當時就決定要禁用含類尼古丁(neonicotinoid)的殺蟲劑,這種物質會破壞昆蟲的神經系統,導致蜜蜂等花粉媒介昆蟲迷路及死亡,威脅到生物多樣性和糧食生產。

法國這一波禁用的五種殺蟲劑包括益達胺(imidacloprid)、可尼丁(clothianidin)、賽速安(Thiamethoxam)、賽果培(Thiacloprid)和亞滅培(Acetamiprid)。

法國政府對這類殺蟲劑的禁令比歐盟嚴格。費加洛報(Le Figaro)報導,法國生態部表示,國會正在審議糧食法草案,通過後,應可再增加禁用類尼古丁殺蟲劑的種類。

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

美法院裁決 環保署須下令禁用陶斯松

摘錄自2018年8月10日中央社報導

聯邦第九巡迴上訴法院今天(10日)裁決,美國環境保護署(EPA)須在60天內下令禁用陶斯松(chlorpyrifos)。批評人士指出,這種廣泛使用的農藥會傷害兒童和農民。

第九巡迴上訴法院以2票贊成、1票反對的裁決結果,推翻前環保署長普魯特(Scott Pruitt)2017年3月拒絕接受環保團體請願的決定。當時環保團體呼籲,禁止陶斯松用於水果、蔬菜和堅果等糧食作物。

代表第九巡迴上訴法院撰寫裁決書的法官拉柯夫(Jed Rakoff)指出,「科學證據顯示,殘留在糧食上(的陶斯松)會對兒童神經發育造成損害」,但環保署未能提出有力反駁,因此下令環保署須在60天內下令禁用陶斯松。

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

【其他文章推薦】

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

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

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

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

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

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

八張圖徹底了解JDK8 GC調優秘籍-附PDF下載

目錄

  • 簡介
  • 分代垃圾回收器的內存結構
  • JDK8中可用的GC
  • 打印GC信息
  • 內存調整參數
  • Thread配置
  • 通用GC參數
  • CMS GC
  • G1參數
  • 總結

簡介

JVM的參數有很多很多,根據我的統計JDK8中JVM的參數總共有1853個,正式的參數也有680個。

這麼多參數帶給我們的是對JVM的細粒度的控制,但是並不是所有的參數都需要我們自己去調節的,我們需要關注的是一些最常用的,對性能影響比較大的GC參數即可。

為了更好的讓大家理解JDK8中 GC的調優的秘籍,這裏特意準備了八張圖。在本文的最後,還附帶了一個總結的PDF all in one文檔,大家把PDF下載回去,遇到問題就看兩眼,不美嗎?

分代垃圾回收器的內存結構

為了更好的提升GC的效率,現代的JVM都是採用的分代垃圾回收的策略(ZGC不是)。

java運行時內存可以分為JVM內存和非JVM內存。

JVM內存又可以分為堆內存和非堆內存。

堆內存大家都很熟悉了,YoungGen中的Eden,Survivor和OldGen。

非堆內存中存儲的有thread Stack,Code Cache, NIO Direct Buffers,Metaspace等。

注意這裏的Metaspace元空間是方法區在JDK8的實現,它是在本地內存中分配的。

JDK8中可用的GC

JDK8中到底有哪些可以使用的GC呢?

這裏我們以HotSpot JVM為例,總共可以使用4大GC方式:

其中對於ParallelGC和CMS GC又可以對年輕代和老年代分別設置GC方式。

大家看到上圖可能有一個疑問,Parallel scavenge和Parallel有什麼區別呢?

其實這兩個GC的算法是類似的,Parallel Scavenge收集器也經常稱為“吞吐量優先”收集器,Parallel Scavenge收集器提供了兩個參數用於精確控制吞吐量; -XX:MaxGCPauseMillis:控制最大垃圾收集停頓時間; -XX:GCTimeRatio:設置吞吐量大小。

同時Parallel Scavenge收集器能夠配合自適應調節策略,把內存管理的調優任務交給虛擬機去完成。

JDK8中默認開啟的是ParallelGC。

打印GC信息

如果想研究和理解GC的內部信息,GC信息打印是少不了的:

上圖提供了一些非常有用的GC日誌的控制參數。

內存調整參數

JVM分為Heap區和非Heap區,各個區又有更細的劃分,下面就是調整各個區域大小的參數:

Thread配置

TLAB大家還記得嗎?TLAB的全稱是Thread-Local Allocation Buffers。TLAB是在Eden區間分配的一個一個的連續空間。然後將這些連續的空間分配個各個線程使用。

因為每一個線程都有自己的獨立空間,所以這裏不涉及到同步的概念。

上圖就是TLAB的參數。

通用GC參數

雖然JDK8的GC這麼多,但是他們有一些通用的GC參數:

這裏講解一下Young space tenuring,怎麼翻譯我不是很清楚,這個主要就是指Young space中的對象經過多少次GC之後會被提升到Old space中。

CMS GC

CMS全稱是Concurrent mark sweep。是一個非常非常複雜的GC。

複雜到什麼程度呢?光光是CMS調優的參數都有一百多個!

下圖是常用的CMS的參數。

CMS這裏就不多講了,因為在JDK9之後,CMS就已經被廢棄了。

主要原因是CMS太過複雜,如果要向下兼容需要巨大的工作量,然後就直接被廢棄了。

在JDK9之後,默認的GC是G1。

G1參數

G1收集器是分代的和region化的,也就是整個堆內存被分為一系列大小相等的region。在啟動時,JVM設置region的大小,根據堆大小的不同,region的大小可以在1MB到32MB之間變動,region的數量最多不超過2048個。Eden區、Survivor區、老年代是這些region的邏輯集合,它們並不是連續的。

G1中的垃圾收集過程:年輕代收集和混合收集交替進行,背後有全局的併發標記周期在進行。當老年代分區佔用的空間達到或超過初始閾值,就會觸發併發標記周期。

下圖是G1的調優參數:

總結

上面總共8副圖,我把他們做成了一個PDF,預覽界面大概是這樣子的:

大家可以通過下面的鏈接直接下載PDF版本:

JDK8GC-cheatsheet.pdf

如果遇到問題可以直接拿過來參考。這種東西英文名字應該叫JDK8 GC cheatsheet,翻譯成中文應該就是JDK8 GC調優秘籍!

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/jdk8-gc-cheatsheet/

本文來源:flydean的博客

歡迎關注我的公眾號:程序那些事,更多精彩等着您!

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

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

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

※台北網頁設計公司全省服務真心推薦

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

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

誰再悄咪咪的吃掉異常,我上去就是一 JIO

又到周末了,周更选手申請出站~

這次分享一下上個月碰到的離奇的問題。一個簡單的問題,硬是因為異常被悄咪咪吃掉,過關難度直線提升,導致小黑哥排查一個晚上。

這個美好的晚上,本想着開兩把 LOL 無限火力,在召喚師峽谷來個五殺的~

哎,就這樣沒了啊!我知道,你們一定能理解這種五殺被搶的感覺~

下次,真的,誰再讓我看到悄咪咪的吃掉異常,我真的要上去一 Jio 了!

好了,本文可不是水文,看完本篇文章,你可以學到以下知識點:

  • Arthas 排查技巧
  • 啥是 NoClassDefFoundError
  • Dubbo 異常內部處理方式

好了,同學們,打開小本子,準備記好知識點~

先贊后看養成習慣,微信搜索「程序通事」,關注就完事了

起因

我們有個業務系統,應用之間調用鏈如下所示:

A 應用是業務發生起始應用,在這個應用中將會根據一定規則選擇最後的通訊渠道 C,然後將這個渠道標識傳遞給 B 應用。

B 應用的功能類似網關,這個應用將會根據 A 應用傳遞過來的渠道標識,將會請求路由下發到具體的 C 應用,起到服務路由的功能。

C 應用是與外部應用交互的應用,我們將其稱為渠道通訊機。

假設一次業務中,A 應用根據規則選擇 C2 的渠道標識,然後傳遞給 B 應用。B 應用根據這個標識選擇使用 C2 進行通訊,最後 C2 調用外部應用完成一次業務調用。

上述所有應用都基於 Dubbo 進行遠程通訊,B 應用實現原理在小黑哥之前文章「支付路由系統演進史」中有寫過,感興趣的同學可以查看一下。

介紹完業務的基本情況,現在我們來看下到底發生了啥事。

一次業務需求中,需要改動 C2 應用,這次改動功能點真的很小,很快就完成了。小黑哥想着閑着也是閑着,於是就把之前 C2 應用中打印的日誌中一些沒有脫敏的信息,進行脫敏處理。

由於之前日誌框架脫敏處理存在一些問題,於是就將日誌框架從 Log4j 升級為 LogBack。升級之後,為了防止不同日誌框架中之間的產生衝突,於是使用 IDEA Maven Helper 插件,統一將應用中所有的 Log4j 相關依賴都給排除了。

改動完成之後,將 C2 應用發布到測試環境,再次從 A 應用發起測試, B 應用返回異常提示未找到 C2 應用

B 應用業務代碼類似如下:

public Response pay(Request req) {
    
    try {
        if (!isSupport(req.getChnlCode())) {
            return new Response("ERROR", "未找到相關渠道應用");
        }
        return doPay(req);
    } catch (Exception e) {
        return new Response("ERROR", "未找到相關渠道應用");
    }
}

正常情況下,若是配置存在問題,B 應用將會返回未找到具體渠道,請求也會在 B 應用結束,不會調用到 C2 應用(也沒辦法調用)。

然而此次配置什麼都沒問題, 而且最詭異的是 C2 應用居然收到了請求,並且成功處理了業務請求。

排查問題

由於 B 應用異常處理時,將異常吃掉了,我們沒辦法得知這個過程到底發生了啥事,所以第一要緊的事獲取異常信息。

最簡單的辦法就是,將 B 應用改造一下,加入打印異常日誌。不過當時比較懶,不想改造應用,就想獲取異常信息,於是想到使用 Arthas

Arthas 排錯技巧

Arthas 是Alibaba開源的Java診斷工具,這裏就不再詳細介紹這個工具,主要講下這次排錯用到的命令-watch

watch 命令可以方便觀察指定方的調用情況,可以具體觀察方法的返回值拋出異常入參,另外還可以通過 OGNL表達式查看對應的變量。

這裏我們主要為了查看方法拋出的異常信息,執行命令如下:

watch com.dubbo.example.DemoService doPay -e -x 2 '{params,throwExp}'

上述命令將會在方法異常之後觀察方法的入參以及異常信息。

注意,我們需要查看 doPay 方法,而不是 pay 方法。這是因為 pay方法中我們將異常捕獲,不太可能會拋出異常哦~

異常信息如下所示:

真正引起此次錯誤的異常信息為:

java.lang.NoClassDefFoundError: Could not initialize class xx.xxx.xx.GELogger

由於此次 B 應用不存在改動,所以推測這個異常實際發生在 C2 應用,於是在 C2 應用處再次使用 Arthas watch 命令,同樣觀察到相同的錯誤信息。

NoClassDefFoundError

NoClassDefFound,從名字上我們可以推測是因為類不存在,從而引發的這個錯誤。按照這個思路,我們首先可以簡單查看一下 B 應用中是否存在 GELogger 相關類。

查看 B 應用相關依賴包,從中發現了這個類文件,這說明這個類確實存在。

在 IDEA 反編譯查看 GELogger類相關源碼,從中發現了問題。

private static Logger logger;

static {
    System.out.println("static init");
    logger = Logger.getLogger(NoClassDefFoundErrorTestService.class);
    System.out.println("Logger init success");
}

GELogger存在一個靜態代碼塊,用於初始化一個 org.apache.log4j.Logger日誌類。

然後在上面改動中,全部的 Log4j依賴都被排除了,所以這裏運行時應該會拋出另外一個找到 org.apache.log4j.Logger 錯誤。

執行以下代碼,模擬拋錯過程。

System.out.println("模擬第一次 Error");
try {
    NoClassDefFoundErrorTestService noClassDefFoundErrorTestService=new NoClassDefFoundErrorTestService();
} catch (Throwable e) {
    e.printStackTrace();
}
System.out.println("模擬第二次 Error");
try {
    NoClassDefFoundErrorTestService noClassDefFoundErrorTestService=new NoClassDefFoundErrorTestService();
} catch (Throwable e) {
    e.printStackTrace();
}

異常信息如下所示:

第一次創建 NoClassDefFoundErrorTestService實例時,Java 虛擬機讀取加載時,將會初始化靜態代碼塊時。由於 org.apache.log4j.Logger類不存在,靜態代碼塊執行異常,從而導致類加載失敗。

第二次再創建 NoClassDefFoundErrorTestService 實例時,Java 虛擬機不會再次讀取加載,所以直接返回了以下異常。

java.lang.NoClassDefFoundError: Could not initialize class com.dubbo.example.NoClassDefFoundErrorTestService

找到問題真正原因,解決辦法也很簡單,直接排除 GELogger 所在依賴包。

Dubbo 內部異常處理

雖然問題到此解決了,但是這裏還有一個疑問,為何 C2 應用發生了異常,卻沒有相關錯誤日誌,並且 C2 業務邏輯也正常處理完成。

這就要說到 Dubbo 內部異常錯誤處理方式,上面 GELogger 其實作用在一個 Dubbo 自定義 Filter 中,用來記錄結果,模擬代碼如下:

@Activate(
        group = {"provider", "consumer"}
)
public class ErrorFilter implements Filter {


    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {

        Result result = invoker.invoke(invocation);
        NoClassDefFoundErrorTestService noClassDefFoundErrorTestService=new NoClassDefFoundErrorTestService();
        // 處理業務邏輯
        return result;
    }
}

這個自定義 Filter 中首先執行 invoker 方法,這個方法將會調用真正的業務方法,這就是為什麼 C2 應用邏輯是正常處理完成。

業務方法處理完成之後,然後執行後續邏輯。由於 NoClassDefFoundErrorTestService將會拋出 Error,最終這個 Error,將會在 HeaderExchangeHandler#handleRequest 被捕獲,然後將會把相關異常信息返回給調用 Dubbo 消費者。

而在 Dubbo 消費者接受到服務提供者返回信息之後,將會在 DefaultFuture#doReceived轉化成 RemotingException

RemotingException 最終將會在 FailoverClusterInvoker#doInvoke 轉換成 RpcException返回給業務代碼。

總結

好了,說了這麼多,總結一下本文知識點

  1. 異常捕獲之後,一定要記得打印日誌,並且要記得輸出堆棧信息
  2. 運行時類不存在,將會導致 NoClassDefFoundError,類加載過程失敗,也會導致 NoClassDefFoundError
  3. 對外提供的二方包,最好不要依賴特定日誌框架,如 Log4j,Logback 等,應該使用 Slf4j 框架。

幫助

1、當Dubbo遇上Arthas:排查問題的實踐

2、java.lang.NoClassDefFoundError 的解決方法一例

3、noclassdeffounderror-could-not-initialize-class-error

歡迎關注我的公眾號:程序通事,獲得日常乾貨推送。如果您對我的專題內容感興趣,也可以關注我的博客:studyidea.cn

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

恕我直言你可能真的不會java第5篇:Stream的狀態與并行操作

一、回顧Stream管道流操作

通過前面章節的學習,我們應該明白了Stream管道流的基本操作。我們來回顧一下:

  • 源操作:可以將數組、集合類、行文本文件轉換成管道流Stream進行數據處理
  • 中間操作:對Stream流中的數據進行處理,比如:過濾、數據轉換等等
  • 終端操作:作用就是將Stream管道流轉換為其他的數據類型。這部分我們還沒有講,我們後面章節再介紹。

看下面的腦圖,可以有更清晰的理解:

二、中間操作:有狀態與無狀態

其實在程序員編程中,經常會接觸到“有狀態”,“無狀態”,絕大部分的人都比較蒙。而且在不同的場景下,“狀態”這個詞的含義似乎有所不同。但是“萬變不離其宗”,理解“狀態”這個詞在編程領域的含義,筆者教給大家幾個關鍵點:

  • 狀態通常代表公用數據,有狀態就是有“公用數據”
  • 因為有公用的數據,狀態通常需要額外的存儲。
  • 狀態通常被多人、多用戶、多線程、多次操作,這就涉及到狀態的管理及變更操作。

是不是更蒙了?舉個例子,你就明白了

  • web開發session就是一種狀態,訪問者的多次請求關聯同一個session,這個session需要存儲到內存或者redis。多次請求使用同一個公用的session,這個session就是狀態數據。
  • vue的vuex的store就是一種狀態,首先它是多組件公用的,其次是不同的組件都可以修改它,最後它需要獨立於組件單獨存儲。所以store就是一種狀態。

回到我們的Stream管道流

  • filter與map操作,不需要管道流的前面後面元素相關,所以不需要額外的記錄元素之間的關係。輸入一個元素,獲得一個結果。
  • sorted是排序操作、distinct是去重操作。像這種操作都是和別的元素相關的操作,我自己無法完成整體操作。就像班級點名就是無狀態的,喊到你你就答到就可以了。如果是班級同學按大小個排序,那就不是你自己的事了,你得和周圍的同學比一下身高並記住,你記住的這個身高比較結果就是一種“狀態”。所以這種操作就是有狀態操作。

三、Limit與Skip管道數據截取

List<String> limitN = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
        .limit(2)
        .collect(Collectors.toList());
List<String> skipN = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
        .skip(2)
        .collect(Collectors.toList());
  • limt方法傳入一個整數n,用於截取管道中的前n個元素。經過管道處理之後的數據是:[Monkey, Lion]。
  • skip方法與limit方法的使用相反,用於跳過前n個元素,截取從n到末尾的元素。經過管道處理之後的數據是: [Giraffe, Lemur]

四、Distinct元素去重

我們還可以使用distinct方法對管道中的元素去重,涉及到去重就一定涉及到元素之間的比較,distinct方法時調用Object的equals方法進行對象的比較的,如果你有自己的比較規則,可以重寫equals方法。

List<String> uniqueAnimals = Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
        .distinct()
        .collect(Collectors.toList());

上面代碼去重之後的結果是: [“Monkey”, “Lion”, “Giraffe”, “Lemur”]

五、Sorted排序

默認的情況下,sorted是按照字母的自然順序進行排序。如下代碼的排序結果是:[Giraffe, Lemur, Lion, Monkey],字數按順序G在L前面,L在M前面。第一位無法區分順序,就比較第二位字母。

List<String> alphabeticOrder = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
        .sorted()
        .collect(Collectors.toList());

排序我們後面還會給大家詳細的講一講,所以這裏暫時只做一個了解。

六、串行、并行與順序

通常情況下,有狀態和無狀態操作不需要我們去關心。除非?:你使用了并行操作。

還是用班級按身高排隊為例:班級有一個人負責排序,這個排序結果最後就會是正確的。那如果有2個、3個人負責按大小個排隊呢?最後可能就亂套了。一個人只能保證自己排序的人的順序,他無法保證其他人的排隊順序。

  • 串行的好處是可以保證順序,但是通常情況下處理速度慢一些
  • 并行的好處是對於元素的處理速度快一些(通常情況下),但是順序無法保證。這可能會導致進行一些有狀態操作的時候,最後得到的不是你想要的結果。
Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
        .parallel()
        .forEach(System.out::println);
  • parallel()函數表示對管道中的元素進行并行處理,而不是串行處理。但是這樣就有可能導致管道流中後面的元素先處理,前面的元素后處理,也就是元素的順序無法保證。

如果數據量比較小的情況下,不太能觀察到,數據量大的話,就能觀察到數據順序是無法保證的。

Monkey
Lion
Lemur
Giraffe
Lion

通常情況下,parallel()能夠很好的利用CPU的多核處理器,達到更好的執行效率和性能,建議使用。但是有些特殊的情況下,parallel並不適合:深入了解請看這篇文章:
https://blog.oio.de/2016/01/22/parallel-stream-processing-in-java-8-performance-of-sequential-vs-parallel-stream-processing/
該文章中幾個觀點,說明并行操作的適用場景:

  • 數據源易拆分:從處理性能的角度,parallel()更適合處理ArrayList,而不是LinkedList。因為ArrayList從數據結構上講是基於數組的,可以根據索引很容易的拆分為多個。
  • 適用於無狀態操作:每個元素的計算都不得依賴或影響任何其他元素的計算,的運算場景。
  • 基礎數據源無變化:從文本文件裏面邊讀邊處理的場景,不適合parallel()并行處理。parallel()一開始就容量固定的集合,這樣能夠平均的拆分、同步處理。

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

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

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

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

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

【其他文章推薦】

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

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

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

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

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

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

GitHub 熱點速覽 Vol.25:距離優雅編程你差個它

作者:HelloGitHub-小魚乾

摘要:如何優雅地誇一個程序員呢?vscode-rainbow-fart 作為一個彩虹屁的項目,深得程序員心,能在你編程時瘋狂稱讚你的除了你自己,還有它。除了鼓勵之外,Super Linte 是官方出品的旨在保證代碼和文檔一致性的工具,有了它,你可以更優雅地進行編程。說完優雅編程,來說下優雅使用 k8s,那就不得不提 Lens,一個專業管理 k8s 工具。

以下內容摘錄自微博@HelloGitHub 的 GitHub Trending,選項標準:新發布 | 實用 | 有趣,根據項目 release 時間分類,發布時間不超過 7 day 的項目會標註 New,無該標誌則說明項目 release 超過一周。由於本文篇幅有限,還有部分項目未能在本文展示,望周知

  • 本文目錄
      1. 本周特推
      • 1.1 GitHub 官方出品:super-linter
      • 1.2 彩虹屁 VSCode 插件:vscode-rainbow-fart
      1. GitHub Trending 周榜
      • 2.1 Python 實用編程:practical-python
      • 2.2 有碼變高清:pulse
      • 2.3 刷題模版:algorithm-pattern
      • 2.4 一分鐘一個小 case:python-small-examples
      • 2.5 專業管理 k8s:lens
      • 2.6 益智遊戲:shapez
      • 2.7 數據科學:GoPlus
      1. 本周 GitHub Trending #量化投資# 主題的主力軍
      • 3.1 量化交易框架:vnpy
      • 3.2 量化交易組件:easytrader
      • 3.3 30 天掌握量化交易:stock
      1. 推薦閱讀

1. 本周特推

1.1 GitHub 官方出品:super-linter

本周 star 增長數:3100+

GitHub Super Linter 是由 GitHub Services DevOps 工程團隊開源的提供給 Action 調用的存儲庫,目的是保持我們文檔和代碼的一致性,同時提升整個公司之間的交流和協作的效率。特性包括:

  • 防止將損壞的代碼上傳到主分支;
  • 幫助建立多種語言的編碼最佳實踐;
  • 制訂代碼布局和格式的指南;
  • 自動化流程以幫助簡化代碼審查;

GitHub 地址→https://github.com/github/super-linter/

1.2 彩虹屁 VSCode 插件:vscode-rainbow-fart

本周 star 增長數:1800+

Newvscode-rainbow-fart 是一個彩虹屁 VSCode 插件,在你編程時瘋狂稱讚你,可以根據代碼關鍵字播放貼近代碼意義的真人語音,誇你寫代碼牛逼。

GitHub 地址→https://github.com/SaekiRaku/vscode-rainbow-fart

2. GitHub Trending 周榜

2.1 Python 實用編程:practical-python

本周 star 增長數:1850+

practical-python 是一個從事 Python 編程近三十年的工程師出的 Python 核心課程,它需要你 3、4 天的學習時間,大約 25-35 小時的時間,包括 130 多個項目實踐。

GitHub 地址→https://github.com/dabeaz-course/practical-python

2.2 有碼變高清:pulse

本周 star 增長數:1500+

Newpulse 是一個可以將馬賽克圖片百年變成高清圖的工具,近日由杜克大學(Duke University)研究團隊開發了。作為一款 AI 修圖黑科技 PULSE,可以解決所有低像素煩惱。據說它能夠將圖像原始分辨率放大 64 倍,任何渣畫質都可以秒變高清、逼真圖像,甚至被打了馬賽克的人臉圖像,毛孔、皺紋,頭髮也都能被清晰還原。

GitHub 地址→https://github.com/adamian98/pulse

2.3 刷題模版:algorithm-pattern

本周 star 增長數:2800+

Newalgorithm-pattern 是項目作者找工作時,從 0 開始刷 LeetCode 的心得記錄,通過各種刷題文章、專欄、視頻等總結的一套自己的刷題模板。

GitHub 地址→https://github.com/greyireland/algorithm-pattern

2.4 一分鐘一個小 case:python-small-examples

本周 star 增長數:10900+

python-small-examples 是一個告別枯燥,60 秒學會一個 Python 小例子的項目,目前庫已有 223 個實用的小例子 。

GitHub 地址→https://github.com/jackzhenguo/python-small-examples

2.5 專業管理 k8s:lens

本周 star 增長數:800+

Len 是一個開源、免費可用的 IDE,可方便管理 Kubernetes 的工具。

GitHub 地址→https://github.com/lensapp/lens

2.6 益智遊戲:shapez.io

本周 star 增長數:600+

shapez.io 是一個受 Factorio 啟發的搭建遊戲。你要做的事情就是簡單地通過切割,旋轉,合併和繪製形狀的零件來產生形狀。

GitHub 地址→https://github.com/tobspr/shapez.io

2.7 數據科學:GoPlus

本周 star 增長數:1800+

NewGoPlus 是數據科學的 Go+ 語言。

GitHub 地址→https://github.com/qiniu/goplus

3. 本周 GitHub Trending #投資量化#主題的主力軍

在本期主題模塊,小魚乾這裏選取了 3 個和量化相關的小工具,希望能增加你的收入,養肥你的錢包。

3.1 量化交易框架:vnpy

vn.py 是一套基於 Python 的開源量化交易系統開發框架。

GitHub 地址→https://github.com/vnpy/vnpy

3.2 量化交易組件:easytrader

easytrader 是一個提供同花順客戶端/國金/華泰客戶端/雪球的基金、股票自動程序化交易以及自動打新,支持跟蹤 joinquant /ricequant 模擬交易和實盤雪球組合的量化交易組件。特性:

  • 進行自動的程序化股票交易
  • 支持跟蹤 joinquant, ricequant 的模擬交易
  • 支持跟蹤雪球組合調倉
  • 支持通用的同花順客戶端模擬操作
  • 實現自動登錄
  • 支持通過 webserver 遠程操作客戶端
  • 支持命令行調用,方便其他語言適配
  • 基於 Python 3.6, Win。注: Linux 僅支持雪球

GitHub 地址→https://github.com/shidenggui/easytrader

3.3 30 天掌握量化交易:stock

stock 是作者作為業餘投機者(韭菜)一枚,自學量化交易,把經歷寫成代碼推送到 GitHub 的項目。

GitHub 地址→https://github.com/Rockyzsu/stock

推薦閱讀

  • GitHub 熱點速覽 Vol.24:程序員自我增值,優雅賺零花錢
  • GitHub 熱點速覽 Vol.23:前後端最佳實踐
  • GitHub 熱點速覽 Vol.22:如何打造超級技術棧

以上為 2020 年第 23 個工作周的 GitHub Trending 如果你 Pick 其他好玩、實用的 GitHub 項目,記得來 HelloGitHub issue 區和我們分享下喲

HelloGitHub 交流群現已全面開放,添加微信號:HelloGitHub 為好友入群,可同前端、Java、Go 等各界大佬談笑風生、切磋技術~

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

【其他文章推薦】

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

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

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

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

新北清潔公司,居家、辦公、裝潢細清專業服務

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

Netty源碼分析之自定義編解碼器

在日常的網絡開發當中,協議解析都是必須的工作內容,Netty中雖然內置了基於長度、分隔符的編解碼器,但在大部分場景中我們使用的都是自定義協議,所以Netty提供了  MessageToByteEncoder<I>  與  ByteToMessageDecoder  兩個抽象類,通過繼承重寫其中的encode與decode方法實現私有協議的編解碼。這篇文章我們就對Netty中的自定義編解碼器進行實踐與分析。

一、編解碼器的使用

下面是MessageToByteEncoder與ByteToMessageDecoder使用的簡單示例,其中不涉及具體的協議編解碼。

創建一個sever端服務

EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        final CodecHandler codecHandler = new CodecHandler();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)
                    .handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            if (sslCtx != null) {
                                p.addLast(sslCtx.newHandler(ch.alloc()));
                            }
                            //添加編解碼handler
                            p.addLast(new MessagePacketDecoder(),new MessagePacketEncoder());
                            //添加自定義handler
                            p.addLast(codecHandler);
                        }
                    });

            // Start the server.
            ChannelFuture f = b.bind(PORT).sync();

繼承MessageToByteEncoder並重寫encode方法,實現編碼功能

public class MessagePacketEncoder extends MessageToByteEncoder<byte[]> {

    @Override
    protected void encode(ChannelHandlerContext ctx, byte[] bytes, ByteBuf out) throws Exception {
        //進行具體的編碼處理 這裏對字節數組進行打印
        System.out.println("編碼器收到數據:"+BytesUtils.toHexString(bytes));
        //寫入並傳送數據
        out.writeBytes(bytes);
    }
}

繼承ByteToMessageDecoder 並重寫decode方法,實現解碼功能

public class MessagePacketDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out){
        try {
            if (buffer.readableBytes() > 0) {
                // 待處理的消息包
                byte[] bytesReady = new byte[buffer.readableBytes()];
                buffer.readBytes(bytesReady);
                //進行具體的解碼處理
                System.out.println("解碼器收到數據:"+ByteUtils.toHexString(bytesReady));
                //這裏不做過多處理直接把收到的消息放入鏈表中,並向後傳遞
                out.add(bytesReady);
            
            }
        }catch(Exception ex) {
            
        }

    }

}

實現自定義的消息處理handler,到這裏其實你拿到的已經是編解碼后的數據

public class CodecHandler extends ChannelInboundHandlerAdapter{
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("CodecHandler收到數據:"+ByteUtils.toHexString((byte[])msg));
        byte[] sendBytes = new byte[] {0x7E,0x01,0x02,0x7e};
        ctx.write(sendBytes);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
}

運行一個客戶端模擬發送字節0x01,0x02,看一下輸出的執行結果

解碼器收到數據:0102
CodecHandler收到數據:0102
編碼器收到數據:7E01027E

 根據輸出的結果可以看到消息的入站與出站會按照pipeline中自定義的順序傳遞,同時通過重寫encode與decode方法實現我們需要的具體協議編解碼操作。

二、源碼分析

 通過上面的例子可以看到MessageToByteEncoder<I>與ByteToMessageDecoder分別繼承了ChannelInboundHandlerAdapter與ChannelOutboundHandlerAdapter,所以它們也是channelHandler的具體實現,並在創建sever時被添加到pipeline中, 同時為了方便我們使用,netty在這兩個抽象類中內置與封裝了一些其操作;消息的出站和入站會分別觸發write與channelRead事件方法,所以上面例子中我們重寫的encode與decode方法,也都是在父類的write與channelRead方法中被調用,下面我們就別從這兩個方法入手,對整個編解碼的流程進行梳理與分析。

1、MessageToByteEncoder

編碼需要操作的是出站數據,所以在MessageToByteEncoder的write方法中會調用我們重寫的encode具體實現, 把我們內部定義的消息實體編碼為最終要發送的字節流數據發送出去。

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        ByteBuf buf = null;
        try {
            if (acceptOutboundMessage(msg)) {//判斷傳入的msg與你定義的類型是否一致
                @SuppressWarnings("unchecked")
                I cast = (I) msg;//轉為你定義的消息類型
                buf = allocateBuffer(ctx, cast, preferDirect);//包裝成一個ByteBuf
                try {
                    encode(ctx, cast, buf);//傳入聲明的ByteBuf,執行具體編碼操作
                } finally {
                    /**
                     * 如果你定義的類型就是ByteBuf 這裏可以幫助你釋放資源,不需要在自己釋放
                     * 如果你定義的消息類型中包含ByteBuf,這裡是沒有作用,需要你自己主動釋放
                     */
                    ReferenceCountUtil.release(cast);//釋放你傳入的資源
                }

                //發送buf
                if (buf.isReadable()) {
                    ctx.write(buf, promise);
                } else {
                    buf.release();
                    ctx.write(Unpooled.EMPTY_BUFFER, promise);
                }
                buf = null;
            } else {
                //類型不一致的話,就直接發送不再執行encode方法,所以這裏要注意如果你傳遞的消息與泛型類型不一致,其實是不會執行的
                ctx.write(msg, promise);
            }
        } catch (EncoderException e) {
            throw e;
        } catch (Throwable e) {
            throw new EncoderException(e);
        } finally {
            if (buf != null) {
                buf.release();//釋放資源
            }
        }
    }

 MessageToByteEncoder的write方法要實現的功能還是比較簡單的,就是把你傳入的數據類型進行轉換和發送;這裡有兩點需要注意:

  • 一般情況下,需要通過重寫encode方法把定義的泛型類型轉換為ByteBuf類型, write方法內部自動幫你執行傳遞或發送操作;
  • 代碼中雖然有通過ReferenceCountUtil.release(cast)釋放你定義的類型資源,但如果定義的消息類中包含ByteBuf對象,仍需要主動釋放該對象資源;

2、ByteToMessageDecoder

從命名上就可以看出ByteToMessageDecoder解碼器的作用是把字節流數據編碼轉換為我們需要的數據格式

作為入站事件,解碼操作的入口自然是channelRead方法

 @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof ByteBuf) {//如果消息是bytebuff
            CodecOutputList out = CodecOutputList.newInstance();//實例化一個鏈表
            try {
                ByteBuf data = (ByteBuf) msg;
                first = cumulation == null;
                if (first) {
                    cumulation = data;
                } else {
                    cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data);
                }
                callDecode(ctx, cumulation, out);//開始解碼
            } catch (DecoderException e) {
                throw e;
            } catch (Exception e) {
                throw new DecoderException(e);
            } finally {
                if (cumulation != null && !cumulation.isReadable()) {//不為空且沒有可讀數據,釋放資源
                    numReads = 0;
                    cumulation.release();
                    cumulation = null;
                } else if (++ numReads >= discardAfterReads) {
                    // We did enough reads already try to discard some bytes so we not risk to see a OOME.
                    // See https://github.com/netty/netty/issues/4275
                    numReads = 0;
                    discardSomeReadBytes();
                }

                int size = out.size();
                decodeWasNull = !out.insertSinceRecycled();
                fireChannelRead(ctx, out, size);//向下傳遞消息
                out.recycle();
            }
        } else {
            ctx.fireChannelRead(msg);
        }
    }

callDecode方法內部通過while循環的方式對ByteBuf數據進行解碼,直到其中沒有可讀數據 

    protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        try {
            while (in.isReadable()) {//判斷ByteBuf是還有可讀數據
                int outSize = out.size();//獲取記錄鏈表大小

                if (outSize > 0) {//判斷鏈表中是否已經有數據
                    fireChannelRead(ctx, out, outSize);//如果有數據繼續向下傳遞
                    out.clear();//清空鏈表

                    // Check if this handler was removed before continuing with decoding.
                    // If it was removed, it is not safe to continue to operate on the buffer.
                    //
                    // See:
                    // - https://github.com/netty/netty/issues/4635
                    if (ctx.isRemoved()) {
                        break;
                    }
                    outSize = 0;
                }

                int oldInputLength = in.readableBytes();
                decodeRemovalReentryProtection(ctx, in, out);//開始調用decode方法

                // Check if this handler was removed before continuing the loop.
                // If it was removed, it is not safe to continue to operate on the buffer.
                //
                // See https://github.com/netty/netty/issues/1664
                if (ctx.isRemoved()) {
                    break;
                }

                //這裏如果鏈表為空且bytebuf沒有可讀數據,就跳出循環
                if (outSize == out.size()) {
                    if (oldInputLength == in.readableBytes()) {
                        break;
                    } else {//有可讀數據繼續讀取
                        continue;
                    }
                }

                if (oldInputLength == in.readableBytes()) {//beytebuf沒有讀取,但卻進行了解碼
                    throw new DecoderException(
                            StringUtil.simpleClassName(getClass()) +
                                    ".decode() did not read anything but decoded a message.");
                }

                if (isSingleDecode()) {//是否設置了每條入站數據只解碼一次,默認false
                    break;
                }
            }
        } catch (DecoderException e) {
            throw e;
        } catch (Exception cause) {
            throw new DecoderException(cause);
        }
    }

decodeRemovalReentryProtection方法內部會調用我們重寫的decode解碼實現

    final void decodeRemovalReentryProtection(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
            throws Exception {
        decodeState = STATE_CALLING_CHILD_DECODE;//標記狀態
        try {
            decode(ctx, in, out);//調用我們重寫的decode解碼實現
        } finally {
            boolean removePending = decodeState == STATE_HANDLER_REMOVED_PENDING;
            decodeState = STATE_INIT;
            if (removePending) {//這裏判斷標記,防止handlerRemoved事件與解碼操作衝突
                handlerRemoved(ctx);
            }
        }
    }

channelRead方法中接受到數據經過一系列邏輯處理,最終會調用我們重寫的decode方法實現具體的解碼功能;在decode方法中我們只需要ByteBuf類型的數據解析為我們需要的數據格式直接放入 List<Object> out鏈表中即可,ByteToMessageDecoder會自動幫你向下傳遞消息。

三、總結

通過上面的講解,我們可以對Netty中內置自定義編解碼器MessageToByteEncoder與ByteToMessageDecoder有一定的了解,其實它們本質上是Netty封裝的一組專門用於自定義編解碼的channelHandler實現類。在實際開發當中基於這兩個抽象類的實現非常具有實用性,所以在這裏稍作分析, 其中如有不足與不正確的地方還望指出與海涵。

 

關注微信公眾號,查看更多技術文章。

 

 

轉載說明:未經授權不得轉載,授權后務必註明來源(註明:來源於公眾號:架構空間, 作者:大凡)

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

【其他文章推薦】

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

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

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

※幫你省時又省力,新北清潔一流服務好口碑

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

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