<del id="nnjnj"></del><track id="nnjnj"></track>

<p id="nnjnj"></p>

<address id="nnjnj"></address>

    <pre id="nnjnj"><pre id="nnjnj"></pre></pre>

      <noframes id="nnjnj"><ruby id="nnjnj"><ruby id="nnjnj"></ruby></ruby>

      • 自動秒收錄
      • 軟件:1973
      • 資訊:56179|
      • 收錄網站:177876|

      IT精英團

      涂鴉智能 dubbo-go 億級流量的實踐與探索

      涂鴉智能 dubbo-go 億級流量的實踐與探索

      瀏覽次數:
      評論次數:
      編輯: mob604756f0bbf4
      信息來源: 51CTO博客
      更新日期: 2021-04-28 20:30:44
      摘要

      dubbo是一個基于Java開發的高性能的輕量級RPC框架,dubbo提供了豐富的服務治理功能和優秀的擴展能力。而dubbo-go在java與golang之間提供統一的服務化能力與標準,是涂鴉智能目前最需要解決的主要問題。本文分為實踐和快速接入兩部分,分享在涂鴉智能的dubbo-go實戰經驗,意在幫助用戶快速接入dubbo-goRPC框架,希望能讓大家少走些彎路。另外,文中的測試代碼基于dubbo

      • 正文開始
      • 相關閱讀
      • 推薦作品

      dubbo 是一個基于 Java 開發的高性能的輕量級 RPC 框架,dubbo 提供了豐富的服務治理功能和優秀的擴展能力。而 dubbo-go 在 java 與 golang 之間提供統一的服務化能力與標準,是涂鴉智能目前最需要解決的主要問題。本文分為實踐和快速接入兩部分,分享在涂鴉智能的 dubbo-go 實戰經驗,意在幫助用戶快速接入 dubbo-go RPC 框架,希望能讓大家少走些彎路。
      另外,文中的測試代碼基于 dubbo-go版本 v1.4.0。

      dubbo-go 網關實踐
      涂鴉智能 dubbo-go 億級流量的實踐與探索

      dubbo-go 在涂鴉智能的使用情況如上圖,接下來會為大家詳細介紹落地細節,希望這些在生產環境中總結的經驗能夠幫助到大家。

      背景
      在涂鴉智能,dubbo-go 已經作為了 golang 服務與原有 dubbo 集群打通的首選 RPC 框架。其中比較有代表性的 open-gateway 網關系統(下文統一稱 gateway,開源版本見 https://github.com/dubbogo/dubbo-go-proxy)。該 gateway 動態加載內部 dubbo 接口信息,以HTTP API 的形式對外暴露。該網關意在解決上一代網關的以下痛點。

      • 通過頁面配置 dubbo 接口開放規則,步驟繁瑣,權限難以把控。

      • 接口非 RESTful 風格,對外部開發者不友好。

      • 依賴繁重,升級風險大。

      • 并發性能問題。

      架構設計
      針對如上痛點,隨即著手準備設計新的 gateway 架構。首先就是語言選型,golang 的協程調用模型使得 golang 非常適合構建 IO 密集型的應用,且應用部署上也較 java 簡單。經過調研后我們敲定使用 golang 作為 proxy 的編碼語言,并使用 dubbo-go 用于連接 dubbo provider 集群。provider 端的業務應用通過使用 java 的插件,以注解形式配置 API 配置信息,該插件會將配置信息和 dubbo 接口元數據更新到元數據注冊中心(下圖中的 redis )。這樣一來,配置從管理后臺頁面轉移到了程序代碼中。開發人員在編碼時,非常方便地看到 dubbo 接口對外的 API 描述,無需從另外一個管理后臺配置 API 的使用方式。
      涂鴉智能 dubbo-go 億級流量的實踐與探索

      實踐
      從上圖可以看到,網關能動態加載 dubbo 接口信息,調用 dubbo 接口是基于 dubbo 泛化調用。泛化調用使 client 不需要構建 provider 的 interface 代碼,在 dubbo-go 中表現為無需調用 config.SetConsumerService 和 hessian.RegisterPOJO 方法,而是將請求模型純參數完成,這使得 client 動態新增、修改接口成為可能。在 apache/dubbo-sample/golang/generic/go-client 中的有泛化調用的演示代碼。

      
      func test() {
          var appName = "UserProviderGer"
          var referenceConfig = config.ReferenceConfig{
              InterfaceName: "com.ikurento.user.UserProvider",
              Cluster:       "failover",
              Registry:      "hangzhouzk",
              Protocol:      dubbo.DUBBO,
              Generic:       true,
          }
          referenceConfig.GenericLoad(appName) // appName is the unique identification of RPCService
      
          time.Sleep(3 * time.Second)
      
          resp, err := referenceConfig.GetRPCService().(*config.GenericService).
              Invoke([]interface{}{"GetUser", []string{"java.lang.String"}, []interface{}{"A003"}})
          if err != nil {
              panic(err)
          }
      }
      

      泛化調用的實現其實相當簡單。其功能作用在 dubbo 的 Filter 層中。Generic Filter 已經作為默認開啟的 Filter 加入到 dubbo Filter 鏈中。其核心邏輯如下:

      func (ef *GenericFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
          if invocation.MethodName() == constant.GENERIC && len(invocation.Arguments()) == 3 {
              oldArguments := invocation.Arguments()
      
              if oldParams, ok := oldArguments[2].([]interface{}); ok {
                  newParams := make([]hessian.Object, 0, len(oldParams))
                  for i := range oldParams {
                      newParams = append(newParams, hessian.Object(struct2MapAll(oldParams[i])))
                  }
                  newArguments := []interface{}{
                      oldArguments[0],
                      oldArguments[1],
                      newParams,
                  }
                  newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments())
                  newInvocation.SetReply(invocation.Reply())
                  return invoker.Invoke(ctx, newInvocation)
              }
          }
          return invoker.Invoke(ctx, invocation)
      }
      

      Generic Filter 將用戶請求的結構體參數轉化為統一格式的 map(代碼中的 struct2MapAll ),將類( golang 中為 struct )的正反序列化操作變成 map 的正反序列化操作。這使得無需 POJO 描述通過硬編碼注入 hessain 庫。

      從上面代碼可以看到,泛化調用實際需要動態構建的內容有 4 個,ReferenceConfig 中需要的 InterfaceName 、參數中的 method 、ParameterTypes、實際入參 requestParams。

      那么這些參數是如何從 HTTP API 匹配獲取到的呢?

      這里就會用到上文提到的 provider 用于收集元數據的插件。引入插件后,應用在啟動時會掃描需要暴露的 dubbo 接口,將 dubbo 元數據和 HTTP API 關聯。插件使用方法大致如下,這里調了幾個簡單的配置作為示例,實際生產時注解內容會更多。
      涂鴉智能 dubbo-go 億級流量的實踐與探索

      最終獲得的 dubbo 元數據如下:

      
      {
          "key": "POST:/hello/{uid}/add",
          "interfaceName": "com.tuya.hello.service.template.IUserServer",
          "methodName": "addUser",
          "parameterTypes": ["com.tuya.gateway.Context", "java.lang.String", "com.tuya.hello.User"],
          "parameterNames": ["context", "uid", "userInfo"],
          "updateTimestamp": "1234567890",
          "permissionDO":{},
          "voMap": {
              "userInfo": {
                  "name": "java.lang.String",
                  "sex": "java.lang.String",
                  "age": "java.lang.Integer"
              }
          },
          "parameterNameHumpToLine": true,
          "resultFiledHumpToLine": false,
          "protocolName": "dubbo",
        .......
      }
      

      Gateway 從元數據配置中心訂閱到以上信息,就能把一個 API 請求匹配到一個 dubbo 接口。再從 API 請求中抓取參數作為入參。這樣功能就完成了流量閉環。

      以上內容,大家應該對此 gateway 的項目拓撲結構有了清晰的認知。我接著分享項目在使用 dubbo-go 過程中遇到的問題和調優經驗。19 年初,當時的 dubbo-go 項目還只是構建初期,沒有什么用戶落地的經驗。我也是一邊參與社區開發,一邊編碼公司內部網關項目。在解決了一堆 hessain 序列化和 zookeeper 注冊中心的問題后,項目最終跑通了閉環。但是,作為一個核心應用,跑通閉環離上生產環境還有很長的路要走,特別是使用了當時穩定性待測試的新框架。整個測試加上功能補全,整整花費了一個季度的時間,直到項目趨于穩定,壓測效果也良好。單臺網關機器( 2C 8G )全鏈路模擬真實環境壓測達到 2000 QPS。由于引入了比較重的業務邏輯(單個請求平均調用 3 個 dubbo 接口),對于這個壓測結果,是符合甚至超出預期的。

      總結了一些 dubbo-go 參數配置調優的經驗,主要是一些網絡相關配置。大家在跑 demo 時,應該會看到配置文件最后有一堆配置,但如果對 dubbo-go 底層網絡模型不熟悉,就很難理解這些配置的含義。目前 dubbo-go 網絡層以 getty 為底層框架,實現讀寫分離和協程池管理。getty 對外暴露 session 的概念,session 提供一系列網絡層方法注入的實現,因為本文不是源碼解析文檔,在這里不過多論述。讀者可以簡單的認為 dubbo-go 維護了一個 getty session池,session 又維護了一個 TCP 連接池。對于每個連接,getty 會有讀協程和寫協程伴生,做到讀寫分離。這里我盡量用通俗的注釋幫大家梳理下對性能影響較大的幾個配置含義:

      
      protocol_conf:
        # 這里是協議獨立的配置,在dubbo協議下,大多數配置即為getty session相關的配置。
        dubbo:
            # 一個session會始終保證connection_number個tcp連接個數,默認是16,
          # 但這里建議大家配置相對小的值,一般系統不需要如此多的連接個數。
          # 每隔reconnect_interval時間,檢查連接個數,如果小于connection_number,
          # 就建立連接。填0或不填都為默認值300ms
          reconnect_interval: 0
          connection_number: 2
          # 客戶端發送心跳的間隔
          heartbeat_period: "30s"
          # OnCron時session的超時時間,超過session_timeout無返回就關閉session
          session_timeout: "30s"
          # 每一個dubbo interface的客戶端,會維護一個最大值為pool_size大小的session池。
          # 每次請求從session池中select一個。所以真實的tcp數量是session數量*connection_number,
          # 而pool_size是session數量的最大值。測試總結下來一般程序4個tcp連接足以。
          pool_size: 4
          # session?;畛瑫r時間,也就是超過session_timeout時間沒有使用該session,就會關閉該session
          pool_ttl: 600
          # 處理返回值的協程池大小
          gr_pool_size: 1200
          # 讀數據和協程池中的緩沖隊列長度,目前已經廢棄。不使用緩沖隊列
          queue_len: 64
          queue_number: 60
          getty_session_param:
            compress_encoding: false
            tcp_no_delay: true
            tcp_keep_alive: true
            keep_alive_period: "120s"
            tcp_r_buf_size: 262144
            tcp_w_buf_size: 65536
            pkg_wq_size: 512
            tcp_read_timeout: "1s"  # 每次讀包的超時時間
            tcp_write_timeout: "5s" # 每次寫包的超時時間
            wait_timeout: "1s" 
            max_msg_len: 102400     # 最大數據傳輸長度
            session_name: "client"
      

      dubbo-go 快速接入
      前文已經展示過 dubbo-go 在涂鴉智能的實踐成果,接下來介紹快速接入 dubbo-go 的方式。

      第一步:hello world
      dubbo-go 使用范例目前和 dubbo 一致,放置在 apache/dubbo-samples 項目中。在 dubbo-sample/golang 目錄下,用戶可以選擇自己感興趣的 feature 目錄,快速測試代碼效果。

      
      tree dubbo-samples/golang -L 1
      dubbo-samples/golang
      ├── README.md
      ├── async
      ├── ci.sh
      ├── configcenter
      ├── direct
      ├── filter
      ├── general
      ├── generic
      ├── go.mod
      ├── go.sum
      ├── helloworld
      ├── multi_registry
      └── registry
      

      我們以 hello world 為例,按照 dubbo-samples/golang/README.md 中的步驟,分別啟動 server 和 client ??梢試L試 golang 調用 java 、 java 調用 golang 、golang 調用 golang 、java 調用 java。dubbo-go 在協議上支持和 dubbo 互通。

      我們以啟動 go-server 為例,注冊中心默認使用 zookeeper 。首先確認本地的 zookeeper 是否運行正常。然后執行以下命令,緊接著你就可以看到你的服務正常啟動的日志了。

      export ARCH=mac
      export ENV=dev
      cd dubbo-samples/golang/helloworld/dubbo/go-server
      sh ./assembly/$ARCH/$ENV.sh
      cd ./target/darwin/user_info_server-2.6.0-20200608-1056-dev/
      sh ./bin/load.sh start
      

      第二步:在項目中使用 dubbo-go
      上面,我們通過社區維護的測試代碼和啟動腳本將用例跑了起來。接下來,我們需要在自己的代碼中嵌入 dubbo-go 框架。很多朋友往往是在這一步遇到問題,這里我整理的一些常見問題,希望能幫到大家。

      1. 環境變量
        目前 dubbo-go 有 3 個環境變量需要配置。
      • CONF_CONSUMER_FILE_PATH : Consumer 端配置文件路徑,使用 consumer 時必需。

      • CONF_PROVIDER_FILE_PATH:Provider 端配置文件路徑,使用 provider 時必需。

      • APP_LOG_CONF_FILE :Log 日志文件路徑,必需。

      • CONF_ROUTER_FILE_PATH:File Router 規則配置文件路徑,使用 File Router 時需要。
      1. 代碼注意點
        注入服務 : 檢查是否執行以下代碼
      # 客戶端
      func init() {
        config.SetConsumerService(userProvider)
      }
      # 服務端
      func init() {
        config.SetProviderService(new(UserProvider))
      }

      注入序列化描述 :檢查是否執行以下代碼

        hessian.RegisterJavaEnum(Gender(MAN))
        hessian.RegisterJavaEnum(Gender(WOMAN))
        hessian.RegisterPOJO(&User{})
      
      1. 正確理解配置文件
        references/services 下的 key ,如下面例子的 "UserProvider" 需要和服務 Reference() 返回值保持一致,此為標識改接口的 key。

      references:
      "UserProvider":
      registry: "hangzhouzk"
      protocol : "dubbo"
      interface : "com.ikurento.user.UserProvider"
      cluster: "failover"
      methods :

      • name: "GetUser"
        retries: 3
      
      注冊中心如果只有一個注冊中心集群,只需配置一個。多個 IP 用逗號隔開,如下:
      

      registries :
      "hangzhouzk":
      protocol: "zookeeper"
      timeout : "3s"
      address: "172.16.120.181:2181,172.16.120.182:2181"
      username: ""
      password: ""

      
      
      4. java 和 go 的問題
      go 和 java 交互的大小寫 :golang 為了適配 java 的駝峰格式,在調用 java 服務時,會自動將 method 和屬性首字母變成小寫。很多同學故意將 java 代碼寫成適配 golang 的參數定義,將首字母大寫,最后反而無法序列化匹配。
      
      **第三步:拓展功能**
      dubbo-go 和 dubbo 都提供了非常豐富的拓展機制??梢詫崿F自定義模塊代替 dubbo-go 默認模塊,或者新增某些功能。比如實現 Cluster、Filter 、Router 等來適配業務的需求。這些注入方法暴露在 dubbo-go/common/extension 中,允許用戶調用及配置。
      
      本文作者:
      潘天穎,Github ID @pantianying,開源愛好者,就職于涂鴉智能。
      
      歡迎加入 dubbo-go 社區
      有任何 dubbo-go 相關的問題,可以加我們的釘釘群 23331795 詢問探討,我們一定第一時間給出反饋。
      標簽:Java
      JetBrains 發布 2020 年 Go 語言調查報告
      ? 上一篇 2021-04-28
      [斗魚]沒人比我更懂微服務--Go微服務框架Jupiter
      下一篇 ? 2021-04-28
      • 談如何設計未來的倉庫建筑
        4閱讀 0條評論 個贊
        編輯:數據社全文共3758個字,建議10分鐘閱讀大家好,我是峰哥,夏天已經來了,小麥馬上要豐收了,今天分析一篇關于未來數倉架構發展方向的文章。Linked大佬JayKreps曾發表過一篇博客,簡單闡……
      • 高并發服務的幾點優化經驗
        0閱讀 0條評論 個贊
        前言:如何優化高并發服務,這里指的是qps在20萬以上的在線服務,注意不是離線服務,在線服務會存在哪些挑戰呢?①無法做離線緩存,所有的數據都是實時讀的②大量的請求會打到線上服務,對于服務的響應時間要……
      • Java處理異常的9個最佳實踐 你做得對嗎?
        1閱讀 0條評論 個贊
        原文:https://dzone.com/articles/9-best-practices-to-handle-exceptions-in-java譯者:颯然Hang譯文:http://www.r……
      • 提高Java字符串編碼和解碼性能的技巧
        1閱讀 0條評論 個贊
        1常見字符串編碼●常見的字符串編碼有:LATIN1只能保存ASCII字符,又稱ISO-8859-1。UTF-8變長字節編碼,一個字符需要使用1個、2個或者3個byte表示。由于中文通常需要3個字節……
      • Linux預定任務調度(crontab) 好實用!
        0閱讀 0條評論 個贊
        概述crontab命令用于設置周期性被執行的指令。該命令從標準輸入設備讀取指令,并將其存放于“crontab”文件中,以供之后讀取和執行??梢允褂胏rontab定時處理離線任務,比如每天凌晨2點更新數……
      發表評論 共有條評論
      用戶名: 密碼:
      驗證碼: 匿名發表
      • 誤操作離線丟棄和恢復場景測試的業務影響——來自“血”的教訓
        0閱讀 0條評論 個贊
        在數據庫恢復過程中,比如我們用了第三方的備份工具,在實施恢復操作時會導出需要的某個表空間這樣可以大大減少恢復時間,是十分值得推薦的做法,這個過程中由于修改控制文件中數據文件的相關信息,需要執行alte……
      • 一行Python代碼實現程序并行
        1閱讀 0條評論 個贊
        Python在程序并行化方面多少有些聲名狼藉。撇開技術上的問題,例如線程的實現和GIL,我覺得錯誤的教學指導才是主要問題。常見的經典Python多線程、多進程教程多顯得偏"重"。而且往往隔靴搔……
      • Linux預定任務調度(crontab) 好實用!
        0閱讀 0條評論 個贊
        概述crontab命令用于設置周期性被執行的指令。該命令從標準輸入設備讀取指令,并將其存放于“crontab”文件中,以供之后讀取和執行??梢允褂胏rontab定時處理離線任務,比如每天凌晨2點更新數……
      • 甲骨文(第11代)單實例-室內空調(第11代)遷移模擬測試
        0閱讀 0條評論 個贊
        Oracle11.2.0.4單實例----Oracle19C-RAC遷移模擬測試總體思想:通過RMAN物理備份在備庫恢復主庫數據,后續通過在主庫停業務后,將從備份后的所有日志都同步到新庫應用,重新配置……
      • 基礎鞏固——至少需要多少行代碼才能實現深度復制?
        1閱讀 0條評論 個贊
        前言深度克?。ㄉ羁截悾┮恢倍际浅?、中級前端面試中經常被問到的題目,網上介紹的實現方式也都各有千秋,大體可以概括為三種方式:JSON.stringify+JSON.parse,這個很好理解;全量判斷類……
      • 緊急情況下數據庫表被鎖 抓瞎?
        4閱讀 0條評論 個贊
        以下文章來源于公眾號-程序新視界,作者二師兄在程序員的職業生涯中,總會遇到數據庫表被鎖的情況,前些天就又撞見一次。由于業務突發需求,各個部門都在批量操作、導出數據,而數據庫又未做讀寫分離,結果就是:數……
      • Linux的10個最危險的命令
        0閱讀 0條評論 個贊
        rm-rf命令該命令可能導致不可恢復的系統崩壞。>rm-rf/#強制刪除根目錄下所有東西。>rm-rf*#強制刪除當前目錄的所有文件。>rm-rf.#強制刪除當前文件夾及其子文件夾。執行rm-r……
      • 如何在Linux下擴展XFS根分區
        2閱讀 0條評論 個贊
        在某些情況下,/分區在Linux中磁盤空間不足。即使壓縮和刪除舊的日志文件也無濟于事,因此在這種情況下,我們別無選擇,只能擴展/文件系統。在本文中,我們將演示如何在Linux系統中擴展不……
      • 服務器端高并發分布式架構的演進之路
        1閱讀 0條評論 個贊
        1.概述本文以淘寶作為例子,介紹從一百個到千萬級并發情況下服務端的架構的演進過程。同時列舉出每個演進階段會遇到的相關技術,讓大家對架構的演進有一個整體的認知。文章最后匯總了一些架構設計的原則。特別說……
      • 談談復雜項目代碼的應用分層
        1閱讀 0條評論 個贊
        —1—背景說起應用分層,大部分人都會認為這個不是很簡單嘛就controller,service,mapper三層??雌饋砗唵?,很多人其實并沒有把他們職責劃分開,在很多代碼中,controller做……
      • 不容錯過的20個ES6技巧
        5閱讀 0條評論 個贊
        前言大家好,我是xieyezi,好久不見,我又重新回歸掘金啦,這次為大家整理了20個使用頻率很高的ES6代碼塊,希望大家喜歡……
      • 如何優雅地升級Kubernetes集群的Docker和Containerd版本
        1閱讀 0條評論 個贊
        前言公司用的k8s集群是“多環境合一”的方式,集群流量入口也摒棄了常見的traefik和ingress-nginx,直接用了一個國內不常見的底層基于Envoy的APIGateway網關服務。當然還有……
      • Linux最常用的命令:解決95%以上的問題
        1閱讀 0條評論 個贊
        Linux是目前應用最廣泛的服務器操作系統,基于Unix,開源免費,由于系統的穩定性和安全性,市場占有率很高,幾乎成為程序代碼運行的最佳系統環境。linux不僅可以長時間的運行我們編寫的程序代碼,還可……
      • 如何用10行bash shell腳本監控Linux?
        1閱讀 0條評論 個贊
        http://985.so/xbtd子沐愛掃地(譯)監控我們的環境對于服務器運維來說至關重要,尤其是在部署新的應用程序時。如今,公司每天都使用開源解決方案來監控系統資源。但是,當出于測試的目的來監控……
      • 說說春云的全鏈路灰度發布方案~
        1閱讀 0條評論 個贊
        以下文章來源于公眾號-碼猿技術專欄,作者不才陳某大家好實際生產中如有需求變更,并不會直接更新線上服務,最通常的做法便是:切出線上的小部分流量進行體驗測試,經過測試后無問題則全面的上線。這樣做的好處也是……
      • 零入侵:一個注解 循環重試功能的優雅實現
        0閱讀 0條評論 個贊
        前言在實際工作中,重處理是一個非常常見的場景,比如:發送消息失敗。調用遠程服務失敗。爭搶鎖失敗。這些錯誤可能是因為網絡波動造成的,等待過后重處理就能成功。通常來說,會用try/catch,while循……
      • 納尼?數據也是立法的嗎?
        1閱讀 0條評論 個贊
        編輯:彭文華來源:大數據架構師(ID:bigdata_arch)彭友們好,我是老彭。最近忙瘋了,天天給客戶寫方案,都沒時間寫文章了。趁著五一假期,跟彭友們嘮嘮新鮮事兒。今天這個,真的是顛覆我的認知,……
      • 解決緩存崩潰問題的一行代碼
        1閱讀 0條評論 個贊
        以下文章來源于公眾號-孤獨煙,作者孤獨煙引言今天,重新回顧一下緩存擊穿這個問題!之所以寫這個文章呢,因為目前網上流傳的文章落地性太差(什么布隆過濾器啊,布谷過濾器啊,嗯,你們懂的),其實這類方案并不適……
      • PostgreSQL并行框架分析
        3閱讀 0條評論 個贊
        作者簡介施博文,目前就職于騰訊云PG團隊概覽PostgreSQL并行框架提供了一系列方便的函數,支持在插件或內核中直接調用相關函數,啟動若干個后臺進程進行并行操作。目前,PG的并行框架主要用來……
      • Python的八個實用“無代碼”特性
        1閱讀 0條評論 個贊
        注:在命令行中使用Python時,“-m”選項參數可以實現非常強大的功能??梢哉f,善用“-m”參數,這是一個優秀的Python技術人的必備技能。曾發過一篇文章《Python中-m的典型用……
      最近發布資訊
      更多
      警花高潮嗷嗷叫
      <del id="nnjnj"></del><track id="nnjnj"></track>

      <p id="nnjnj"></p>

      <address id="nnjnj"></address>

        <pre id="nnjnj"><pre id="nnjnj"></pre></pre>

          <noframes id="nnjnj"><ruby id="nnjnj"><ruby id="nnjnj"></ruby></ruby>