<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          基于Prometheus網關的監(jiān)控完整實現(xiàn)參考

          共 20471字,需瀏覽 41分鐘

           ·

          2021-03-26 16:04

          走過路過不要錯過

          點擊藍字關注我們


          prometheus 是一個非常好的監(jiān)控組件,尤其是其與grafana配合之后,更是如虎添翼。而prometheus的監(jiān)控有兩種實現(xiàn)方式。1. server端主動拉取應用監(jiān)控數(shù)據(jù);2. 主動推送監(jiān)控數(shù)據(jù)到prometheus網關。這兩種方式各有優(yōu)劣,server端主動拉取實現(xiàn)可以讓應用專心做自己的事,根本無需關心外部監(jiān)控問題,但有一個最大的麻煩就是server端需要主動發(fā)現(xiàn)應用的存在,這個問題也并不簡單(雖然現(xiàn)在的基于k8s的部署方式可以實現(xiàn)自動發(fā)現(xiàn))。而基本prometheus網關推送的實現(xiàn),則需要應用主動發(fā)送相應數(shù)據(jù)到網關,即應用可以根據(jù)需要發(fā)送監(jiān)控數(shù)據(jù),可控性更強,但也同時帶來一個問題就是需要應用去實現(xiàn)這個上報過程,實現(xiàn)得不好往往會給應用帶來些不必要的麻煩,而且基于網關的實現(xiàn),還需要考慮網關的性能問題,如果應用無休止地發(fā)送數(shù)據(jù)給網關,很可能將網關沖跨,這就得不償失了。

          而prometheus的sdk實現(xiàn)也非常多,我們可以任意選擇其中一個來做業(yè)務埋點。如:dropwizard, simpleclient ...  也并無好壞之分,主要看自己的業(yè)務需要罷了。比如 dropwizard 操作簡單功能豐富,但只支持單值的監(jiān)控。而 simpleclient 支持多子標簽的的監(jiān)控,可以用于豐富的圖表展現(xiàn),但也需要更麻煩的操作等等。

          由于我們也許更傾向于多子標簽的支持問題,今天我們就基于 simpleclient 來實現(xiàn)一個完整地網關推送的組件吧。給大家提供一些思路和一定的解決方案。

          1:pom 依賴引入

          如果我們想簡單化監(jiān)控以及如果需要一些tps方面的數(shù)據(jù),則可以使用 dropwizard 的依賴:

                  <!-- jmx 埋點依賴 -->        <dependency>            <groupId>io.dropwizard.metrics</groupId>            <artifactId>metrics-core</artifactId>            <version>4.0.0</version>        </dependency>        <dependency>            <groupId>io.dropwizard.metrics</groupId>            <artifactId>metrics-jmx</artifactId>            <version>4.0.0</version>        </dependency>

          當然,以上不是我們本文的基礎,我們基于simpleclient 依賴實現(xiàn):

                  <!-- https://mvnrepository.com/artifact/io.prometheus/simpleclient_pushgateway -->        <dependency>            <groupId>io.prometheus</groupId>            <artifactId>simpleclient_pushgateway</artifactId>            <version>0.9.0</version>        </dependency>

          看起來simpleclient的依賴更簡單些呢!但實際上因為我們需要使用另外組件將dropwizard的數(shù)據(jù)暴露原因,不過這無關緊要。

          2. metrics 埋點簡單使用

          dropwizard 的使用樣例如下:

          public class PrometheusMetricManager {    // 監(jiān)控數(shù)據(jù)寫入容器    private static final MetricRegistry metricsContainer = new MetricRegistry();
          static { // 使用 jmx_exporter 將埋點數(shù)據(jù)暴露出去 JmxReporter jmxReporter = JmxReporter.forRegistry(metricsContainer).build(); jmxReporter.start(); }
          // 測試使用 public static void main(String[] args) { // tps 類數(shù)據(jù)監(jiān)控 Meter meter = metricsContainer.meter("tps_meter"); meter.mark(); Map<String, Object> queue = new HashMap<>(); queue.put("sss", 1); // 監(jiān)控數(shù)組大小 metricsContainer.register("custom_metric", new Gauge<Integer>() { @Override public Integer getValue() { return queue.size(); } }); }}

          simpleclient 使用樣例如下:

          public class PrometheusMetricManager {
          /** * prometheus 注冊實例 */ private static final CollectorRegistry registry = new CollectorRegistry();

          /** * prometheus 網關實例 */ private static volatile PushGateway pushGatewayIns = new PushGateway("172.30.12.167:9091");
          public static void main(String[] args) { try{ // 測試 gauge, counter Gauge guage = Gauge.build("my_custom_metric", "This is my custom metric.") .labelNames("a").create().register(registry); Counter counter = Counter.build("my_counter", "counter help") .labelNames("a", "b").create().register(registry);
          guage.labels("1").set(23.12);
          counter.labels("1", "2").inc(); counter.labels("1", "3").inc();
          Map<String, String> groupingKey = new HashMap<String, String>(); groupingKey.put("instance", "my_instance"); // 推送網關數(shù)據(jù) pushGatewayIns.pushAdd(registry, "my_job", groupingKey); } catch (Exception e){ e.printStackTrace(); } }
          }

          以上就是簡單快速使用prometheus的sdk進行埋點數(shù)據(jù)監(jiān)控了,使用都非常簡單,即注冊實例、業(yè)務埋點、暴露數(shù)據(jù); 

          但要做好管理埋點也許并不是很簡單,因為你可能需要做到易用性、可管理性、及性能。

          3. 一個基于pushgateway 的管理metrics完整實現(xiàn)

          從上節(jié),我們知道要做埋點很簡單,但要做到好的管理不簡單。比如如何做到易用?如何做到可管理性強?

          解決問題會有很多方法,我這邊給到方案是,要想易用,那么我就封裝一些必要的接口給到應用層,比如應用層只做數(shù)據(jù)量統(tǒng)計,那么我就只暴露一個counter的增加方法,其他一概隱藏,應用層想要使用埋點時也不用管什么底層推送,數(shù)據(jù)結構之類,只需調用一個工廠方法即可得到操作簡單的實例。想要做可管理,那么就必須要依賴于外部的配置系統(tǒng),只需從外部配置系統(tǒng)一調整,應用立馬可以感知到,從而做出相應的改變,比如推送頻率、推送開關、網關地址。。。

          下面一個完整的實現(xiàn)樣例:

          import com.my.mvc.app.common.util.ArraysUtil;import com.my.mvc.app.common.util.IpUtil;import com.my.mvc.app.component.metrics.types.*;import io.prometheus.client.*;import io.prometheus.client.exporter.PushGateway;import lombok.extern.slf4j.Slf4j;
          import java.io.IOException;import java.util.HashMap;import java.util.Map;import java.util.concurrent.*;
          /** * 功能描述: prometheus指標埋點 操作類 * */@Slf4jpublic class PrometheusMetricManager {
          /** * prometheus 注冊實例 */ private static final CollectorRegistry registry = new CollectorRegistry();
          /** * 指標統(tǒng)一容器 * * counter: 計數(shù)器類 * gauge: 儀表盤類 * histogram: 直方圖類 * summary: 摘要類 */ private static final Map<String, CounterMetric> counterMetricContainer = new ConcurrentHashMap<>(); private static final Map<String, TimerMetric> timerMetricContainer = new ConcurrentHashMap<>(); private static final Map<String, CustomValueMetricCollector> customMetricContainer = new ConcurrentHashMap<>(); private static final Map<String, Histogram> histogramMetricContainer = new ConcurrentHashMap<>(); private static final Map<String, Summary> summaryMetricContainer = new ConcurrentHashMap<>();

          /** * prometheus 網關實例 */ private static volatile PushGateway pushGatewayIns;
          /** * prometheus gateway api 地址 */ private static volatile String gatewayApiCurrent;
          /** * 項目埋點統(tǒng)一前綴 */ private static final String METRICS_PREFIX = "sys_xxx_";
          /** * 指標的子標簽key名, 統(tǒng)一定義 */ private static final String METRIC_LABEL_NAME_SERVER_HOST = "server_host";
          /** * 推送gateway線程池 */ private static final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1, r -> new Thread(r, "Prometheus-push"));
          static { // 自動進行gateway數(shù)據(jù)上報 startPrometheusThread(); }
          private PrometheusMetricManager() {
          }
          /** * 注冊一個prometheus的監(jiān)控指標, 并返回指標實例 * * @param metricName 指標名稱(只管按業(yè)務命名即可: 數(shù)字+下劃線) * @param labelNames 所要監(jiān)控的子指標名稱,會按此進行分組統(tǒng)計 * @return 注冊好的counter實例 */ public static CounterMetric registerCounter(String metricName, String... labelNames) { CounterMetric counter = counterMetricContainer.get(metricName); if(counter == null) { synchronized (counterMetricContainer) { counter = counterMetricContainer.get(metricName); if(counter == null) { String[] labelNameWithServerHost = ArraysUtil.addFirstValueIfAbsent( METRIC_LABEL_NAME_SERVER_HOST, labelNames); Counter counterProme = Counter.build() .name(PrometheusMetricManager.METRICS_PREFIX + metricName) .labelNames(labelNameWithServerHost) .help(metricName + " counter") .register(registry); counter = new PrometheusCounterAdapter(counterProme, labelNameWithServerHost != labelNames); counterMetricContainer.put(metricName, counter); } } } return counter; }
          /** * 注冊一個儀表盤指標實例 * * @param metricName 指標名稱 * @param labelNames 子標簽名列表 * @return 儀表實例 */ public static TimerMetric registerTimer(String metricName, String... labelNames) { TimerMetric timerMetric = timerMetricContainer.get(metricName); if(timerMetric == null) { synchronized (timerMetricContainer) { timerMetric = timerMetricContainer.get(metricName); if(timerMetric == null) { String[] labelNameWithServerHost = ArraysUtil.addFirstValueIfAbsent( METRIC_LABEL_NAME_SERVER_HOST, labelNames); Gauge gauge = Gauge.build() .name(METRICS_PREFIX + metricName) .labelNames(labelNameWithServerHost) .help(metricName + " gauge") .register(registry); timerMetric = new PrometheusTimerAdapter(gauge, labelNameWithServerHost != labelNames); timerMetricContainer.put(metricName, timerMetric); } } } return timerMetric; }
          /** * 注冊一個儀表盤指標實例 * * @param metricName 指標名稱 * @param valueSupplier 用戶自定義實現(xiàn)的單值提供實現(xiàn) */ public static void registerSingleValueMetric(String metricName, CustomMetricValueSupplier<? extends Number> valueSupplier) { CustomValueMetricCollector customMetric = customMetricContainer.get(metricName); if(customMetric == null) { synchronized (customMetricContainer) { customMetric = customMetricContainer.get(metricName); if(customMetric == null) { String[] labelNameWithServerHost = { METRIC_LABEL_NAME_SERVER_HOST }; CustomValueMetricCollector customCollector = CustomValueMetricCollector.build() .name(METRICS_PREFIX + metricName) .labelNames(labelNameWithServerHost) .valueSupplier(valueSupplier) .help(metricName + " custom value metric") .register(registry); // 主動觸發(fā)固定參數(shù)的value計數(shù) customCollector.labels(IpUtil.getLocalIp()); customMetricContainer.put(metricName, customCollector); } } } }
          /** * 定時推送指標到PushGateway */ private static void pushMetric() throws IOException { refreshPushGatewayIfNecessary(); pushGatewayIns.pushAdd(registry, "my_job"); }
          /** * 保證pushGateway 為最新版本 */ private static void refreshPushGatewayIfNecessary() { // PushGateway地址 com.ctrip.framework.apollo.Config config = com.ctrip.framework.apollo.ConfigService.getAppConfig(); String gatewayApi = config.getProperty("prometheus_gateway_api", "10.1.20.121:9091"); if(pushGatewayIns == null) { pushGatewayIns = new PushGateway(gatewayApi); return; } if(!gatewayApi.equals(gatewayApiCurrent)) { gatewayApiCurrent = gatewayApi; pushGatewayIns = new PushGateway(gatewayApi); } }
          /** * 開啟推送 gateway 線程 * * @see #useCustomMainLoopPushGateway() * @see #useJdkSchedulerPushGateway() */ private static void startPrometheusThread() { useCustomMainLoopPushGateway(); }
          /** * 使用自定義純種循環(huán)處理推送網關數(shù)據(jù) */ private static void useCustomMainLoopPushGateway() { executorService.submit(() -> { while (isPrometheusMetricsPushSwitchOn()) { try { pushMetric(); } catch (IOException e) { log.error("【prometheus】推送gateway失敗:" + e.getMessage(), e); } finally { sleep(getPrometheusPushInterval()); } }
          // 針對關閉埋點采集后,延時檢測是否重新開啟了, 以便重新恢復埋點上報 executorService.schedule(PrometheusMetricManager::startPrometheusThread, 30, TimeUnit.SECONDS); }); }
          /** * 休眠指定時間(毫秒) * * @param millis 指定時間(毫秒) */ private static void sleep(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { log.error("sleep異常", e); } }
          /** * 獲取prometheus推送網關頻率(單位:s) * * @return 頻率如: 60(s) */ private static Integer getPrometheusPushInterval() { com.ctrip.framework.apollo.Config config = com.ctrip.framework.apollo.ConfigService.getAppConfig(); return config.getIntProperty("prometheus_metrics_push_gateway_interval", 10) * 1000; }
          /** * 檢測apollo是否開啟推送網關數(shù)據(jù)開關 * * @return true:已開啟, false:已關閉(不得推送指標數(shù)據(jù)) */ private static boolean isPrometheusMetricsPushSwitchOn() { com.ctrip.framework.apollo.Config config = com.ctrip.framework.apollo.ConfigService.getAppConfig(); return "1".equals(config.getProperty("prometheus_metrics_push_switch", "1")); }
          /** * 使用 scheduler 進行推送采集指標數(shù)據(jù) */ private static void useJdkSchedulerPushGateway() { executorService.scheduleAtFixedRate(() -> { if(!isPrometheusMetricsPushSwitchOn()) { return; } try { PrometheusMetricManager.pushMetric(); } catch (Exception e) { log.error("【prometheus】推送gateway失敗:" + e.getMessage(), e); } }, 1, getPrometheusPushInterval(), TimeUnit.SECONDS); }
          // 測試功能 public static void main(String[] args) throws Exception { // 測試counter CounterMetric myCounter1 = PrometheusMetricManager.registerCounter( "hello_counter", "topic", "type"); myCounter1.incWithLabelValues("my-spec-topic", "t1");
          // 測試 timer TimerMetric timerMetric = PrometheusMetricManager.registerTimer("hello_timer", "sub_label1"); timerMetric.startWithLabelValues("key1"); Thread.sleep(1000); timerMetric.stop();
          Map<String, Object> queue = new HashMap<>(); queue.put("a", 11); queue.put("b", 1); queue.put("c", 222);
          // 測試隊列大小監(jiān)控,自定義監(jiān)控實現(xiàn) PrometheusMetricManager.registerSingleValueMetric( "custom_value_supplier", queue::size);
          // 隊列值發(fā)生變化 Thread.sleep(60000); queue.put("d", 22);
          // 等待發(fā)送線程推送數(shù)據(jù) System.in.read(); }}

          以上,就是咱們整個推送網關的管理框架了,遵循前面說的原則,只暴露幾個注冊接口,返回的實例按自定義實現(xiàn),只保留必要的功能。使用時只管注冊,及使用有限功能即可。(注意:這不是寫一個通用框架,而僅是為某類業(yè)務服務的管理組件)

          實際也是比較簡單的,如果按照這些原則來做的話,應該會為你的埋點監(jiān)控工作帶來些許的方便。另外,有些細節(jié)的東西我們稍后再說。

          4. 自定義監(jiān)控的實現(xiàn)

          上面我們看到,我們有封裝 CounterMetric, TimerMetric 以減少不必要的操作。這些主要是做了一下prometheus的一些代理工作,本身是非常簡單的,我們可以簡單看看。

          /** * 功能描述: 計數(shù)器型埋點指標接口定義 * *           <p>簡化不必要的操作方法暴露</p> * */public interface CounterMetric {
          /** * 計數(shù)器 +1, 作別名使用 (僅對無多余l(xiāng)abelNames 情況), 默認無需實現(xiàn)該方法 */ default void inc() { incWithLabelValues(); }
          /** * 帶子標簽類型填充的計數(shù)器 +1 * * @param labelValues 子標簽值(與最初設置時順序個數(shù)一致) */ void incWithLabelValues(String... labelValues);
          }
          // -------------- 以下是實現(xiàn)類 ---------------import com.my.common.util.ArraysUtil;import com.my.common.util.IPAddressUtil;import io.prometheus.client.Counter;
          /** * 功能描述: prometheus counter 適配器實現(xiàn) * */public class PrometheusCounterAdapter implements CounterMetric {
          private Counter counter;
          /** * 是否在頭部添加 主機名 */ private boolean appendServerHost;
          public PrometheusCounterAdapter(Counter counter, boolean appendServerHost) { this.counter = counter; this.appendServerHost = appendServerHost; }
          @Override public void incWithLabelValues(String... labelValues) { if(appendServerHost) { labelValues = ArraysUtil.addFirstValue(IPAddressUtil.getLocalIp(), labelValues); } counter.labels(labelValues).inc(); }
          }

          不復雜,看業(yè)務需要實現(xiàn)某些功能即可。供參考,其他類似功能可自行實現(xiàn)。

          我們主要來看一下自定義監(jiān)控值的實現(xiàn),主要場景如隊列大小監(jiān)控。Prometheus 的 simpleclient 中給我們提供了幾種監(jiān)控類型 Counter, Gauge, Histogram, Summary, 可能都不能很好的支持到我們這種自定義的實現(xiàn)。所以,需要自己干下這件事。其與 Gauge 的實現(xiàn)是非常相似的,值都是可大可小可任意,所以我們可以參考Gauge的實現(xiàn)做出我們的自定義值監(jiān)控。具體實現(xiàn)如下:

          import io.prometheus.client.Collector;import io.prometheus.client.GaugeMetricFamily;import io.prometheus.client.SimpleCollector;
          import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.Map;
          /** * 功能描述: prometheus 自定義單值監(jiān)控工具(如:元素大小監(jiān)控) * */public class CustomValueMetricCollector extends SimpleCollector<CustomValueMetricCollector.Child> implements Collector.Describable {
          private CustomMetricValueSupplier<? extends Number> valueSupplier;
          private CustomValueMetricCollector(Builder b) { super(b); this.valueSupplier = b.valueSupplier; if(valueSupplier == null) { throw new IllegalArgumentException("unknown value supplier"); } }
          /** * Return a Builder to allow configuration of a new Gauge. */ public static Builder build() { return new Builder(); }
          @Override protected Child newChild() { return new Child(valueSupplier); }
          @Override public List<MetricFamilySamples> describe() { return Collections.<MetricFamilySamples>singletonList( new GaugeMetricFamily(fullname, help, labelNames)); }
          @Override public List<MetricFamilySamples> collect() { List<MetricFamilySamples.Sample> samples = new ArrayList<>(children.size()); for(Map.Entry<List<String>, Child> c: children.entrySet()) { samples.add(new MetricFamilySamples.Sample( fullname, labelNames, c.getKey(), c.getValue().get())); } return familySamplesList(Type.GAUGE, samples); }
          public static class Builder extends SimpleCollector.Builder <CustomValueMetricCollector.Builder, CustomValueMetricCollector> { private CustomMetricValueSupplier<? extends Number> valueSupplier;
          @Override public CustomValueMetricCollector create() { return new CustomValueMetricCollector(this); }
          /** * 自定義值提供者 * * @param valueSupplier 提供者用戶實現(xiàn)實現(xiàn) * @param <T> 用戶返回的數(shù)值類型 */ public <T extends Number> Builder valueSupplier( CustomMetricValueSupplier<T> valueSupplier) { this.valueSupplier = valueSupplier; return this; } }

          /** * 多標簽時使用的子項描述類 * * 實際上并不支持多標簽配置,除了一些統(tǒng)一標簽如 IP */ public static class Child {
          private CustomMetricValueSupplier<? extends Number> valueSupplier;
          Child(CustomMetricValueSupplier<? extends Number> valueSupplier) { this.valueSupplier = valueSupplier; }
          /** * Get the value of the gauge. */ public double get() { return Double.valueOf(valueSupplier.getValue().toString()); } }}

          之所以要使用到 Child, 是因為我們需要支持多子標簽的操作,所以稍微繞了一點。不過總體也不復雜。而且對于單值提供者的實現(xiàn),也只有一個 getValue 方法,這會很好地讓我們利用 Lamda 表達式,寫出極其簡單的提供者實現(xiàn)。接口定義如下:

          /** * 功能描述:  單值型度量 提供者(用戶自定義實現(xiàn)) * * @param <T> 返回的數(shù)據(jù)類型,一定是數(shù)值型喲 */public interface CustomMetricValueSupplier<T extends Number> {
          /** * 用戶實現(xiàn)的提供度量值方法 */ T getValue();}

          具體使用時就非常簡單了:

             // 測試隊列大小監(jiān)控,自定義監(jiān)控實現(xiàn)    PrometheusMetricManager.registerSingleValueMetric(            "custom_value_supplier", queue::size);

          如此,一個完整的監(jiān)控數(shù)據(jù)上報功能就完成了。你要做的僅是找到需要監(jiān)控的業(yè)務點,然后使用僅有api調用就可以了,至于后續(xù)是使用jmx上報,主動上報,網關推送。。。你都不需要關心了,而且還可以根據(jù)情況隨時做出調整。

          至于后續(xù)的監(jiān)控如何做,可以參考我另一篇文章(grafana方案): 快速構建業(yè)務監(jiān)控體系,觀grafana監(jiān)控的藝術

          5. 使用springmvc暴露指標數(shù)據(jù)

          prometheus網關,實際上并不被官方推薦使用,因為他認為這具有侵入性。那么,如果我們能夠同時提供prometheus自主查詢的能力,那就再好不過了。

          基于以上的實現(xiàn),只要稍加改造,就可以支持spring 的restful接口暴露數(shù)據(jù)了。主要分三步:1. 引入servlet依賴;2. 配置servlet服務;3. 修改注冊源;

          1. 引入servlet依賴

                  <dependency>            <groupId>io.prometheus</groupId>            <artifactId>simpleclient_servlet</artifactId>            <version>0.9.0</version>        </dependency>

          2. 配置servlet服務

          springmvc中就是web.xml中配置即可:

              <servlet>        <servlet-name>metrics</servlet-name>        <servlet-class>io.prometheus.client.exporter.MetricsServlet</servlet-class>    </servlet>    <servlet-mapping>        <servlet-name>metrics</servlet-name>        <url-pattern>/metrics</url-pattern>    </servlet-mapping>

          3. 修改適配注冊源

          因為網關的實現(xiàn)中,我們是自己new的一個注冊源,那么它自然不會被其他框架發(fā)現(xiàn)。所以要稍微改下,使用默認注冊源,這樣大家都方便取數(shù)據(jù)了。

          public class PrometheusMetricsManager {
          /** * prometheus 注冊實例 * * 所有prometheus共享注冊實例 */ private static final CollectorRegistry registry = CollectorRegistry.defaultRegistry; ...}

          如此,我們既支持網關的推送,又支持prometheus主動采集了。




          往期精彩推薦



          騰訊、阿里、滴滴后臺面試題匯總總結 — (含答案)

          面試:史上最全多線程面試題 !

          最新阿里內推Java后端面試題

          JVM難學?那是因為你沒認真看完這篇文章


          END


          關注作者微信公眾號 —《JAVA爛豬皮》


          了解更多java后端架構知識以及最新面試寶典


          你點的每個好看,我都認真當成了


          看完本文記得給作者點贊+在看哦~~~大家的支持,是作者源源不斷出文的動力


          作者:等你歸去來

          出處:https://www.cnblogs.com/yougewe/p/13698833.html

          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  五月天婷婷基地 | 欧美性爱男人的天堂 | www.俺来也.com | www.啪| 大鸡巴无码 |