一行代碼引來的安全漏洞就讓我們丟失了整個服務器的控制權

之前在某廠的某次項目開發中,項目組同學設計和實現了一個“引以為傲”,額,有點擴張,不過自認為還說得過去的 feature,結果臨上線前被啪啪打臉,因為實現過程中因為一行代碼(沒有標題黨,真的是一行代碼)帶來的安全漏洞讓我們丟失了整個服務器控制權(測試環境)。多虧了上線之前有公司安全團隊的人會對代碼進行掃描,才讓這個漏洞被扼殺在搖籃里。

下面我們就一起來看看這個事故,啊,不對,是故事。

背景說明

我們的項目是一個面向全球用戶的 Web 項目,用 SpringBoot 開發。在項目開發過程中,離不開各種異常信息的處理,比如表單提交參數不符合預期,業務邏輯的處理時離不開各種異常信息(例如網絡抖動等)的處理。於是利用 SpringBoot 各種現成的組件支持,設計了一個統一的異常信息處理組件,統一管理各種業務流程中可能出現的錯誤碼和錯誤信息,通過國際化的資源配置文件進行統一輸出給用戶。

統一錯誤信息配置管理

我們的用戶遍布全球,為了給各個國家用戶比較好的體驗會進行不同的翻譯。具體而言,實現的效果如下,為了方便理解,以“找回登錄密碼”這樣一個業務場景來進行闡述說明。

假設找回密碼時,需要用戶輸入手機或者郵箱驗證碼,假設這個時候用戶輸入的驗證碼通過後台數據庫(可能是Redis)對比發現已經過期。在業務代碼中,只需要簡單的 throw new ErrorCodeException(ErrorCodes.AUTHCODE_EXPIRED) 即可。具體而言,針對不同國家地區不同的語言看到的效果不一樣:

  • 中文用戶看到的提示就是“您輸入的驗證碼已過期,請重新獲取”;
  • 歐美用戶看到的效果是“The verification code you input is expired, …”;
  • 德國用戶看到的是:“Der von Ihnen eingegebene Verifizierungscode ist abgelaufen, bitte wiederholen” 。(我瞎找的翻譯,不一定準)
  • ……

統一錯誤信息配置管理代碼實現

關鍵信息其實就在於一個 GlobalExceptionHandler,對所有Controller 入口進行 AOP 攔截,根據不同的錯誤信息,獲取相應資源文件配置的 key,並從語言資源文件中讀取不同國家的錯誤翻譯信息。

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(BadRequestException.class)
    @ResponseBody
    public ResponseEntity handle(HttpServletRequest request, BadRequestException e){
        String i18message = getI18nMessage(e.getKey(), request);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Response.error(e.getCode(), i18message));
    }
    
    @ExceptionHandler(ErrorCodeException.class)
    @ResponseBody
    public ResponseEntity handle(HttpServletRequest request, ErrorCodeException e){
        String i18message = getI18nMessage(e.getKey(), request);
        return ResponseEntity.status(HttpStatus.OK).body(Response.error(e.getCode(), i18message));
    }
}

 

不同語言的資源文件示例

private String getI18nMessage(String key, HttpServletRequest request) {
   try {
       return messageSource.getMessage(key, null, LanguaggeUtils.currentLocale(request));
   } catch (Exception e) {
       // log
       return key;
   }
}

 

詳細代碼實現可以參考本人之前寫的這篇文章一文教你實現 SpringBoot 中的自定義 Validator 和錯誤信息國際化配置,上面有附完整的代碼實現。

基於註解的表單校驗(含自定義註解)

還有一種常見的業務場景就是後端接口需要對用戶提交的表單進行校驗。以“註冊用戶”這樣的場景舉例說明, 註冊用戶時,往往會提交昵稱,性別,郵箱等信息進行註冊,簡單起見,就以這 3 個屬性為例。

定義的表單如下:

public class UserRegForm {
 private String nickname;
 private String gender;
 private String email;
}

 

對於表單的約束,我們有:

  • 昵稱字段:“nickname” 必填,長度必須是 6 到 20 位;
  • 性別字段:“gender” 可選,如果填了,就必須是“Male/Female/Other/”中的一種。說啥,除了男女還有其他?對,是的。畢竟全球用戶嘛,你去看看非死不可,還有更多。
  • 郵箱: “email”,必填,必須滿足郵箱格式。

對於以上約束,我們只需要在對應的字段上添加如下註解即可。

public class UserRegForm {
 @Length(min = 6, max = 20, message = "validate.userRegForm.nickname")
 private String nickname;

 @Gender(message="validate.userRegForm.gender")
 private String gender;

 @NotNull
 @Email(message="validate.userRegForm.email")
 private String email;
}

 

然後在各個語言資源文件中配置好相應的錯誤信息提示即可。其中, @Gender 就是一個自定義的註解。

基於含自定義註解的表單校驗關鍵代碼

自定義註解的實現主要的其實就是一個自定義註解的定義以及一個校驗邏輯。 例如定義一個自定義註解 CustomParam

@Documented
@Constraint(validatedBy = CustomValidator.class)
@Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomParam {
    String message() default "name.tanglei.www.validator.CustomArray.defaultMessage";

    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default { };

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
    @interface List {
        CustomParam[] value();
    }
}

 

校驗邏輯的實現 CustomValidator

public class CustomValidator implements ConstraintValidator<CustomParam, String> {
    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        if (null == s || s.isEmpty()) {
            return true;
        }
        if (s.equals("tanglei")) {
            return true;
        } else {
            error(constraintValidatorContext, "Invalid params: " + s);
            return false;
        }
    }

    @Override
    public void initialize(CustomParam constraintAnnotation) {
    }

    private static void error(ConstraintValidatorContext context, String message) {
        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
    }
}

 

上面例子只為了闡述說明問題,其中校驗邏輯沒有實際意義,這樣,如果輸入參數不滿足條件,就會明確提示用戶輸入的哪個參數不滿足條件。例如輸入參數 xx,則會直接提示:Invalid params: xx

這個跟第一部分的處理方式類似,因為現有的 validator 組件實現中,如果違反相應的約束也是一種拋異常的方式實現的,因此只需要在上述的 GlobalExceptionHandler中添加相應的異常信息即可,這裏就不詳述了。 這不是本文的重點,這裏就不詳細闡述了。 詳細代碼實現可以參考本人之前寫的這篇文章一文教你實現 SpringBoot 中的自定義 Validator 和錯誤信息國際化配置,上面有附完整的代碼實現。

場景重現

一切都顯得很完美,直到上線前代碼提交至安全團隊掃描,就被“啪啪打臉”,掃描報告反饋了一個嚴重的安全漏洞。而這個安全漏洞,屬於很高危的遠程代碼執行漏洞。

用前文提到的自定義 Validator,輸入的參數用: “1+1=${1+1}”,看看效果:

太 TM 神奇了,居然幫我運算出來了,返回 "message": "Invalid params: 1+1=2"

問題就出現在實現自定義註解進行校驗的這行代碼(如下圖所示):

其實,最開始的時候,這裏直接返回了“Invalid params”,當初為了更好的用戶體驗,要明確告訴用戶哪個參數沒有通過校驗,因此在輸出的提示上加上了用戶輸入的字段,也就是上面的"Invalid params: " + s,沒想到,這闖了大禍了(回過頭來想,感覺這裏沒必要這麼詳細啊,因為前端已經有相應的校驗了,正常情況下回攔住,針對不守規矩的用非常規手段來的接口請求,直接返回校驗不通過就行了,畢竟不是對外提供的 OpenAPI 服務)。

仔細看,這個方法實際上是 ConstraintValidatorContext這個接口中聲明的,看方法名字其實能知道輸入參數是一個字符串模板,內部會進行解析替換的(這其實也符合“見名知意”的良好編程習慣)。(教訓:大家應該把握好自己寫的每一行代碼背後實際在做什麼。)

/* ......
 * @param messageTemplate new un-interpolated constraint message
 * @return returns a constraint violation builder
 */
ConstraintViolationBuilder buildConstraintViolationWithTemplate(String messageTemplate);

 

這個 case,源碼調試進去之後,就能跟蹤到執行翻譯階段,在如下方法中: org.hibernate.validator.messageinterpolation.AbstractMessageInterpolator.interpolateMessage

再往後,就是表達式求值了。

以為就這樣就完了嗎?

剛開始感覺,能幫忙算簡單的運算規則也就完了吧,你還能把我怎麼樣?其實這個相當於暴露了一個入口,支持用戶輸入任意 EL 表達式進行執行。網上通過關鍵字 “SpEL表達式注入漏洞” 找找,就能發現事情並沒有想象中那麼簡單。

我們構造恰當的 EL 表達式(注意各種轉義,下文的輸入參數相對比較明顯在做什麼了,實際上還有更多黑科技,比如各種二進制轉義編碼啊等等),就能直接執行輸入代碼,例如:可以直接執行命令,“ls -al”, 返回了一個 UNIXProcess 實例,命令已經被執行過了。

比如,我們執行個打開計算器的命令,搞個計算器玩玩~

我錄製了一個動圖,來個演示可能更生動一些。

這還得了嗎?這相當於提供了一個 webshell 的功能呀,你看想運行啥命令就能運行啥命令,例如 ping 本人博客地址(ping www.tanglei.name),下面動圖演示一下整個過程(從運行 ping 到 kill ping)。

我錄製了一個視頻,點擊這裏可以訪問。

豈不是直接創建一個用戶,然後遠程登錄就可以了。後果很嚴重啊,別人想幹嘛就幹嘛了。

我們跟蹤下對應的代碼,看看內部實現,就會“恍然大悟”了。

經驗教訓

幸虧這個漏洞被扼殺在搖籃里,否則後果還真的挺嚴重的。通過這個案例,我們有啥經驗和教訓呢?那就是作為程序員,我們要對每一行代碼都保持“敬畏”之心。也許就是因為你的不經意的一行代碼就帶來了嚴重的安全漏洞,要是不小心被壞人利用,輕則……重則……(自己想象吧)

此外,我們也應該看到,程序員需要對常見的安全漏洞(例如XSS/CSRF/SQL注入等等)有所了解,並且要有足夠的安全意識(其實有時候研究一些安全問題還挺好玩的,比如這篇《RSA算法及一種”旁門左道”的攻擊方式》就比較有趣)。例如:

  • 用戶權限分離:運行程序的用戶不應該用 root,例如新建一個“web”或者“www”之類的用戶,並設置該用戶的權限,比如不能有可執行 xx 的權限之類的。本文 case,如果權限進行了分離(遵循最小權限原則),應該也不會這麼嚴重。(本文就剛好是因為是測試環境,所以沒有強制實施)
  • 任何時候都不要相信用戶的輸入,必須對用戶輸入的進行校驗和過濾,又特別是針對公網上的應用。
  • 敏感信息加密保存。退一萬步講,假設攻擊者攻入了你的服務器,如果這個時候,你的數據庫賬戶信息等配置都直接明文保存在服務器中。那數據庫也被脫走了。

如果可能的話,需要對開發者的代碼進行漏洞掃描。一些常見的安全漏洞現在應該是有現成的工具支持的。另外,讓專業的人做專業的事情,例如要有安全團隊,可能你會說你們公司沒有不也活的好好的,哈哈,只不過可能還沒有被壞人盯上而已,壞人也會考慮到他們的成本和預期收益的,當然這就更加對我們開發者提高了要求。一些敏感權限盡量控制在少部分人手中,配合相應的流程來支撐(不得不說,大公司繁瑣的流程還是有一定道理的)。

畢竟我不是專業研究Web安全的,以上說得可能也不一定對,如果你有不同意見或者更好的建議歡迎留言參与討論。

這篇文章從寫代碼做實驗,到錄屏做視頻動圖等等耗時還蠻久的(好幾個周末的時間呢),原創真心不易,希望你能幫我個小忙唄,如果本文內容你覺得有所啟發,有所收穫,請幫忙點個“在看”唄,或者轉發分享讓更多的小夥伴看到。

精彩推薦
  • 一個由跨平台產生的浮點數bug | 有你意想不到的結果。
  • RSA算法及一種”旁門左道”的攻擊方式。
  • 震驚! 阿里的程序員也不過如此,竟被一個簡單的 SQL 查詢難住。
  • 面了7輪 Google,最終還是逃不脫被掛的命運。

文章首發於本人微信公眾號(ID:tangleithu),請感興趣的同學關注我的微信公眾號,及時獲取技術乾貨。

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

※推薦台中搬家公司優質服務,可到府估價

03 . Prometheus監控容器和HTTP探針應用

Eeporter是什麼及來源?

是什麼?

廣義上講所有可以向Prometheus提供監控樣本數據的程序都可以被稱為一個Exporter。而Exporter的一個實例稱為target,如下所示,Prometheus通過輪詢的方式定期從這些target中獲取樣本數據:

來源有哪些?

社區提供的

Prometheus社區提供了豐富的Exporter實現,涵蓋了從基礎設施,中間件以及網絡等各個方面的監控功能。這些Exporter可以實現大部分通用的監控需求。下錶列舉一些社區中常用的Exporter:

範圍 常用Exporter
數據庫 MySQL Exporter, Redis Exporter, MongoDB Exporter, MSSQL Exporter等
硬件 Apcupsd Exporter,IoT Edison Exporter, IPMI Exporter, Node Exporter等
消息隊列 Beanstalkd Exporter, Kafka Exporter, NSQ Exporter, RabbitMQ Exporter等
存儲 Ceph Exporter, Gluster Exporter, HDFS Exporter, ScaleIO Exporter等
HTTP服務 Apache Exporter, HAProxy Exporter, Nginx Exporter等
API服務 AWS ECS Exporter, Docker Cloud Exporter, Docker Hub Exporter, GitHub Exporter等
日誌 Fluentd Exporter, Grok Exporter等
監控系統 Collectd Exporter, Graphite Exporter, InfluxDB Exporter, Nagios Exporter, SNMP Exporter等
其他 Blockbox Exporter, JIRA Exporter, Jenkins Exporter, Confluence Exporter等

用戶自定義的

除了直接使用社區提供的Exporter程序以外,用戶還可以基於Prometheus提供的Client Library創建自己的Exporter程序,目前Promthues社區官方提供了對以下編程語言的支持:Go、Java/Scala、Python、Ruby。同時還有第三方實現的如:Bash、C++、Common Lisp、Erlang,、Haskeel、Lua、Node.js、PHP、Rust等。

Exporter的運行方式

從Exporter的運行方式來講,又可以分為

獨立使用的

以我們已經使用過的Node Exporter為例,由於操作系統本身並不直接支持Prometheus,同時用戶也無法通過直接從操作系統層面上提供對Prometheus的支持。因此,用戶只能通過獨立運行一個程序的方式,通過操作系統提供的相關接口,將系統的運行狀態數據轉換為可供Prometheus讀取的監控數據。 除了Node Exporter以外,比如MySQL Exporter、Redis Exporter等都是通過這種方式實現的。 這些Exporter程序扮演了一个中間代理人的角色。

集成到應用中的

為了能夠更好的監控系統的內部運行狀態,有些開源項目如Kubernetes,ETCD等直接在代碼中使用了Prometheus的Client Library,提供了對Prometheus的直接支持。這種方式打破的監控的界限,讓應用程序可以直接將內部的運行狀態暴露給Prometheus,適合於一些需要更多自定義監控指標需求的項目。

Exporter規範

所有的Exporter程序都需要按照Prometheus的規範,返回監控的樣本數據。以Node Exporter為例,當訪問/metrics地址時會返回以下內容:

# HELP node_cpu Seconds the cpus spent in each mode.
# TYPE node_cpu counter
node_cpu{cpu="cpu0",mode="idle"} 362812.7890625
# HELP node_load1 1m load average.
# TYPE node_load1 gauge
node_load1 3.0703125

這是一種基於文本的格式規範,在Prometheus 2.0之前的版本還支持Protocol buffer規範。相比於Protocol buffer文本具有更好的可讀性,以及跨平台性。Prometheus 2.0的版本也已經不再支持Protocol buffer。

Exporter返回的樣本數據,主要由三個部分組成:樣本的一般註釋信息(HELP),樣本的類型註釋信息(TYPE)和樣本。Prometheus會對Exporter響應的內容逐行解析:

如果當前行以# HELP開始,Prometheus將會按照以下規則對內容進行解析,得到當前的指標名稱以及相應的說明信息:

# HELP <metrics_name> <doc_string>

如果當前行以# TYPE開始,Prometheus會按照以下規則對內容進行解析,得到當前的指標名稱以及指標類型:

# TYPE <metrics_name> <metrics_type>

TYPE註釋行必須出現在指標的第一個樣本之前。如果沒有明確的指標類型需要返回為untyped。 除了# 開頭的所有行都會被視為是監控樣本數據。 每一行樣本需要滿足以下格式規範:

metric_name [
  "{" label_name "=" `"` label_value `"` { "," label_name "=" `"` label_value `"` } [ "," ] "}"
] value [ timestamp ]

其中metric_name和label_name必須遵循PromQL的格式規範要求。value是一個float格式的數據,timestamp的類型為int64(從1970-01-01 00:00:00以來的毫秒數),timestamp為可選默認為當前時間。具有相同metric_name的樣本必須按照一個組的形式排列,並且每一行必須是唯一的指標名稱和標籤鍵值對組合。

需要特別注意的是對於histogram和summary類型的樣本。需要按照以下約定返回樣本數據:

1 . 類型為summary或者histogram的指標x,該指標所有樣本的值的總和需要使用一個單獨的x_sum指標表示

2 . 類型為summary或者histogram的指標x,該指標所有樣本的總數需要使用一個單獨的x_count指標表示。

3 . 對於類型為summary的指標x,其不同分位數quantile所代表的樣本,需要使用單獨的x{quantile=”y”}表示。

4 . 對於類型histogram的指標x為了表示其樣本的分佈情況,每一個分佈需要使用x_bucket{le=”y”}表示,其中y為當前分佈的上位數。同時必須包含一個樣本x_bucket{le=”+Inf”},並且其樣本值必須和x_count相同。

5 . 對於histogram和summary的樣本,必須按照分位數quantile和分佈le的值的遞增順序排序。

以下是類型為histogram和summary的樣本輸出示例

# A histogram, which has a pretty complex representation in the text format:
# HELP http_request_duration_seconds A histogram of the request duration.
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{le="0.05"} 24054
http_request_duration_seconds_bucket{le="0.1"} 33444
http_request_duration_seconds_bucket{le="0.2"} 100392
http_request_duration_seconds_bucket{le="+Inf"} 144320
http_request_duration_seconds_sum 53423
http_request_duration_seconds_count 144320

# Finally a summary, which has a complex representation, too:
# HELP rpc_duration_seconds A summary of the RPC duration in seconds.
# TYPE rpc_duration_seconds summary
rpc_duration_seconds{quantile="0.01"} 3102
rpc_duration_seconds{quantile="0.05"} 3272
rpc_duration_seconds{quantile="0.5"} 4773
rpc_duration_seconds_sum 1.7560473e+07
rpc_duration_seconds_count 2693

指定樣式格式的版本
在Exporter響應的HTTP頭信息中,可以通過Content-Type指定特定的規範版本,例如:

HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 2906
Content-Type: text/plain; version=0.0.4
Date: Sat, 17 Mar 2018 08:47:06 GMT

其中version用於指定Text-based的格式版本,當沒有指定版本的時候,默認使用最新格式規範的版本。同時HTTP響應頭還需要指定壓縮格式為gzip。

容器監控

Docker是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然後發布到任何流行的Linux/Windows/Mac機器上。容器鏡像正成為一個新的標準化軟件交付方式。

例如,可以通過一下命令快速在本地啟動一個Nginx服務:

安裝docker
# 安裝一些必要的系統工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加軟件源信息
# docker 官方源
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 阿里雲源
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

sudo yum makecache fast

# CentOS7安裝 Docker-ce
yum -y install docker-ce   


mkdir /etc/docker
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}

# 啟動Docker後台服務
systemctl start docker && systemctl enable docker
systemctl daemon-reload                 # 守護進程重啟

# 運行一個nginx做測試
docker run -itd nginx

為了能夠獲取到Docker容器的運行狀態,用戶可以通過Docker的stats命令獲取到當前主機上運行容器的統計信息,可以查看容器的CPU利用率、內存使用量、網絡IO總量以及磁盤IO總量等信息。

docker stats
CONTAINER           CPU %      MEM USAGE / LIMIT     MEM %      NET I/O         BLOCK I/O   PIDS
9a1648bec3b2        0.30%      196KiB / 3.855GiB     0.00%      828B / 0B       827kB / 0B  1
# 除了使用命令以外,用戶還可以通過docker提供的http api查看容器的監控統計信息.

使用CAdvisor

CAdvisor是Google開源的一款用於展示和分析容器運行狀態的可視化工具。通過在主機上運行CAdvisor用戶可以輕鬆的獲取到當前主機上容器的運行統計信息,並以圖表的形式向用戶展示。

在本地運行CAdvisor也非常簡單,直接運行一下命令即可:

docker run \
  --volume=/:/rootfs:ro \
  --volume=/var/run:/var/run:rw \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  --publish=8080:8080 \
  --detach=true \
  --name=cadvisor \
  google/cadvisor:latest
# 通過訪問http://localhost:8080可以查看,當前主機上容器的運行狀態.

CAdvisor是一個簡單易用的工具,相比於使用Docker命令行工具,用戶不用再登錄到服務器中即可以可視化圖表的形式查看主機上所有容器的運行狀態。

而在多主機的情況下,在所有節點上運行一個CAdvisor再通過各自的UI查看監控信息顯然不太方便,同時CAdvisor默認只保存2分鐘的監控數據。好消息是CAdvisor已經內置了對Prometheus的支持。訪問http://localhost:8080/metrics即可獲取到標準的Prometheus監控樣本輸出:

下面列舉了一些CAdvisor中獲取的典型監控指標

指標名稱 類型 含義
gauge 再過去10秒內容器CPU的平均負載
container_cpu_usage_seconds_total
指標名稱 類型 含義
container_cpu_load_average_10s gauge 過去10秒內容器CPU的平均負載
container_cpu_usage_seconds_total counter 容器在每個CPU內核上的累積佔用時間 (單位:秒)
container_cpu_system_seconds_total counter System CPU累積佔用時間(單位:秒)
container_cpu_user_seconds_total counter User CPU累積佔用時間(單位:秒)
container_fs_usge_bytes gauge 容器中文件系統的使用量(單位:字節)
container_network_receive_bytes_total counter 容器網絡累計接受數據總量(單位: 字節)
container_network_transmit_bytes_total counter 容器網絡累計傳輸數據總量(單位: 字節)

與Prometheus集成

修改/etc/prometheus/prometheus.yml,將cAdvisor添加監控數據採集任務目標當中:

  - job_name: 'docker'
    static_configs:
    - targets: ['172.19.0.27:8080']

systemctl restart prometheus

啟動Prometheus服務,可以在Prometheus UI中看到當前所有的Target狀態:

當能夠正常採集到cAdvisor的樣本數據后,可以通過一下錶達式計算容器的CPU使用率.

sum(irate(container_cpu_usage_seconds_total{image!=""}[1m])) without (cpu)

查詢容器內存使用量(單位: 字節)

container_memory_usage_bytes{image!=""}

查詢容器網絡接收量速率(單位: 字節/秒)

sum(rate(container_network_receive_bytes_total{image!=""}[1m])) without (interface)

查詢容器網絡傳輸量速率

sum(rate(container_network_transmit_bytes_total{image!=""}[1m])) without (interface)

查詢容器文件系統讀取速率

sum(rate(container_fs_reads_bytes_total{image!=""}[1m])) without (device)

# 為了方便看出效果,我們使用dd命令
docker exec -it 628d /bin/bash
dd if=/dev/zero of=test bs=1M count=1000

  • 查詢容器文件系統寫入速率(單位: 字節/秒)
sum(rate(container_fs_writes_bytes_total{image!=""}[1m])) without (device)

Prometheus網絡探測

接下來我們主要介紹Prometheus下如何進行白盒監控,我們之前監控主機的資源用量、容器的運行狀態、數據庫中間件的運行數據。 這些都是支持業務和服務的基礎設施,通過白盒能夠了解其內部的實際運行狀態,通過對監控指標的觀察能夠預判可能出現的問題,從而對潛在的不確定因素進行優化。而從完整的監控邏輯的角度,除了大量的應用白盒監控以外,還應該添加適當的黑盒監控。
黑盒監控即以用戶的身份測試服務的外部可見性,常見的黑盒監控包括HTTP探針、TCP探針等用於檢測站點或者服務的可訪問性,以及訪問效率等。

黑盒監控相較於白盒監控最大的不同在於黑盒監控是以故障為導向當故障發生時,黑盒監控能快速發現故障,而白盒監控則側重於主動發現或者預測潛在的問題。一個完善的監控目標是要能夠從白盒的角度發現潛在問題,能夠在黑盒的角度快速發現已經發生的問題。

安裝Blackbox Exporter

Blackbox Exporter是Prometheus社區提供的官方黑盒監控解決方案,其允許用戶通過:HTTP、HTTPS、DNS、TCP以及ICMP的方式對網絡進行探測。用戶可以直接使用go get命令獲取Blackbox Exporter源碼並生成本地可執行文件:

下載安裝blackbox_exporter

wget https://github.com/prometheus/blackbox_exporter/releases/download/v0.16.0/blackbox_exporter-0.16.0.linux-amd64.tar.gz

tar xvf blackbox_exporter-0.16.0.linux-amd64.tar.gz -C /usr/local/prometheus/
mv blackbox_exporter-0.16.0.linux-amd64/ blackbox_exporter
useradd prometheus
chown -R prometheus:prometheus /usr/local/prometheus/

vim /usr/lib/systemd/system/blackbox_exporter.service
[Unit]
Description=blackbox_exporter
After=network.target

[Service]
Type=simple
User=prometheus
ExecStart=/usr/local/prometheus/blackbox_exporter/blackbox_exporter --config.file=/usr/local/prometheus/blackbox_exporter/blackbox.yml
Restart=on-failure

[Install]
WantedBy=multi-user.target

systemctl enable blackbox_exporter.service
systemctl start blackbox_exporter.service

運行Blackbox Exporter時,需要用戶提供探針的配置信息,這些配置信息可能是一些自定義的HTTP頭信息,也可能是探測時需要的一些TSL配置,也可能是探針本身的驗證行為。在Blackbox Exporter每一個探針配置稱為一個module,並且以YAML配置文件的形式提供給Blackbox Exporter。 每一個module主要包含以下配置內容,包括探針類型(prober)、驗證訪問超時時間(timeout)、以及當前探針的具體配置項:

# 探針類型:http、 tcp、 dns、 icmp.
prober: <prober_string>
# 超時時間
[ timeout: <duration> ]
# 探針的詳細配置,最多只能配置其中的一個
[ http: <http_probe> ]
[ tcp: <tcp_probe> ]
[ dns: <dns_probe> ]
[ icmp: <icmp_probe> ]

下面是一個簡化的探針配置文件blockbox.yml,包含兩個HTTP探針配置項

modules:
  http_2xx:
    prober: http
    http:
      method: GET
  http_post_2xx:
    prober: http
    http:
      method: POST

通過運行一下命令,並指定使用的探針設置文件啟動Blockbox Exporter實例:

blackbox_exporter --config.file=/etc/prometheus/blackbox.yml
or
systemctl restart blackbox_exporter.service

啟動成功后,就可以通過訪問http://172.19.0.27:9115/probe?module=http_2xx&target=baidu.com對baidu.com進行探測。這裏通過在URL中提供module參數指定了當前使用的探針,target參數指定探測目標,探針的探測結果通過Metrics的形式返回:

# HELP probe_dns_lookup_time_seconds Returns the time taken for probe dns lookup in seconds
# TYPE probe_dns_lookup_time_seconds gauge
probe_dns_lookup_time_seconds 0.004359875
# HELP probe_duration_seconds Returns how long the probe took to complete in seconds
# TYPE probe_duration_seconds gauge
probe_duration_seconds 0.046153996
# HELP probe_failed_due_to_regex Indicates if probe failed due to regex
# TYPE probe_failed_due_to_regex gauge
probe_failed_due_to_regex 0
# HELP probe_http_content_length Length of http content response
# TYPE probe_http_content_length gauge
probe_http_content_length 81
# HELP probe_http_duration_seconds Duration of http request by phase, summed over all redirects
# TYPE probe_http_duration_seconds gauge
probe_http_duration_seconds{phase="connect"} 0.00105657
probe_http_duration_seconds{phase="processing"} 0.039457402
probe_http_duration_seconds{phase="resolve"} 0.004359875
probe_http_duration_seconds{phase="tls"} 0
probe_http_duration_seconds{phase="transfer"} 0.000337184
# HELP probe_http_last_modified_timestamp_seconds Returns the Last-Modified HTTP \
response header in unixtime
# TYPE probe_http_last_modified_timestamp_seconds gauge
probe_http_last_modified_timestamp_seconds 1.26330408e+09
# HELP probe_http_redirects The number of redirects
# TYPE probe_http_redirects gauge
probe_http_redirects 0
# HELP probe_http_ssl Indicates if SSL was used for the final redirect
# TYPE probe_http_ssl gauge
probe_http_ssl 0
# HELP probe_http_status_code Response HTTP status code
# TYPE probe_http_status_code gauge
probe_http_status_code 200
# HELP probe_http_uncompressed_body_length Length of uncompressed response body
# TYPE probe_http_uncompressed_body_length gauge
probe_http_uncompressed_body_length 81
# HELP probe_http_version Returns the version of HTTP of the probe response
# TYPE probe_http_version gauge
probe_http_version 1.1
# HELP probe_ip_protocol Specifies whether probe ip protocol is IP4 or IP6
# TYPE probe_ip_protocol gauge
probe_ip_protocol 4
# HELP probe_success Displays whether or not the probe was a success
# TYPE probe_success gauge
probe_success 1

從返回的樣本中,用戶可以獲取站點的DNS解析耗時,站點響應時間,HTTP響應狀態碼等等和站點訪問質量相關的監控指標,從而幫助管理員主動的發現故障和問題.

Prometheus集成

接下來,只需要在Prometheus下配置對Blockbox Exporter實例的採集任務即可、最直觀的配置方式.

  - job_name: 'baidu_http2xx_probe'
    params:
      module:
      - http_2xx
      target:
      - baidu.com
    metrics_path: /probe
    static_configs:
    - targets: ['172.19.0.27:9115']

  - job_name: 'prometheus_http2xx_probe'
    params:
      module:
      - http_2xx
      target:
      - prometheus.io
    metrics_path: /probe
    static_configs:
    - targets: ['172.19.0.27:9115']

systemctl restart prometheus

這裏分別配置了名為baidu_http2x_probe和prometheus_http2xx_probe的採集任務,並且通過params指定使用的探針(module)以及探測目標(target).

那問題就來了,假如我們有N個目標站點且都需要M種探測方式,那麼Prometheus中將包含N * M個採集任務,從配置管理的角度來說顯然是不可接受的。這裏我們也可以採用Relabling的方式對這些配置進行簡化,配置方式如下:

  - job_name: 'blackbox'
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets:
        - http://prometheus.io    # Target to probe with http.
        - https://prometheus.io   # Target to probe with https.
        - http://example.com:8080 # Target to probe with http on port 8080.
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: 172.19.0.27:9115

這裏針對每一個探針服務(如http_2xx)定義一個採集任務,並且直接將任務的採集目標定義為我們需要探測的站點,在採集樣本數據之前通過relabel_configs對採集任務進行動態配置.

* 第一步, 根據Target實例的地址,寫入__param_target標籤中,__param_<name>形式的標籤來表示,
	# 在採集任務時會在請求目標地址中添加<name>參數,等同於params的設置.
* 第二步,  獲取__param_target的值,並覆寫到instance標籤中.
* 第三步,  覆寫Target實例的__address__標籤值為BlockBox Exporter實例的訪問地址.

HTTP探針

HTTP探針是進行黑盒監控時最常用的探針之一,通過HTTP探針能夠網站或者HTTP服務建立有效的監控,包括其本身的可用性,以及用戶體驗相關的如響應時間等等。除了能夠在服務出現異常的時候及時報警,還能幫助系統管理員分析和優化網站體驗。

Blockbox Exporter中所有的探針均是以Module的信息進行配置。如下所示,配置了一個最簡單的HTTP探針:

modules:
  http_2xx_example:
    prober: http
    http:

通過prober配置項指定探針類型。配置項http用於自定義探針的探測方式,這裡有沒對http配置項添加任何配置,表示完全使用HTTP探針的默認配置,該探針將使用HTTP GET的方式對目標服務進行探測,並且驗證返回狀態碼是否為2XX,是則表示驗證成功,否則失敗。

自定義HTTP請求

HTTP服務通常會以不同的形式對外展現,有些可能就是一些簡單的網頁,而有些則可能是一些基於REST的API服務。 對於不同類型的HTTP的探測需要管理員能夠對HTTP探針的行為進行更多的自定義設置,包括:HTTP請求方法、HTTP頭信息、請求參數等。對於某些啟用了安全認證的服務還需要能夠對HTTP探測設置相應的Auth支持。對於HTTPS類型的服務還需要能夠對證書進行自定義設置。

如下所示,這裏通過method定義了探測時使用的請求方法,對於一些需要請求參數的服務,還可以通過headers定義相關的請求頭信息,使用body定義請求內容:

http_post_2xx:
    prober: http
    timeout: 5s
    http:
      method: POST
      headers:
        Content-Type: application/json
      body: '{}'

如果HTTP服務啟用了安全認證,Blockbox Exporter內置了對basic_auth的支持,可以直接設置相關的認證信息即可:

http_basic_auth_example:
    prober: http
    timeout: 5s
    http:
      method: POST
      headers:
        Host: "login.example.com"
      basic_auth:
        username: "username"
        password: "mysecret"

對於使用了Bear Token的服務也可以通過bearer_token配置項直接指定令牌字符串,或者通過bearer_token_file指定令牌文件。

對於一些啟用了HTTPS的服務,但是需要自定義證書的服務,可以通過tls_config指定相關的證書信息:

 http_custom_ca_example:
    prober: http
    http:
      method: GET
      tls_config:
        ca_file: "/certs/my_cert.crt"
  • 自定義探針行為
  • 在默認情況下HTTP探針只會對HTTP返回狀態碼進行校驗,如果狀態碼為2XX(200 <= StatusCode < 300)則表示探測成功,並且探針返回的指標probe_success值為1。
  • 如果用戶需要指定HTTP返回狀態碼,或者對HTTP版本有特殊要求,如下所示,可以使用valid_http_versions和valid_status_codes進行定義:
  http_2xx_example:
    prober: http
    timeout: 5s
    http:
      valid_http_versions: ["HTTP/1.1", "HTTP/2"]
      valid_status_codes: []

默認情況下,Blockbox返回的樣本數據中也會包含指標probe_http_ssl,用於表明當前探針是否使用了SSL:

# HELP probe_http_ssl Indicates if SSL was used for the final redirect
# TYPE probe_http_ssl gauge
probe_http_ssl 0

而如果用戶對於HTTP服務是否啟用SSL有強制的標準。則可以使用fail_if_ssl和fail_if_not_ssl進行配置。fail_if_ssl為true時,表示如果站點啟用了SSL則探針失敗,反之成功。fail_if_not_ssl剛好相反。

  http_2xx_example:
    prober: http
    timeout: 5s
    http:
      valid_status_codes: []
      method: GET
      no_follow_redirects: false
      fail_if_ssl: false
      fail_if_not_ssl: false

除了基於HTTP狀態碼,HTTP協議版本以及是否啟用SSL作為控制探針探測行為成功與否的標準以外,還可以匹配HTTP服務的響應內容。使用fail_if_matches_regexp和fail_if_not_matches_regexp用戶可以定義一組正則表達式,用於驗證HTTP返回內容是否符合或者不符合正則表達式的內容。

  http_2xx_example:
    prober: http
    timeout: 5s
    http:
      method: GET
      fail_if_matches_regexp:
        - "Could not connect to database"
      fail_if_not_matches_regexp:
        - "Download the latest version here"

最後需要提醒的時,默認情況下HTTP探針會走IPV6的協議。 在大多數情況下,可以使用preferred_ip_protocol=ip4強制通過IPV4的方式進行探測。在Bloackbox響應的監控樣本中,也會通過指標probe_ip_protocol,表明當前的協議使用情況:

# HELP probe_ip_protocol Specifies whether probe ip protocol is IP4 or IP6
# TYPE probe_ip_protocol gauge
probe_ip_protocol 6

除了支持對HTTP協議進行網絡探測以外,Blackbox還支持對TCP、DNS、ICMP等其他網絡協議![]

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

【其他文章推薦】

※回頭車貨運收費標準

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

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

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

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

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

蘋果電動車傳2021年問世、定價7.5萬美元

蘋果跨足電動車市場傳言甚囂塵上,投資機構Piper Jaffray資深分析師Gene Munster預測,蘋果將循設計、代工模式開發電動車,預計五年後也就是2021年上路。

蘋果電動車專案代號傳為「Titan」,Munster估計該電動車每輛定價約7.5萬美元,雖然全由蘋果設計,但生產製造有八成都將委外代工。

年初有報導指出,蘋果電動車計畫的幕後推手薩德斯基(Steve Zadesky)可能離職,即便如此,Munster仍舊看好蘋果電動車成功的機率超過五成,畢竟蘋果有錢、有人還有廣大粉絲做後盾。

據AppleInsider報導,蘋果電動車員工人數今年已膨脹至逾1千人,但可能也就是因為擴編速度太快,造成薩德斯基飯碗不保。

基本上,Munster認為電動車幾乎是營收成長動能的保證,因此蘋果不太可能放棄,最快2019、2020年應該會有初步產品展出。

(本文內容由授權提供)

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

【其他文章推薦】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

大陸寄台灣空運注意事項

大陸海運台灣交貨時間多久?

※避免吃悶虧無故遭抬價!台中搬家公司免費估價,有契約讓您安心有保障!

塞席爾特產 全球最大堅果海椰子瀕危

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

來自印度洋群島國家塞席爾的特殊植物「海椰子」,擁有全世界最大的種子,果實又酷似女子的骨盆,而被人津津樂道,有些地區文化還將它視為愛情靈藥,但也因為濫採而面臨絕種危機。

海椰子的果肉每公斤價值可達約100美元,一個完整的空殼則可以賣出兩倍的價格。然而幾個世紀以來的過度開採,海椰子幾乎快要從世上消失。2011年,國際自然保護聯盟將海椰子列為「瀕危物種」。

海椰子的果實是全世界最大的堅果,塞席爾政府採取強硬措施保護,規定一年最多只能採收2000顆,並禁止整顆出口,嚴格管控限制買賣,希望藉此保護這項獨特的植物避免滅絕。

自然資源管理
永續發展
國際新聞
東非
印度洋
多群島國家
椰子

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

【其他文章推薦】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

大陸寄台灣空運注意事項

大陸海運台灣交貨時間多久?

※避免吃悶虧無故遭抬價!台中搬家公司免費估價,有契約讓您安心有保障!

大眾因電池問題在美召回近5600輛e-Golf電動汽車

據路透社報導,大眾汽車週一稱,該公司將在美國市場上召回近5600萬輛e-Golf電動汽車,以便修復一個可能導致車輛熄火的電池問題。

大眾汽車表示,此次召回活動將覆蓋該公司自2014年11月份在美國市場上推出電動汽車以來所售出的全部車輛。

美國高速公路安全管理局週一稱,大眾汽車淨召回2015-2016年款e-Golf電動汽車,原因是其“高壓電池管理系統”中的軟體“可能會非故意地將短暫的內部電流浪湧/峰值分類為一種緊急的電池狀況”,從而導致車輛熄火。

大眾汽車已在此前承認其安裝了作弊軟體,從而使得58萬輛柴油動力汽車通過了美國的實驗室排放檢測,但其實際上路時的排放則遠高於標準,並因此而面臨諸多法律訴訟和業界批評。本月早些時候,該公司稱其美國部門首席執行官將會離職。

經銷商將為大眾汽車召回的電動汽車安裝更新好的軟體。去年,大眾汽車在美國總共售出了4232輛e-Golf汽車,遠高於2014年的357輛。在今年前兩個月時間裡,該公司則售出了526輛e-Golf。另外,此次召回活動還覆蓋了經銷商手中尚未售出的157輛電動汽車。

大眾汽車在其向美國高速公路安全管理局提交的檔中稱,這個問題可能會“導致高電壓電池突然被關閉,從而導致車輛的電動馬達熄火”。此前,大眾汽車曾在2015年初稱其首次收到了有關一樁熄火事件的資訊;在2015年6月份,一樁熄火事件則發生了在了一輛內部測試的車輛上。

最近幾個月以來,大眾汽車一直都在收到來自美國車主對熄火問題的投訴,從而促使其啟動了此次召回行動。

德國報紙《星期日世界報》曾在上個月報導稱,美國當局責令大眾汽車在該國生產電動汽車,從而作為彌補其操縱柴油車排放檢測過錯的一種方式。報導稱,美國環境保護署要求大眾汽車在其位於田納西州查特努加市的工廠生產電動汽車,並要求其幫助建設一個美國電動汽車充電站網路。美國環境保護署則拒絕就此報導置評。

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

【其他文章推薦】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

大陸寄台灣空運注意事項

大陸海運台灣交貨時間多久?

※避免吃悶虧無故遭抬價!台中搬家公司免費估價,有契約讓您安心有保障!

武漢肺炎拖慢氣候行動腳步 開發中國家恐交不出升級版減碳目標

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

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

【其他文章推薦】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

大陸寄台灣空運注意事項

大陸海運台灣交貨時間多久?

※避免吃悶虧無故遭抬價!台中搬家公司免費估價,有契約讓您安心有保障!

蘋果電動車專案未止步,挖角、研發行動低調進行中

市場瘋傳蘋果(Apple)將推出電動車,但至今仍只聞樓梯響。不過,海外媒體持續傳出蘋果電動車專案仍有大小動作,包含聘用新人、營運研發實驗室等,計畫看來並未胎死腹中。

蘋果電動車的計畫代號傳聞為「Titan」,傳言將在2019年正式開始出貨。蘋果電動車被報導將搭載自動駕駛技術,也會研究採用載運工具共享服務。

科技網站Electrek報導,蘋果將聘用原特斯拉(Tesla)工程開發副總裁Chris Porritt接替將要離職的Steve Zadesky,繼續執行與電動車專案相關的工作。而在這之前,蘋果已從特斯拉、福特、賓士、通用汽車等國際車廠與電池廠挖角專家,也聘用曾在福斯汽車、Nvidia等公司服務,專注於先進駕駛輔助系統與自動駕駛系統領域的專業人士。

此外,MacRumors也引述德國FrankfurterAllgemeine Zeitung報導,指出蘋果正在德國柏林暗中營運一座研發實驗室,共有15~20名研發人員,主要來自德國汽車產業界,或許正是蘋果電動車專案的一部分。

蘋果執行長Tim Cook過去曾參訪BMW的電動車i3產線,與電動車相關的傳言滿天飛。但蘋果對於電動車計畫始終守口如瓶,沒有正面回應。

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

【其他文章推薦】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

大陸寄台灣空運注意事項

大陸海運台灣交貨時間多久?

※避免吃悶虧無故遭抬價!台中搬家公司免費估價,有契約讓您安心有保障!

長安李偉:汽車智慧化分為智慧駕駛、智慧互聯和智慧交互三大發展範疇

未來汽車應該是什麼樣子?每個人都有自己的想像,每個車企都有各自的概念。而在差異化之中的相似之處是,許多企業都把智慧化作為發展方向,將無人駕駛作為嘗試的關鍵步驟。

長安汽車副總裁李偉表示智慧汽車可分為三大發展範疇:智慧駕駛、智慧互聯和智慧交互,而智慧駕駛又可分為四級技術水準。

智慧汽車的第一個範疇——智慧駕駛。對於長安汽車來講,智慧駕駛的一級技術已經成熟且在車上搭載,例如全速的自我調整巡航,緊急高速自動、緊急制動等,這些技術都已經在16款睿騁、CS75、逸動等車型上實現量產;智慧駕駛的二級技術,現在已經在做產品的研發和測試,二級技術主要是在一級自我調整巡航系統的基礎上升級,爭取把手解脫了,另外再加一個全自動倒車,二級的系統長安預計在2017年要量產;智慧駕駛三級技術水準是實現在高速路段的無人駕駛,從重慶到北京的整個無人駕駛汽車,實際上就是智慧駕駛的三級水準,長安汽車計畫在2018年實現整個技術儲備開發,全部匹配結束,2019年能夠得以上市。另外全自動化駕駛技術,就是智慧駕駛的最高級四級,長安努力爭取在2025年前能夠實現量產。

智能汽車的第二個範疇——智能互聯。李偉簡單舉了個例子,“現在長安在美國MTC現場進行叫智慧互聯汽車,它實際上是車和車可以通訊,車和路可以通訊,車和交通信號可以通訊等等。大家如果設想一下,我們現在長安目前的無人駕駛狀態,實際上是靠車本身的信號識別來判斷我的交通情況。未來如果說我們城市是智慧城市,我的交通都是數位的信號,在一公里之前車就能感知我那邊的紅綠燈什麼時候變紅燈什麼時候變綠燈,除了前邊車之外還有什麼車,通過車和車的通訊就會知道,這樣整個交通就會更加更加智慧。未來智慧城市,車聯網和車更加融合,這個車就會更加智慧,沒看到就會知道是什麼前邊情況,從這個方面來講,傳統自動智慧駕駛汽車和智慧互聯再有機的融合,就會帶來更聰明的汽車,就會有更自動的汽車。”

智能汽車的第三個範疇——智能交互。這個階段就是所謂的”人機交互”階段,需要發出什麼指令,不用操作,也不用說出來,只需要在腦袋裡一想,汽車就能執行相應命令。

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

【其他文章推薦】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

大陸寄台灣空運注意事項

大陸海運台灣交貨時間多久?

※避免吃悶虧無故遭抬價!台中搬家公司免費估價,有契約讓您安心有保障!

Kafka needs no Keeper(關於KIP-500的討論)

寫在前面的

最近看了Kafka Summit上的這個分享,覺得名字很霸氣,標題直接沿用了。這個分享源於社區的,大體的意思今後Apache Kafka不再需要ZooKeeper。整個分享大約40幾分鐘。完整看下來感覺乾貨很多,這裏特意總結出來。如果你把這個分享看做是《三國志》的話,那麼姑且就把我的這篇看做是裴松之注吧:)

客戶端演進

首先,社區committer給出了Kafka Java客戶端移除ZooKeeper依賴的演進過程。下面兩張圖總結了0.8.x版本和0.11.x版本(是否真的是從0.11版本開始的變化並不重要)及以後的功能變遷:在Kafka 0.8時代,Kafka有3個客戶端,分別是Producer、Consumer和Admin Tool。其中Producer負責向Kafka寫消息,Consumer負責從Kafka讀消息,而Admin Tool執行各種運維任務,比如創建或刪除主題等。其中Consumer的位移數據保存在ZooKeeper上,因此Consumer端的位移提交和位移獲取操作都需要訪問ZooKeeper。另外Admin Tool執行運維操作也要訪問ZooKeeper,比如在對應的ZooKeeper znode上創建一個臨時節點,然後由預定義的Watch觸發相應的處理邏輯。

後面隨着Kafka的演進,社區引入了__consumer_offsets位移主題,同時定義了OffsetFetch和OffsetCommit等新的RPC協議,這樣Consumer的位移提交和位移獲取操作全部轉移到與位移主題進行交互,避免了對ZooKeeper的訪問。同時社區引入了新的運維工具AdminClient以及相應的CreateTopics、DeleteTopics、AlterConfigs等RPC協議,替換了原先的Admin Tool,這樣創建和刪除主題這樣的運維操作也完全移動Kafka這一端來做,就像下面右邊這張圖展示的:

至此, Kafka的3個客戶端基本上都不需要和ZooKeeper交互了。應該說移除ZooKeeper的工作完成了大部分,但依然還有一部分工作要在ZooKeeper的幫助下完成,即Consumer的Rebalance操作。在0.8時代,Consumer Group的管理是交由ZooKeeper完成的,包括組成員的管理和訂閱分區的分配。這個設計在新版Consumer中也得到了修正。全部的Group管理操作交由Kafka Broker端新引入的Coordinator組件來完成。要完成這些工作,Broker端新增了很多RPC協議,比如JoinGroup、SyncGroup、Heartbeat、LeaveGroup等。

  

此時,Kafka的Java客戶端除了AdminClient還有一點要依賴ZooKeeper之外,所有其他的組件全部擺脫了對ZooKeeper的依賴。

之後,社區引入了Kafka安全層,實現了對用戶的認證和授權。這個額外的安全層也是不需要訪問ZooKeeper的,因此之前依賴ZooKeeper的客戶端是無法“享用”這個安全層。一旦啟用,新版Clients都需要首先接入這一層並通過審核之後才能訪問到Broker,如下圖所示:

這麼做的好處在於統一了Clients訪問Broker的模式,即定義RPC協議,比如我們熟知的PRODUCE協議、FETCH協議、METADATA協議、CreateTopics協議等。如果後面需要實現更多的功能,社區只需要定義新的RPC協議即可。同時新引入的安全層負責對這套RPC協議進行安全校驗,統一了訪問模式。另外這些協議都是版本化的(versioned),因此能夠獨立地進行演進,同時也兼顧了兼容性方面的考量。

Broker間交互

說完了Clients端,我們說下Broker端的現狀。目前,應該說Kafka Broker端對ZooKeeper是重度依賴的,主要表現在以下幾個方面:

  • Broker註冊管理
  • ACL安全層配置管理
  • 動態參數管理
  • 副本ISR管理
  • Controller選舉

我們拿一張圖來說明,圖中有4個Broker節點和一個ZooKeeper,左上角的Broker充當Controller的角色。當前,所有的Broker啟動后都必須維持與ZooKeeper的會話。Kafka依賴於這個會話實現Broker端的註冊,而且Kafka集群中的所有配置信息、副本信息、主題信息也都保存在ZooKeeper上。最後Controller與集群中每個Broker都維持了一個TCP長連接用於向這些Broker發送RPC請求。當前的Controller RPC類型主要有3大類:

  • LeaderAndIsr:主要用於向集群廣播主題分區Leader和ISR的變更情況,比如對應的Broker應該是特定分區的Leader還是Follower
  • StopReplica:向集群廣播執行停止副本的命令
  • UpdateMetadata:向集群廣播執行變更元數據信息的命令

圖中還新增了一個AlterISR RPC,這是KIP-497要實現的新RPC協議。現階段Kafka各個主題的ISR信息全部保存在ZooKeeper中。如果後續要捨棄ZooKeeper,必須要將這些信息從ZooKeeper中移出來,放在了Controller一端來做。同時還要在程序層面支持對ISR的管理。因此社區計劃在KIP-497上增加AlterISR協議。對了,還要提一句,當前Controller的選舉也是依靠ZooKeeper完成的。

所以後面Broker端的演進可能和Clients端的路線差不多:首先是把Broker與ZooKeeper的交互全部幹掉,只讓Controller與ZooKeeper進行交互,而其他所有Broker都只與Controller交互,如下圖所示:

 

看上去這種演進路線社區已經走得輕車熟路了,但實際上還有遺留了一些問題需要解決。

Broker Liveness

首先就是Broker的liveness問題,即Kafka如何判斷一個Broker到底是否存活?在目前的設計中,Broker的生存性監測完全依賴於與ZooKeeper之間的會話。一旦會話超時或斷開Controller自動觸發ZooKeeper端的Watch來移除該Broker,並對其上的分區做善後處理。如果移除了ZooKeeper,Kafka應該採用什麼機制來判斷Broker的生存性是一個問題。

Network Partition

如何防範網絡分區也是一個需要討論的話題。當前可能出現的Network Partition有4種:1、單個Broker完全與集群隔離;2、Broker間無法通訊;3、Broker與ZooKeeper無法通訊;4、Broker與Controller無法通訊。下面4張圖分別展示了這4種情況:

 

我們分別討論下。首先是第一種情況,單Broker與集群其他Broker隔離,這其實並不算太嚴重的問題。當前的設計已然能夠保證很好地應對此種情況。一旦Broker被隔離,Controller會將其從集群中摘除,雖然可用性降低了,但是整個集群的一致性依然能夠得到保證。第二種情況是Broker間無法通訊,可能的後果是消息的備份機制無法執行,Kafka要收縮ISR,依然是可用性上的降低,但是一致性狀態並沒有被破壞。情況三是Broker無法與ZooKeeper通訊。Broker能正常運轉,它只是無法與ZooKeeper進行通訊。此時我們說該Broker處於殭屍狀態,即所謂的Zoobie狀態。因Zoobie狀態引入的一致性bug社區jira中一直沒有斷過,社區這幾年也一直在修正這方面的問題,主要對抗的機制就是fencing。比如leader epoch等。最後一類情況是Broker無法與Controller通訊,那麼所有的元數據更新通道被堵死,即使這個Broker依然是healthy的,但是它保存的元數據信息可能是非常過期的。這樣連接該Broker的客戶端可能會看到各種非常古怪的問題。之前在知乎上回答過類似的問題:4。目前,社區對這種情況並沒有太好的解決辦法,主要的原因是Broker的liveness完全交由ZooKeeper來做的。一旦Broker與ZooKeeper之間的交互沒有問題,其他原因導致的liveness問題就無法徹底規避。

第四類Network Partition引入了一個經典的場景:元數據不一致。目前每個Broker都緩存了一份集群的元數據信息,這份數據是異步更新的。當第四類Partition發生時,Broker端緩存的元數據信息必然與Controller的不同步,從而造成各種各樣的問題。

下面簡要介紹一下元數據更新的過程。主要的流程就是Controller啟動時會同步地從ZooKeeper上拉取集群全量的元數據信息,之後再以異步的方式同步給其他Broker。其他Broker與Controller之間的同步往往有一個時間差,也就是說可能Clients訪問的元數據並不是最新的。我個人認為現在社區很多flaky test failure都是因為這個原因導致的。 事實上,實際使用過程中有很多場景是Broker端的元數據與Controller端永遠不同步。通常情況下如果我們不重啟Broker的話,那麼這個Broker上的元數據將永遠“錯誤”下去。好在社區還給出了一個最後的“大招”: 登錄到ZooKeeper SHELL,手動執行rmr /controller,強迫Controller重選舉,然後重新加載元數據,並給所有Broker重刷一份。不過在實際生產環境,我懷疑是否有人真的要這麼干,畢竟代價不小,而且最關鍵的是這麼做依然可能存在兩個問題:1. 我們如何確保Controller和Broker的數據是一致的?2. 加載元數據的過程通常很慢。

這裏詳細說說第二點,即加載元數據的性能問題。總體來說,加載元數據是一個O(N)時間複雜度的過程,這裏的N就是你集群中總的分區數。考慮到Controller從ZooKeeper加載之後還要推給其他的Broker,那麼做這件事的總的時間複雜度就是O(N * M),其中M是集群中Broker的數量。可以想見,當M和N都很大時,在集群中廣播元數據不是一個很快的過程。

Metadata as an Event Log

Okay,鑒於以上所提到的所有問題,當Kafka拋棄了ZooKeeper之後,社區應該如何解決它們呢?總體的思路就是Metadata as an Event Log + Controller quorum。我們先說metadata as an event log。如果你讀過Jay Kreps的《I ️Logs》,你應該有感觸,整個Kafka的架構其實都是構建在Log上的。每個topic的分區本質上就是一個Commit Log,但元數據信息的保存卻不是Log形式。在現有的架構設計中你基本上可以認為元數據的數據結構是KV形式的。這一次,社區採用了與消息相同的數據保存方式,即將元數據作為Log的方式保存起來,如下錶所示:

 

這樣做的好處在於每次元數據的變更都被當做是一條消息保存在Log中,而這個Log可以被視作是一個普通的Kafka主題被備份到多台Broker上。Log的一個好處在於它有清晰的前後順序關係,即每個事件發生的時間是可以排序的,配合以恰當的處理邏輯,我們就能保證對元數據變更的處理是按照變更發生時間順序處理,不出現亂序的情形。另外Log機制還有一個好處是,在Broker間同步元數據時,我們可以選擇同步增量數據(delta),而非全量狀態。現在Kafka Broker間同步元數據都是全量狀態同步的。前面說過了,當集群分區數很大時,這個開銷是很可觀的。如果我們能夠只同步增量狀態,勢必能極大地降低同步成本。最後一個好處是,我們可以很容易地量化元數據同步的進度,因為對Log的消費有位移數據,因此通過監控Log Lag就能算出當前同步的進度或是落後的進度。

採用Log機制后,其他Broker像是一個普通的Consumer,從Controller拉取元數據變更消息或事件。由於每個Broker都是一個Consumer,所以它們會維護自己的消費位移,就像下面這張圖一樣:

 這種設計下,Controller所在的Broker必須要承擔起所有元數據topic的管理工作,包括創建topic、管理topic分區的leader以及為每個元數據變更創建相應的事件等。既然社區選擇和__consumer_offsets類似的處理方式,一個很自然的問題在於這個元數據topic的管理是否能夠復用Kafka現有的副本機制?答案是:不可行。理由是現有的副本機制依賴於Controller,因此Kafka沒法依靠現有的副本機制來實現Controller——按照我們的俗語來說,這有點雞生蛋、蛋生雞的問題,屬於典型的循環依賴。為了實現這個,Kafka需要一套leader選舉協議,而這套協議或算法是不依賴於Controller的,即它是一個自管理的集群quorum(抱歉,在分佈式領域內,特別是分佈式共識算法領域中,針對quorum的恰當翻譯我目前還未找到,因此直接使用quorum原詞了)。最終社區決定採用Raft來實現這組quorum。這就是上面我們提到的第二個解決思路:Controller quorum。

Controller Quorum

與藉助Controller幫忙選擇Leader不同,Raft是讓自己的節點自行選擇Leader並最終令所有節點達成共識——對選擇Controller而言,這是一個很好的特性。其實Kafka現有的備份機制與Raft已經很接近了,下錶羅列了一下它們的異同:

 一眼掃過去,其實Kafka的備份機制和Raft很類似,比如Kafka中的offset其實就是Raft中的index,epoch對應於term。當然Raft中採用的半數機制來確保消息被提交以及Leader選舉,而Kafka設計了ISR機制來實現這兩點。總體來說,社區認為只需要對備份機製做一些小改動就應該可以很容易地切換到Raft-based算法。

下面這張圖展示Controller quorum可能更加直觀:

整個controller quorum類似於一個小的集群。和ZooKeeper類似,這個quorum通常是3台或5台機器,不需要讓Kafka中的每個Broker都自動稱為這個quorum中的一個節點。該quorum裏面有一個Leader負責處理客戶端發來的讀寫請求,這個Leader就是Kafka中的active controller。根據ZooKeeper的Zab協議,leader處理所有的寫請求,而follower是可以處理讀請求的。當寫請求發送給follower后,follower會將該請求轉發給leader處理。不過我猜Kafka應該不會這樣實現,它應該只會讓leader(即active controller)處理所有的讀寫請求,而客戶端(也就是其他Broker)壓根就不會發送讀寫請求給follower。在這一點上,這種設計和現有的Kafka請求處理機制是一致的。

現在還需要解決一個問題,即Leader是怎麼被選出來的?既然是Raft-based,那麼採用的也是Raft算法中的Leader選舉策略。讓Raft選出的Leader稱為active controller。網上有很多關於Raft選主的文章,這裏就不在贅述了,有興趣的可以讀一讀Raft的論文:《In Search of an Understandable Consensus Algorithm(Extended Version)》。

這套Raft quorum的一個好處在於它天然提供了低延時的failover,因此leader的切換會非常的迅速和及時,因為理論上不再有元數據加載的過程了,所有的元數據現在都同步保存follower節點的內存中,它已經有其他Broker需要拉取的所有元數據信息了!更酷的是,它避免了現在機制中一旦Controller切換要全量拉取元數據的低效行為,Broker無需重新拉取之前已經“消費”的元數據變更消息,它只需要從新Leader繼續“消費”即可。

另一個好處在於:採用了這套機制后,Kafka可以做元數據的緩存了(metadata caching):即Broker能夠把元數據保存在磁盤上,同時就像剛才說的,Broker只需讀取它關心的那部分數據即可。還有,和現在snapshot機制類似,如果一個Broker保存的元數據落後Controller太多或者是一個全新的Broker,Kafka甚至可以像Raft那樣直接發送一個snapshot文件,快速令其追上進度。當然大多數情況下,Broker只需要拉取delta增量數據即可。

Post KIP-500 Broker註冊

當前Broker啟動之後會向ZooKeeper註冊自己的信息,比如自己的主機名、端口、監聽協議等數據。移除ZooKeeper之後,Broker的註冊機制也要發生變化:Broker需要向active controller發送心跳來進行註冊。Controller收集心跳中包含的Broker數據構建整個Kafka集群信息,如下圖所示:

 同時Controller也會對心跳進行響應,顯式地告知Broker它們是否被允許加入集群——如果不允許,則可能需要被隔離(fenced)。當然controller自己也可以對自己進行隔離。我們針對前面提到的隔離場景討論下KIP-500是怎麼應對的。

Fencing

首先是普通Broker與集群完全隔離的場景,比如該Broker無法與controller和其他Broker進行通信,但它依然可以和客戶端程序交互。此時,fencing機制就很簡單了,直接讓controller令其下線即可。這和現在依靠ZooKeeper會話機制維持Broker判活的機制是一模一樣的,沒有太大改進。

第二種情況是Broker間的通訊中斷。此時消息無法在leader、follower間進行備份。但是對於元數據而言,我們不會看到數據不一致的情形,因為Broker依然可以和controller通訊,因此也不會有什麼問題。

第三種情況是Broker與Controller的隔離。現有機制下這是個問題,但KIP-500之後,Controller僅僅將該Broker“踢出場”即可,不會造成元數據的不一致。

最後一種情況是Broker與ZooKeeper的隔離, 既然ZooKeeper要被移除了,自然這也不是問題了。

部署

終於聊到KIP-500之後的Kafka運維了。下錶總結了KIP-500前後的部署情況對比:

很簡單,現在任何時候部署和運維Kafka都要考慮對ZooKeeper的運維管理。在KIP-500之後我們只需要關心Kafka即可。

Controller quorum共享模式

如前所述,controller改成Raft quorum機制后,可能使用3或5台機器構成一個小的quorum。那麼一個很自然的問題是,這些Broker機器還能否用作他用,是唯一用作controller quorum還是和其他Broker一樣正常處理。社區對此也做了解釋:兩種都支持!

如果你的Kafka集群資源很緊張,你可以使用共享controller模式(Shared Controller Mode),即充當controller quorum的Broker機器也能處理普通的客戶端請求;相反地,如果你的Kafka資源很充足,專屬controller模式(Separate Controller Mode)可能是更適合的,即在controller quorum中的Broker機器排它地用作Controller的選舉之用,不再對客戶端提供讀寫服務。這樣可以實現更好的資源隔離,適用於大集群。

Roadmap

最後說一下KIP-500的計劃。社區計劃分三步走:

第一步是移除客戶端對ZooKeeper的依賴——這一步基本上已經完成了,除了目前AdminClient還有少量的API依賴ZooKeeper之外,其他客戶端應該說都不需要訪問ZooKeeper了;第二步是移除Broker端的ZooKeeper依賴:這主要包括移除Broker端需要訪問ZooKeeper的代碼,以及增加新的Broker端API,如前面所說的AlterISR等,最後是將對ZooKeeper的訪問全部集中在controller端;最後一步就是實現controller quorum,實現Raft-based的quorum負責controller的選舉。

至於Kafka升級,如果從現有的Kafka直接升級到KIP-500之後的Kafka會比較困難,因此社區打算引入一個名為Bridge Release的中間過渡版本,如下圖所示:

這個Bridge版本的特點在於所有對ZooKeeper的訪問都集中到了controller端,Broker訪問ZooKeeper的其他代碼都被移除了。 

總結

KIP-500應該說是最近幾年社區提出的最重磅的KIP改進了。它幾乎是顛覆了Kafka已有的使用模式,摒棄了之前重度依賴的Apache ZooKeeper。就我個人而言,我是很期待這個KIP,後續有最新消息我也會在一併同步出來。讓我們靜觀其變吧~~~

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

【其他文章推薦】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

大陸寄台灣空運注意事項

大陸海運台灣交貨時間多久?

※避免吃悶虧無故遭抬價!台中搬家公司免費估價,有契約讓您安心有保障!

噴藥害死蜜蜂 奧地利果農遭判刑

摘錄自2018年9月26日中央社報導

奧地利一名果農因違法噴灑殺蟲劑,隸屬鄰近2個養蜂人超過50個蜂群因此死亡。26日奧地利克拉根福法院(Klagenfurt)以「蓄意危害環境」,判處果農1年有期徒刑,至少需服刑4個月才可假釋,以及賠償超過2萬歐元(2萬3500美元)。

這名47歲果農針對他位於奧地利卡林西亞省(Carinthia)拉萬特地區(Lavanttal)的果樹噴灑藥效強大的殺蟲劑陶斯松(chlorpyrifos),當時果樹的花仍會吸引蜜蜂前去。法院指出,以他的經驗和訓練他人的角色,足以證明他知道自身行為會帶來何種後果。

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

【其他文章推薦】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

大陸寄台灣空運注意事項

大陸海運台灣交貨時間多久?

※避免吃悶虧無故遭抬價!台中搬家公司免費估價,有契約讓您安心有保障!