<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    分布式定時調度:xxl-job 萬字詳解

    VSole2022-11-29 09:18:22

    一.定時任務概述

    1.定時任務認識

    1.1.什么是定時任務

    定時任務是按照指定時間周期運行任務。使用場景為在某個固定時間點執行,或者周期性的去執行某個任務,比如:每天晚上24點做數據匯總,定時發送短信等。

    1.2.常見定時任務方案
    • While + Sleep : 通過循環加休眠的方式定時執行
    • Timer和TimerTask實現 :JDK自帶的定時任務,可以實現簡單的間隔執行任務(在指定時間點執行某一任務,也能定時的周期性執行),無法實現按日歷去調度執行任務。
    • ScheduledExecutorService : Java并發包下,JDK1.5出現,是比較理想的定時任務實現方案。Eureka就使用的是它
    • QuartZ : 使用Quartz,它是一個異步任務調度框架,功能豐富,可以實現按日歷調度,支持持久化。
    • 使用Spring Task,Spring 3.0后提供Spring Task實現任務調度,支持按日歷調度,相比Quartz功能稍簡單,但是在開發基本夠用,支持注解編程方式。
    • SpringBoot中的Schedule : 通過@EnableScheduling+@Scheduled最實現定時任務,底層使用的是Spring Task

    2.分布式定時任務

    2.1.遇到什么問題

    上述的定時任務都是集中式(單體項目使用)的定時任務,在分布式中將會面臨一些問題或不足

    • 業務量大,單機性能瓶頸需要擴展
    • 多臺機器部署如何保證定時任務不重復執行
    • 定時任務時間需要可調整,可以暫停
    • 機器發生故障down機,定時任務依然可用,如何實現故障轉移
    • 定時任務,執行日志是否可監控
    2.2.分布式定時任務xxl-job

    XXL-JOB是一個分布式任務調度平臺,于2015問世,其核心設計目標是開發迅速、學習簡單、輕量級、易擴展。現已開放源代碼并接入多家公司線上產品線,開箱即用。其具備且不止如下能力

    1. 簡單:支持通過Web頁面對任務進行CRUD操作,操作簡單,一分鐘上手;
    2. 動態:支持動態修改任務狀態、啟動/停止任務,以及終止運行中任務,即時生效;
    3. 調度中心HA(中心式):調度采用中心式設計,“調度中心”基于集群Quartz實現并支持集群部署,可保證調度中心HA;執行器HA(分布式):任務分布式執行,任務"執行器"支持集群部署,可保證任務執行HA;
    4. 彈性擴容縮容:一旦有新執行器機器上線或者下線,下次調度時將會重新分配任務;
    5. 路由策略:執行器集群部署時提供豐富的路由策略,包括:第一個、最后一個、輪詢、隨機、一致性HASH、最不經常使用、最近最久未使用、故障轉移、忙碌轉移等;
    6. 故障轉移:任務路由策略選擇"故障轉移"情況下,如果執行器集群中某一臺機器故障,將會自動Failover切換到一臺正常的執行器發送調度請求。
    7. 任務失敗告警:默認提供郵件方式失敗告警,同時預留擴展接口,可方面的擴展短信、釘釘等告警方式;
    具體見:https://github.com/xuxueli/xxl-job/tree/v2.0.0

    二.XXL-JOB初體驗

    1.xxl-job架構設計

    1.1.設計思想

    將調度行為抽象形成“調度中心”公共平臺,而平臺自身并不承擔業務邏輯,“調度中心”負責發起調度請求。

    將任務抽象成分散的JobHandler,交由“執行器”統一管理,“執行器”負責接收調度請求并執行對應的JobHandler中業務邏輯。因此,“調度”和“任務”兩部分可以相互解耦,提高系統整體穩定性和擴展性;

    1.2.架構設計圖

    xxl-job分為 調度中心和執行器兩大模塊

    • 調度模塊(調度中心)

    負責管理調度信息,按照調度配置發出調度請求,自身不承擔業務代碼。調度系統與任務解耦,提高了系統可用性和穩定性,同時調度系統性能不再受限于任務模塊;

    支持可視化、簡單且動態的管理調度信息,包括任務新建,更新,刪除,GLUE開發和任務報警等,所有上述操作都會實時生效,同時支持監控調度結果以及執行日志,支持執行器Failover(故障轉移)。

    • 執行模塊(執行器)

    負責接收調度請求并執行任務邏輯。任務模塊專注于任務的執行等操作,開發和維護更加簡單和高效;

    接收“調度中心”的執行請求、終止請求和日志請求等。

    • 調度中心高可用

    基于數據庫的集群方案,數據庫選用Mysql;集群分布式并發環境中進行定時任務調度時,會在各個節點會上報任務,存到數據庫中,執行時會從數據庫中取出觸發器來執行,如果觸發器的名稱和執行時間相同,則只有一個節點去執行此任務。

    • 并行調度

    調度采用線程池方式實現,避免單線程因阻塞而引起任務調度延遲。XXL-JOB調度模塊默認采用并行機制,在多線程調度的情況下,調度模塊被阻塞的幾率很低,大大提高了調度系統的承載量。

    XXL-JOB的不同任務之間并行調度、并行執行。XXL-JOB的單個任務,針對多個執行器是并行運行的,針對單個執行器是串行執行的。同時支持任務終止。

    • 執行器(任務)高可用

    執行器如若集群部署,調度中心將會感知到在線的所有執行器,如“127.0.0.1:9997, 127.0.0.1:9998, 127.0.0.1:9999”。多個執行器可以選擇“路由策略”來采用輪詢,隨機等方式進行多機器調度。

    當任務”路由策略”選擇”故障轉移(FAILOVER)”時,當調度中心每次發起調度請求時,會按照順序對執行器發出心跳檢測請求,第一個檢測為存活狀態的執行器將會被選定并發送調度請求。調度成功后,可在日志監控界面查看“調度備注”

    2.xxl-job安裝

    2.1.下載源碼

    請下載項目源碼并解壓,使用IDEA工具導入項目

    源碼倉庫地址

    • https://github.com/xuxueli/xxl-job
    • http://gitee.com/xuxueli0323/xxl-job

    項目代碼結構如下

    • doc :文檔,即SQL腳本所在目錄
    • db : “調度數據庫”建表腳本
    • xxl-job-admin : 調度中心項目源碼
    • xxl-job-core : 核心模塊,公共Jar依賴
    • xxl-job-executor-samples : 執行器,Sample示例項目(大家可以在該項目上進行開發,也可以將現有項目改造生成執行器項目)
    2.2.導入數據庫

    打開項目代碼,獲取 “調度數據庫初始化SQL腳本” 并執行即可。“調度數據庫初始化SQL腳本” 位置為: /xxl-job/doc/db/tables_xxl_job.sql ,數據庫名:xxl_job

    數據庫如下

    • xxl_job_lock:任務調度鎖表;
    • xxl_job_group:執行器信息表,維護任務執行器信息;
    • xxl_job_info:調度擴展信息表:用于保存XXL-JOB調度任務的擴展信息,如任務分組、任務名、機器地址、執行器、執行入參和報警郵件等等;
    • xxl_job_log:調度日志表:用于保存XXL-JOB任務調度的歷史信息,如調度結果、執行結果、調度入參、調度機器和執行器等等;
    • xxl_job_log_report:調度日志報表:用戶存儲XXL-JOB任務調度日志的報表,調度中心報表功能頁面會用到;
    • xxl_job_logglue:任務GLUE日志:用于保存GLUE更新歷史,用于支持GLUE的版本回溯功能;
    • xxl_job_registry:執行器注冊表,維護在線的執行器和調度中心機器地址信息;
    • xxl_job_user:系統用戶表;
    2.3.啟動調度中心

    打開 xxl-job-admin 的配置文件,/xxl-job/xxl-job-admin/src/main/resources/application.properties 對調度中心進行配置,重要配置如下

    • server.port : 根據情況修改端口
    • spring.datasource.url :指向剛才準備的數據庫
    • spring.datasource.password : 記得修改成自己的數據庫密碼
    • spring.mail.username :配置自己的郵件賬號
    • spring.mail.password :郵件的授權碼,我下面是以qq郵箱為例

    下面根據自己的情況進行修改,不要直接復制

    ### 調度中心JDBC鏈接:鏈接地址請保持和 2.1章節 所創建的調度數據庫的地址一致
    spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
    spring.datasource.username=root
    spring.datasource.password=root_pwd
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    ### 報警郵箱
    spring.mail.host=smtp.qq.com
    spring.mail.port=25
    spring.mail.username=xxx@qq.com
    spring.mail.password=郵箱授權碼,不是登錄密碼
    spring.mail.properties.mail.smtp.auth=true
    spring.mail.properties.mail.smtp.starttls.enable=true
    spring.mail.properties.mail.smtp.starttls.required=true
    spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
    ### 調度中心通訊TOKEN [選填]:非空時啟用;
    xxl.job.accessToken=
    ### 調度中心國際化配置 [必填]: 默認為 "zh_CN"/中文簡體, 可選范圍為 "zh_CN"/中文簡體, "zh_TC"/中文繁體 and "en"/英文;
    xxl.job.i18n=zh_CN
    ## 調度線程池最大線程配置【必填】
    xxl.job.triggerpool.fast.max=200
    xxl.job.triggerpool.slow.max=100
    ### 調度中心日志表數據保存天數 [必填]:過期日志自動清理;限制大于等于7時生效,否則, 如-1,關閉自動清理功能;
    xxl.job.logretentiondays=30
    

    然后啟動調度中心 ,執行 XxlJobAdminApplication#main 方法 , 啟動之后,瀏覽器訪問 http://localhost:18080/xxl-job-admin/jobinfo?jobGroup=2 ;注意URL中有個上下文路徑。默認登錄賬號 “admin/123456”, 登錄后運行界面如下圖所示。

    2.3.配置部署“執行器項目

    “執行器”項目:xxl-job-executor-sample-springboot (提供多種版本執行器供選擇,現以 springboot 版本為例,可直接使用,也可以參考其并將現有項目改造成執行器)

    作用:負責接收“調度中心”的調度并執行;可直接部署執行器,也可以將執行器集成到現有業務項目中。

    修改配置:/xxl-job/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties

    • xxl.job.admin.addresses : 調度中心的地址,如果調度中心修改過端口,這里也要對應修改
    ### 調度中心部署跟地址 [選填]:如調度中心集群部署存在多個地址則用逗號分隔。執行器將會使用該地址進行"執行器心跳注冊"和"任務結果回調";為空則關閉自動注冊;
    xxl.job.admin.addresses=http://127.0.0.1:18080/xxl-job-admin
    ### 執行器通訊TOKEN [選填]:非空時啟用;
    xxl.job.accessToken=
    ### 執行器AppName [選填]:執行器心跳注冊分組依據;為空則關閉自動注冊
    xxl.job.executor.appname=xxl-job-executor-sample
    ### 執行器注冊 [選填]:優先使用該配置作為注冊地址,為空時使用內嵌服務 ”IP:PORT“ 作為注冊地址。從而更靈活的支持容器類型執行器動態IP和動態映射端口問題。
    xxl.job.executor.address=
    ### 執行器IP [選填]:默認為空表示自動獲取IP,多網卡時可手動設置指定IP,該IP不會綁定Host僅作為通訊實用;地址信息用于 "執行器注冊" 和 "調度中心請求并觸發任務";
    xxl.job.executor.ip=
    ### 執行器端口號 [選填]:小于等于0則自動獲取;默認端口為9999,單機部署多個執行器時,注意要配置不同執行器端口;
    xxl.job.executor.port=9999
    ### 執行器運行日志文件存儲磁盤路徑 [選填] :需要對該路徑擁有讀寫權限;為空則使用默認路徑;
    xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
    ### 執行器日志文件保存天數 [選填] : 過期日志自動清理, 限制值大于等于3時生效; 否則, 如-1, 關閉自動清理功能;
    xxl.job.executor.logretentiondays=30
    

    上面配置是為了在Spring容器中創建一個 XxlJobSpringExecutor 執行器Bean,見:com.xxl.job.executor.core.config.XxlJobConfig#xxlJobExecutor

    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        logger.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appname);
        xxlJobSpringExecutor.setAddress(address);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
    
        return xxlJobSpringExecutor;
    }
    

    com.xxl.job.executor.service.jobhandler.SampleXxlJob中提供了簡單的定時任務實例

    為方便用戶參考與快速實用,示例執行器內原生提供多個Bean模式任務Handler,可以直接配置實用,如下:

    • demoJobHandler:簡單示例任務,任務內部模擬耗時任務邏輯,用戶可在線體驗Rolling Log等功能;
    • shardingJobHandler:分片示例任務,任務內部模擬處理分片參數,可參考熟悉分片任務;
    • httpJobHandler:通用HTTP任務Handler;業務方只需要提供HTTP鏈接等信息即可,不限制語言、平臺。示例任務入參如下:
    /**
     * XxlJob開發示例(Bean模式)
     *
     * 開發步驟:
     * 1、在Spring Bean實例中,開發Job方法,方式格式要求為 "public ReturnT execute(String param)"
     * 2、為Job方法添加注解 "@XxlJob(value="自定義jobhandler名稱", init = "JobHandler初始化方法", destroy = "JobHandler銷毀方法")",注解value值對應的是調度中心新建任務的JobHandler屬性的值。
     * 3、執行日志:需要通過 "XxlJobLogger.log" 打印執行日志;
     *
     * @author xuxueli 2019-12-11 21:52:51
     */
    @Component
    public class SampleXxlJob {
        private static Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);
     /**
         * 1、簡單任務示例(Bean模式)
         */
        @XxlJob("demoJobHandler")
        public ReturnT demoJobHandler(String param) throws Exception {
            logger.info("XXL-JOB, Hello World. param={}",param);
            return ReturnT.SUCCESS;
        }
        //...省略...
    }
    
    【重要】 如果我們要寫自己的定時任務,參照上面方法,在方法上注解一個@XxlJob("任務名字") ,方法可以接受一個字符串參數,方法需要返回ReturnT格式。

    最后啟動執行器項目.

    3.配置定時任務

    3.1.執行器創建

    打開調度中心可視化界面,在執行器管理界面,添加新增執行器

    • appName : 執行器的名字,可以任意填寫
    • 名稱:任意填寫
    • 注冊方式:調度中心是通過RPC的方式對執行器發起調度,所以這里需要的是執行器項目的ip:port ,注意,該端口不是執行器項目的server.port ,而是:xxl.job.executor.port 端口。你可以選擇自動注冊,也可以手動錄入。
    3.2.創建任務

    在 任務管理 界面,新增任務

    • 路由策略:有輪詢,隨機,故障轉移等等策略,是用在集群模式下的調度方式。
    • cron : 定時任務的執行時間規則,時間表達式
    • JobHandler : 這個是要對應 “執行器項目”中 @XxlJob("demoJobHandler") 注解中的名字
    • 運行模式 :Bean ,使用內置代碼方式,也可以執行在線執行代碼方式
    • 報警郵件 :如果定時任務失敗,會發送報警郵件到郵箱
    • 任務參數:這個參數可以傳遞給 @XxlJob("demoJobHandler")所在方法的參數。

    創建好任務之后就可以執行了

    調度日志

    IDEA工具控制臺效果

    15:47:33.017 logback [Thread-16] INFO  c.x.j.e.s.jobhandler.SampleXxlJob - XXL-JOB, Hello World. param=
    15:47:34.007 logback [Thread-16] INFO  c.x.j.e.s.jobhandler.SampleXxlJob - XXL-JOB, Hello World. param=
    15:47:35.008 logback [Thread-16] INFO  c.x.j.e.s.jobhandler.SampleXxlJob - XXL-JOB, Hello World. param=
    ...省略...
    

    4.GLUE模式(Java)

    4.1.添加任務

    該模式支持在線編輯定時任務的內容,立刻執行,無需再開發工具中編輯代碼,也無需重啟項目。

    請點擊任務右側 “GLUE” 按鈕,進入 “GLUE編輯器開發界面” ,見下圖。“GLUE模式(Java)” 運行模式的任務默認已經初始化了示例任務代碼,即打印Hello World。

    任務以源碼方式維護在調度中心,支持通過Web IDE在線更新,實時編譯和生效,因此不需要指定JobHandler

    4.2.編寫代碼

    保存之后可以在操作按鈕里面去編寫任務

    (“GLUE模式(Java)” 運行模式的任務實際上是一段繼承自IJobHandler的Java類代碼,它在執行器項目中運行,可使用@Resource/@Autowire注入執行器里中的其他服務),比如我的定時任務如下,編輯好之后點擊保存

    保存好之后,啟動定時任務,效果如下

    三.XXL-JOB集群部署

    1.調度中心集群

    1.1.問題概述

    調度中心支持集群部署,提升調度系統容災和可用性。調度中心集群部署時,幾點要求和建議:

    • DB配置保持一致;
    • 集群機器時鐘保持一致(單機集群忽視);
    • 當啟動多個調度器時,執行器配置調度中心部署跟地址可以用逗號分隔。執行器將會使用該地址進行"執行器心跳注冊"和"任務結果回調";為空則關閉自動注冊;
    但是建議:推薦通過nginx為調度中心集群做負載均衡,分配域名。調度中心訪問、執行器回調配置、調用API服務等操作均通過該域名進行。
    1.2.啟動多個調度中心

    修改調度中心端口,啟動多個調度中心,我這里啟動兩個如

    • http://localhost:18080/xxl-job-admin/
    • http://localhost:18081/xxl-job-admin/
    1.3.配置Nginx負載均衡

    當啟動多個調度器時,執行器配置調度中心部署跟地址可以用逗號分隔。執行器將會使用該地址進行“執行器心跳注冊”和“任務結果回調”;為空則關閉自動注冊;

    但是建議:推薦通過nginx為調度中心集群做負載均衡,分配域名。調度中心訪問、執行器回調配置、調用API服務等操作均通過該域名進行。

    我們啟動了2個調度中心,那么我的執行器項目該注冊到哪個調度中心呢?我們通過Nginx來解決這個問題,原理如下圖:

    我們再hosts配置 www.jobs.com作為nginx的主機域名,然后反向代理到多個調度中心,這樣一來執行器就只需要注冊到www.jobs.com Nginx即可。

    修改 C:\Windows\System32\drivers\etc\hosts增加配置如下

    127.0.0.1 www.jobs.com
    

    Nginx配置如下

    #調度中心
    upstream jobs{
     server localhost:18080;
     server localhost:18081;
    }
    
    server {
          listen       80;
          #使用域名
          server_name  www.jobs.com;
    
          #charset koi8-r;
    
          #access_log  logs/host.access.log  main;
    
          location / {
           #調度中心反向代理配置
              proxy_pass   http://jobs/;
          }
    
          #error_page  404              /404.html;
    
          # redirect server error pages to the static page /50x.html
          #
          error_page   500 502 503 504  /50x.html;
          location = /50x.html {
              root   html;
          }
    
          
      }
    

    啟動Nginx,通過瀏覽器訪問 http://www.jobs.com/xxl-job-admin/ ,可以訪問到調度中心的管理界面

    2.執行器項目集群

    執行器支持集群部署,提升調度系統可用性,同時提升任務處理能力。

    執行器集群部署時,幾點要求和建議:

    • 執行器回調地址(xxl.job.admin.addresses)需要保持一致;執行器根據該配置進行執行器自動注冊等操作。
    • 同一個執行器集群內AppName(xxl.job.executor.appname)需要保持一致;調度中心根據該配置動態發現不同集群的在線執行器列表。
    2.1.啟動多個執行器項目

    現在對執行器項目做集群,修改xxl-job-executor-sample-springboot配置文件application.properties

    • server.port : 既然是做集群,項目端口需要修改
    • xxl.job.admin.addresses : 調度中心地址需要修改成www.jobs.com ,多個執行器配置同一個地址。
    • xxl.job.executor.port : RPC通信端口也要修改,多個執行器該端口需要不一樣

    第一個實例配置

    server.port=19090
    xxl.job.admin.addresses=http://www.jobs.com/xxl-job-admin #對應Nginx地址
    xxl.job.executor.port=9999
    

    第二個實例配置

    server.port=19091
    xxl.job.admin.addresses=http://www.jobs.com/xxl-job-admin
    xxl.job.executor.port=9998
    

    Configurations中配置,允許啟動多個實例

    啟動實例如下

    2.2.配置定時任務

    通過http://www.jobs.com/xxl-job-admin 訪問調度中心管理界面,在執行器管理中可以看到多臺執行器實例

    在任務管理中,可以編輯任務,然后選擇路由策略,比如:選擇輪詢,然后啟動任務,就會看到兩個執行器項目輪著執行定時任務。

    說在最后

    xxl-job確實很強大,功能也很全,經過該文章學習相信你可以把xxl-job給用起來了,但是如果你的項目是一個小體量的單體,我不太建議使用它,Quzrtz或者SpringBoot Task就足夠 ,對于xxl-job個人還是有些笨重。

    mysql定時任務分布式部署
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    任務模塊專注于任務的執行等操作,開發和維護更加簡單和高效;接收“調度中心”的執行請求、終止請求和日志請求等。XXL-JOB的不同任務之間并行調度、并行執行。同時支持任務終止。當任務”路由策略”選擇”故障轉移”時,當調度中心每次發起調度請求時,會按照順序對執行器發出心跳檢測請求,第一個檢測為存活狀態的執行器將會被選定并發送調度請求。
    用戶名:加密密碼:密碼最后一次修改日期:兩次密碼的修改時間間隔:密碼有效期:密碼修改到期到的警告天數:密碼過期之后的寬限天數:賬號失效時間:保留。查看下pid所對應的進程文件路徑,
    目前業界常見的延時消息方案
    背景我負責的系統到2021年初完成了功能上的建設,開始進入到推廣階段。隨著推廣的逐步深入,收到了很多好評的同時也收到了很多對性能的吐槽。作為一個優秀的后端程序員,這個數據肯定是不能忍的,我們馬上就進入了漫長的接口優化之路。
    添加消息的任務我們稱為producer,而取出并使用消息的任務,我們稱之為consumer。kafka應運而生,它是專門設計用來做消息中間件的系統。這兩點也是kafka要解決的核心問題。為此,kafka提出了partition的概念。由于消息不會被刪除,因此可以等消費者明確告知kafka這條消息消費成功以后,再去更新游標。對于同一個topic,不同的消費組有各自的游標。
    網上安全滲透測試工具整理全集,部分鏈接可能失效,但可以搜索到
    Web Hacking 101 中文版:https://wizardforcel.gitbooks.io/web-hacking-101/content/ 淺入淺出Android安全 中文版:https://wizardforcel.gitbooks.io/asani/content/ Android 滲透測試學習手冊 中文
    零信任策略下K8s安全監控最佳實踐
    低代碼成了企追求的主流目標,與使用計算機編程語言構建應用程序的傳統方法不同,低代碼開發平臺是使用圖形向導來創建和構建軟件的應用程序開發平臺。因此,在許多情況下,低代碼或無代碼(幾乎沒有代碼)這個名稱是作為可視化開發工具來幫助設計人員進行拖放、組件瀏覽器和邏輯構建器的。
    系統定位是發現資產,進行端口爆破。幫助企業更快發現弱口令問題。如果之前安裝過,使用如下命令刪除所有名字包含linglong的歷史鏡像。一般這時候就部署好了,如果訪問不了. 要確認下服務器上安全組的8001和18000有沒有打開。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类