精华内容
下载资源
问答
  • 搭建企业级可用HBase

    千次阅读 2016-08-10 17:19:53
    本文介绍了HBase的企业级可用集群的配置方法,并介绍了如何动态增删集群节点。

    1 HBase介绍

    HBase是一个分布式的、面向列的开源数据库,就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。它是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。

    HBase的常见使用场景如下:

    1、大数据量(100s TB级数据)且有快速随机访问的需求。例如淘宝的交易历史记录,数据量巨大无容置疑,面向普通用户的请求必然要即时响应。

    2、容量的优雅扩展。大数据驱使下的动态扩展系统容量是必须的。

    3、业务场景简单,不需要关系数据库中很多特性(例如交叉列、交叉表,事务,连接等等)。

    4、合理设计rowkey。因为hbase的查询用rowkey是最高效的,也几乎是生产环境下唯一可行的方式。

    2 集群规划

    在搭建HBase高可用集群时,将HBase的RegionServer部署在HDFS的3个DataNode节点上,HBase的HMaster服务部署在HDFS的2个NameNode(Active和Standby)节点上,部署2个HMaster保证集群的高可用性,防止单点问题。这里使用了独立的ZooKeeper集群,未使用HBase自带的ZooKeeper。下面给出HBase的集群搭建架构图:

    搭建HBase HA集群需要首先搭建Hadoop HA集群,其方法可参考我的上一篇文章《Hadoop2.0 HA高可用集群配置详解》。在其基础上加入HBaseHA,规划整个集群由5台主机组成,具体情况如下表所示:

    主机名

    IP地址

    安装的软件

    JPS

    hadoop-master1

    172.16.20.81

    Jdk/hadoop/hbase

    Namenode/ZKFC/ResourceManager/

    JobHistoryServer/HMaster

    hadoop-master2

    172.16.20.82

    Jdk/hadoop/hbase

    Namenode/ZKFC/ResourceManager/

    WebProxyServer/HMaster

    hadoop-slave1

    172.16.20.83

    Jkd/hadoop/hbase/zookeepe

    Datanode/JournalNode/NodeManager/

    quorumPeerMain/HRegionServer

    hadoop-slave2

    172.16.20.84

    Jkd/hadoop/hbase/zookeeper

    Datanode/JournalNode/NodeManager/

    quorumPeerMain/HRegionServer

    hadoop-slave3

    172.16.20.85

    Jkd/hadoop/hbase/zookeeper

    Datanode/JournalNode/NodeManager/

    quorumPeerMain/HRegionServer

    3 企业级系统参数配置

    // 查看linux系统最大进程数和最大文件打开数

    $ ulimit-a


    // 设置linux系统最大进程数和最大文件打开数(设置完重新登录shell)

    $ suroot

    # vim/etc/security/limits.conf

    root    soft   nproc   50000

    root    hard   nproc   50000

    root    soft   nofile  25535

    root    hard   nofile  25535

    hadoop    soft   nproc   50000

    hadoop    hard   nproc   50000

    hadoop    soft   nofile  25535

    hadoop    hard   nofile  25535

    // 调整linux内核参数

    # vim/etc/sysctl.conf

    net.ipv4.ip_forward= 0

    net.ipv4.conf.default.rp_filter= 1

    net.ipv4.conf.default.accept_source_route= 0

    kernel.core_users_pid= 1

    net.ipv4.tcp_syncookies= 1

    net.bridge.bridge-nf-call-ip6tables= 0

    net.bridge.bridge-nf-call-iptables= 0

    net.bridge.bridge-nf-call-arptables= 0

    kernel.mggmnb= 65536

    kernel.mggmax= 65536

    kernel.shmmax= 68719476736

    kernel.shmall= 268435456

    net.ipv4.tcp_max_syn_backlog= 65000

    net.core.netdev_max_backlog= 32768

    net.core.somaxconn= 32768

    fs.file-max= 65000

    net.core.wmem_default= 8388608

    net.core.rmem_default= 8388608

    net.core.rmem_max= 16777216

    net.core.wmem_max= 16777216

    net.ipv4.tcp_timestamps= 1

    net.ipv4.tcp_synack_retries= 2

    net.ipv4.tcp_syn_retries= 2

    net.ipv4.tcp_mem= 94500000 915000000 927000000

    net.ipv4.tcp_max_orphans= 3276800

    net.ipv4.tcp_tw_reuse= 1

    net.ipv4.tcp_tw_recycle= 1

    net.ipv4.tcp_keepalive_time= 1200

    net.ipv4.tcp_syncookies= 1

    net.ipv4.tcp_fin_timeout= 10

    net.ipv4.tcp_keepalive_intvl= 15

    net.ipv4.tcp_keepalive_probes= 3

    net.ipv4.ip_local_port_range= 1024 65535

    net.ipv4.conf.eml.send_redirects= 0

    net.ipv4.conf.lo.send_redirects= 0

    net.ipv4.conf.default.send_redirects= 0

    net.ipv4.conf.all.send_redirects= 0

    net.ipv4.icmp_echo_ignore_broadcasts= 1

    net.ipv4.conf.eml.accept_source_route= 0

    net.ipv4.conf.lo.accept_source_route= 0

    net.ipv4.conf.default.accept_source_route= 0

    net.ipv4.conf.all.accept_source_route= 0

    net.ipv4.icmp_ignore_bogus_error_responses= 1

    kernel.core_pattern= /tmp/core

    vm.overcommit_memory= 1

    #sysctl -p

    4 HBase HA配置

    // 在hadoop-master1节点解压hadoop安装包

    $ tar-xvf hbase-1.2.0-cdh5.7.1.tar.gz -C /home/hadoop/app/cdh/

     

    // 删除安装包

    $ rmhbase-1.2.0-cdh5.7.1.tar.gz

     

    // 进入hbase的conf目录

    $ cd/home/hadoop/app/cdh/hbase-1.2.0-cdh5.7.1/conf/

     

    // 修改hbase-env.sh

    $ vimhbase-env.sh

    # 配置JDK安装路径

    exportJAVA_HOME=/home/hadoop/app/jdk1.7.0_79

    # 配置Hadoop安装路径

    exportHADOOP_HOME=/home/hadoop/app/cdh/hadoop-2.6.0-cdh5.7.1

    # 设置HBase的日志目录

    exportHBASE_LOG_DIR=${HBASE_HOME}/logs

    # 设置HBase的pid目录

    exportHBASE_PID_DIR=${HBASE_HOME}/pids

    # 使用独立的ZooKeeper集群

    exportHBASE_MANAGES_ZK=false

    # 优化配置项

    # 设置HBase内存堆的大小

    exportHBASE_HEAPSIZE=1024

    # 设置HMaster最大可用内存

    exportHBASE_MASTER_OPTS="-Xmx512m"

    # 设置HRegionServer最大可用内存

    exportHBASE_REGIONSERVER_OPTS="-Xmx1024m"

     

    // 配置hbase-site.xml

    $ vim hbase-site.xml

    <configuration>
      <!-- 设置HRegionServers共享目录 -->
      <property>
        <name>hbase.rootdir</name>
        <value>hdfs://mycluster/hbase</value>
      </property>
      
      <!-- 设置HMaster的rpc端口 -->
      <property>
        <name>hbase.master.port</name>
        <value>16000</value>
      </property>
      
      <!-- 设置HMaster的http端口 -->
      <property>
        <name>hbase.master.info.port</name>
        <value>16010</value>
      </property>
      
      <!-- 指定缓存文件存储的路径 -->
      <property>
        <name>hbase.tmp.dir</name>
        <value>/home/hadoop/app/cdh/hbase-1.2.0-cdh5.7.1/tmp</value>
      </property>
    
      <!-- 开启分布式模式 -->
      <property>
        <name>hbase.cluster.distributed</name>
        <value>true</value>
      </property>
      
      <!-- 指定ZooKeeper集群位置 -->
      <property>
        <name>hbase.zookeeper.quorum</name>
        <value>hadoop-slave1,hadoop-slave2,hadoop-slave3</value>
      </property>
      
      <!-- 指定ZooKeeper集群端口 -->
      <property>
        <name>hbase.zookeeper.property.clientPort</name>
        <value>2181</value>
      </property>
      
      <!--指定Zookeeper数据目录,需要与ZooKeeper集群上配置相一致 -->
      <property>
        <name>hbase.zookeeper.property.dataDir</name>
        <value>/home/hadoop/app/cdh/zookeeper-3.4.5-cdh5.7.1/data</value>
      </property>
      
      <!-- \\\\\\\\\\以下为优化配置项\\\\\\\\\\ -->
      <!-- 关闭分布式日志拆分 -->
      <property>
        <name>hbase.master.distributed.log.splitting</name>
        <value>false</value>
      </property>
      
      <!-- hbase客户端rpc扫描一次获取的行数 -->
      <property>
        <name>hbase.client.scanner.caching</name>
        <value>2000</value>
      </property>
      
      <!-- HRegion分裂前最大的文件大小(10G) -->
      <property>
        <name>hbase.hregion.max.filesize</name>
        <value>10737418240</value>
      </property>
      
      <!-- HRegionServer中最大的region数量 -->
      <property>
        <name>hbase.regionserver.reginoSplitLimit</name>
        <value>2000</value>
      </property>
      
      <!-- StoreFile的个数超过这个数就开始合并 -->
      <property>
        <name>hbase.hstore.compactionThreshold</name>
        <value>6</value>
      </property>
      
      <!-- 当某一个region的storefile个数达到该值则block写入,等待compact -->
      <property>
        <name>hbase.hstore.blockingStoreFiles</name>
        <value>14</value>
      </property>
      
      <!-- 超过memstore大小的倍数达到该值则block所有写入请求,自我保护 -->
      <property>
        <name>hbase.hregion.memstore.block.multiplier</name>
        <value>20</value>
      </property>
      
      <!-- service工作的sleep间隔 -->
      <property>
        <name>hbase.server.thread.wakefrequency</name>
        <value>500</value>
      </property>
      
      <!-- ZooKeeper客户端同时访问的并发连接数 -->
      <property>
        <name>hbase.zookeeper.property.maxClientCnxns</name>
        <value>2000</value>
      </property>
      
      <!-- 根据业务情况进行配置 -->
      <property>
        <name>hbase.regionserver.global.memstore.lowerLimit</name>
        <value>0.3</value>
      </property>
      <property>
        <name>hbase.regionserver.global.memstore.upperLimit</name>
        <value>0.39</value>
      </property>
      <property>
        <name>hbase.block.cache.size</name>
        <value>0.4</value>
      </property>
      
      <!-- RegionServer的请求处理IO线程数 -->
      <property>
        <name>hbase.reginoserver.handler.count</name>
        <value>300</value>
      </property>
      
      <!-- 客户端最大重试次数 -->
      <property>
        <name>hbase.client.retries.number</name>
        <value>5</value>
      </property>
      
      <!-- 客户端重试的休眠时间 -->
      <property>
        <name>hbase.client.pause</name>
        <value>100</value>
      </property>
    </configuration>
    

    // 配置regionservers

    $ vimregionservers

    hadoop-slave1

    hadoop-slave2

    hadoop-slave3

     

    // 新建backup-masters文件并配置

    $ vimbackup-masters

    hadoop-master2

     

    // 创建hbase的缓存文件目录

    $ cd/home/hadoop/app/cdh/hbase-1.2.0-cdh5.7.1/

    $ mkdirtmp

     

    // 创建hbase的日志文件目录

    $ mkdirlogs

     

    // 创建hbase的pid文件目录

    $ mkdirpids

     

    // 将hbase工作目录同步到集群其它节点

    $ scp-r /home/hadoop/app/cdh/hbase-1.2.0-cdh5.7.1/hadoop-master2:/home/hadoop/app/cdh/

    $ scp-r /home/hadoop/app/cdh/hbase-1.2.0-cdh5.7.1/ hadoop-slave1:/home/hadoop/app/cdh/

    $ scp-r /home/hadoop/app/cdh/hbase-1.2.0-cdh5.7.1/ hadoop-slave2:/home/hadoop/app/cdh/

    $ scp-r /home/hadoop/app/cdh/hbase-1.2.0-cdh5.7.1/ hadoop-slave3:/home/hadoop/app/cdh/

     

    // 在集群各节点上修改用户环境变量

    $ vim .bash_profile

    export HBASE_HOME=/home/hadoop/app/cdh/hbase-1.2.0-cdh5.7.1

    export PATH=$PATH:$HBASE_HOME/bin

    $ source.bash_profile

     

    // 删除hbase的slf4j-log4j12-1.7.5.jar,解决hbase和hadoop的LSF4J包冲突

    $ cd /home/hadoop/app/cdh/hbase-1.2.0-cdh5.7.1/lib

    $ mvslf4j-log4j12-1.7.5.jar slf4j-log4j12-1.7.5.jar.bk

    5 集群启动

    // 启动zookeeper集群(分别在slave1、slave2和slave3上执行)

    $ zkServer.shstart

    备注:此命令分别在slave1/slave2/slave3节点启动了QuorumPeerMain。

    // 启动HDFS(在master1执行)

    $ start-dfs.sh

    备注:此命令分别在master1/master2节点启动了NameNode和ZKFC,分别在slave1/slave2/slave3节点启动了DataNode和JournalNode。

    // 启动YARN(在master2执行)

    $ start-yarn.sh

    备注:此命令在master2节点启动了ResourceManager,分别在slave1/slave2/slave3节点启动了NodeManager。

    // 启动YARN的另一个ResourceManager(在master1执行,用于容灾)

    $ yarn-daemon.sh start resourcemanager

    备注:此命令在master1节点启动了ResourceManager。

    // 启动HBase(在master1执行)

    $ start-hbase.sh

    备注:此命令分别在master1/master2节点启动了HMaster,分别在slave1/slave2/slave3节点启动了HRegionServer。

    6 功能测试

    6.1 Web UI

    下图为http://hadoop-master1:16010,可看到主Master状态:


    下图为http://hadoop-master2:50070,可看到备份Master状态:


    6.2 Shell操作

    // 连接hbase客户端

    $ hbase shell

     

    // 创建表,表名为employee,列族为info

    > create 'employee','info'

     

    // 显示hbase已创建的表,验证表employee是否创建成功

    > list

     

    // 在表employee中插入测试数据

    > put'employee','rowkey01','info:id','1001'

    > put'employee','rowkey01','info:name','Henry'

    > put 'employee','rowkey01','info:address','Bangalore'

    > put'employee','rowkey02','info:id','1002'

    > put'employee','rowkey02','info:name','Messi'

     

    // 检索表employee中的所有记录

    > scan 'employee'

     

    // 检索表employee中行键为rowkey01的记录

    > get 'employee','rowkey01'

     

    // 禁用表employee并删除

    > disable 'employee'

    > drop 'employee'

     

    7 动态替换节点

    7.1 Hadoop动态添加节点

    (一)设置新节点与集群NameNode的SSH无密码登录

    (二)在hosts文件中添加主机名和IP地址,并将该文件同步到集群其它节点

    (三)修改hadoop配置文件slaves,加入新节点的主机名

    (四)在新节点通过命令hadoop-daemon.shstart datanode和yarn-daemon.sh start nodemanager启动datanode和nodemanager进程

    (五)在新节点中通过命令start-balancer.sh均衡当前的HDFS块,在执行前可通过命令Hdfs dfsadmin -setBalancerBandwidth字节数 设置带宽

    7.2 Hadoop动态删除节点

    (一)在hadoop配置文件hdfs-site.xml中配置如下:

    <property>

    <name>dfs.hosts.exclude</name>

    <value>/home/hadoop/app/cdh/hadoop-2.6.0-cdh5.7.1/etc/hadoop/exclude</value>

    </property>

    (二)在配置文件exclude中添加需要删除的节点主机名

    (三)通过命令hdfsafsadmin -refreshNodes执行节点刷新操作

    (四)通过命令hdfsafsadmin -report可查看该节点状况

    7.3 HBase动态添加节点

    (一)在HBase的配置文件regionserver中添加新节点的主机名

    (二)在新节点通过命令hbase-daemon.shstart regionserver启动HRegionServer

    (三)进入hbaseshell,通过命令balance_switch true进行region平衡

    7.4 HBase动态删除节点

    (一)通过命令graceful_stop.sh主机名 停止需要删除的节点

    (二)在HBase的配置文件regionserver中移除删除节点的主机名



    展开全文
  • Android企业级实战-界面篇-1

    万次阅读 多人点赞 2021-06-14 19:00:08
    Android企业级实战-界面篇-1 计蒙创作不易,未入驻的其他平台搬运请按协议规则搬运。 文章目录文章目录前言(大佬请直接跳转至第三步)一、先看看实现的效果二、实现前准备(简单讲解以及辅助文件代码,以及取名...

    文章目录

    Android企业级实战-界面篇-1

    计蒙创作不易,未入驻的其他平台搬运请按协议规则搬运。


    前言(大佬请直接跳转至第三步)

    计蒙从上班再次回到学校生活后,认识的很多学校软件系朋友通过校招拿到了大厂Android开发岗位的offer,计蒙因为学习是专科起点,到本科后算法部分缺陷极大,仅拿到一家大厂offer,由于个人好不容易回到校园生活,不想太早再次回到上班的日子,于是继续准备升学,为了不将Android遗忘,还是偶尔写写代码,也就有了此文章。


    以下是本篇文章正文内容

    一、先看看实现的效果

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    二、实现前准备(简单讲解以及辅助文件代码,以及取名借鉴规范)

    1.莫大厂规范(为例)

    在这里插入图片描述

    2.dimens.xml文件内容(此案例可用)

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <dimen name="jimeng_dp_0">0.0dip</dimen>
        <dimen name="jimeng_dp_05">0.5dip</dimen>
        <dimen name="jimeng_dp_1">1.0dip</dimen>
        <dimen name="jimeng_dp_10">10.0dip</dimen>
        <dimen name="jimeng_dp_100">100.0dip</dimen>
        <dimen name="jimeng_dp_11">11.0dip</dimen>
        <dimen name="jimeng_dp_115">115.0dip</dimen>
        <dimen name="jimeng_dp_12">12.0dip</dimen>
        <dimen name="jimeng_dp_120">120.0dip</dimen>
        <dimen name="jimeng_dp_123">123.0dip</dimen>
        <dimen name="jimeng_dp_13">13.0dip</dimen>
        <dimen name="jimeng_dp_135">135.0dip</dimen>
        <dimen name="jimeng_dp_14">14.0dip</dimen>
        <dimen name="jimeng_dp_140">140.0dip</dimen>
        <dimen name="jimeng_dp_15">15.0dip</dimen>
        <dimen name="jimeng_dp_16">16.0dip</dimen>
        <dimen name="jimeng_dp_169">169.0dip</dimen>
        <dimen name="jimeng_dp_17">17.0dip</dimen>
        <dimen name="jimeng_dp_18">18.0dip</dimen>
        <dimen name="jimeng_dp_183">183.0dip</dimen>
        <dimen name="jimeng_dp_2">2.0dip</dimen>
        <dimen name="jimeng_dp_20">20.0dip</dimen>
        <dimen name="jimeng_dp_22">22.0dip</dimen>
        <dimen name="jimeng_dp_225">225.0dip</dimen>
        <dimen name="jimeng_dp_24">24.0dip</dimen>
        <dimen name="jimeng_dp_246">246.0dip</dimen>
        <dimen name="jimeng_dp_250">250.0dip</dimen>
        <dimen name="jimeng_dp_28">28.0dip</dimen>
        <dimen name="jimeng_dp_280">280.0dip</dimen>
        <dimen name="jimeng_dp_30">30.0dip</dimen>
        <dimen name="jimeng_dp_32">32.0dip</dimen>
        <dimen name="jimeng_dp_34">34.0dip</dimen>
        <dimen name="jimeng_dp_375">375.0dip</dimen>
        <dimen name="jimeng_dp_38">38.0dip</dimen>
        <dimen name="jimeng_dp_4">4.0dip</dimen>
        <dimen name="jimeng_dp_40">40.0dip</dimen>
        <dimen name="jimeng_dp_43">43.0dip</dimen>
        <dimen name="jimeng_dp_44">44.0dip</dimen>
        <dimen name="jimeng_dp_45">45.0dip</dimen>
        <dimen name="jimeng_dp_46">46.0dip</dimen>
        <dimen name="jimeng_dp_48">48.0dip</dimen>
        <dimen name="jimeng_dp_49">49.0dip</dimen>
        <dimen name="jimeng_dp_5">5.0dip</dimen>
        <dimen name="jimeng_dp_50">50.0dip</dimen>
        <dimen name="jimeng_dp_54">54.0dip</dimen>
        <dimen name="jimeng_dp_55">55.0dip</dimen>
        <dimen name="jimeng_dp_56">56.0dip</dimen>
        <dimen name="jimeng_dp_58">58.0dip</dimen>
        <dimen name="jimeng_dp_6">6.0dip</dimen>
        <dimen name="jimeng_dp_60">60.0dip</dimen>
        <dimen name="jimeng_dp_64">64.0dip</dimen>
        <dimen name="jimeng_dp_65">65.0dip</dimen>
        <dimen name="jimeng_dp_68">68.0dip</dimen>
        <dimen name="jimeng_dp_7">7.0dip</dimen>
        <dimen name="jimeng_dp_70">70.0dip</dimen>
        <dimen name="jimeng_dp_75">75.0dip</dimen>
        <dimen name="jimeng_dp_76">76.0dip</dimen>
        <dimen name="jimeng_dp_8">8.0dip</dimen>
        <dimen name="jimeng_dp_84">84.0dip</dimen>
        <dimen name="jimeng_dp_86">86.0dip</dimen>
        <dimen name="jimeng_dp_90">90.0dip</dimen>
        <dimen name="jimeng_px_1">1.0px</dimen>
        <dimen name="dp_10">10.0dip</dimen>
    </resources>
    

    3.ids.xml文件内容(此案例可用)

    <resources>
    <!--    第一个UI模块id-->
        <item type="id" name="like_icon" />
        <item type="id" name="user_profile_all_msg_layout" />
        <item type="id" name="ll_msg_layout1" />
        <item type="id" name="my_msg_like" />
        <item type="id" name="like_txt" />
        <item type="id" name="like_num" />
        <item type="id" name="my_msg_comment" />
        <item type="id" name="comment_txt" />
        <item type="id" name="comment_icon" />
        <item type="id" name="comment_num" />
        <item type="id" name="my_msg_chat" />
        <item type="id" name="chat_icon" />
        <item type="id" name="chat_txt" />
        <item type="id" name="chat_num" />
        <item type="id" name="my_msg_notification" />
        <item type="id" name="notification_icon" />
        <item type="id" name="notification_num" />
        <item type="id" name="notification_txt" />
        <item type="id" name="ll_msg_layout" />
        <item type="id" name="ll_my_history" />
        <item type="id" name="iv_foot_print_txt" />
        <item type="id" name="foot_print_txt" />
        <item type="id" name="ll_draft_box" />
        <item type="id" name="iv_draft_icon" />
        <item type="id" name="tv_draft_" />
        <item type="id" name="ll_question_box" />
        <item type="id" name="question_icon" />
        <item type="id" name="tv_question_box_count" />
        <item type="id" name="question_txt" />
        <item type="id" name="user_customer_layout" />
        <item type="id" name="feedback_icon" />
        <item type="id" name="qiyu_tip" />
        <item type="id" name="user_customer_title" />
        <item type="id" name="rl_view_stub" />
        <item type="id" name="rl_view_stub1" />
    
    </resources>
    

    4.colors.xml文件内容(此案例可用)

        <color name="jimeng_background_primary_light">#ffffffff</color>
        <color name="jimeng_white">@color/jimeng_background_primary_light</color>
        <color name="jimeng_text_primary_light">#ff2e2e2e</color>
        <color name="jimeng_black">@color/jimeng_text_primary_light</color>
        <color name="jimeng_red_light">#ffff6c93</color>
    

    5.strings.xml文件内容(此案例可用)

        <string name="str_they_like_me">收到的喜欢</string>
        <string name="str_comment">评论</string>
        <string name="str_chat">聊天</string>
        <string name="str_notification">通知</string>
        <string name="str_help_and_feedback">帮助与反馈</string>
        <string name="str_question_box">提问箱</string>
        <string name="str_drafts">草稿箱</string>
        <string name="str_footprint">足迹</string>
    

    三、实现

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@id/user_profile_all_msg_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/jimeng_dp_16"
        android:orientation="vertical">
    
        <LinearLayout
            android:id="@id/ll_msg_layout1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/jimeng_dp_16"
            android:layout_marginRight="@dimen/jimeng_dp_16"
            android:background="@color/jimeng_white"
            android:orientation="horizontal">
    
            <RelativeLayout
                android:id="@id/my_msg_like"
                android:layout_width="0.0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1.0"
                android:orientation="vertical">
    
                <TextView
                    android:id="@id/like_txt"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/like_icon"
                    android:layout_centerHorizontal="true"
                    android:text="@string/str_they_like_me"
                    android:textColor="@color/jimeng_black"
                    android:textSize="12.0dip" />
    
                <ImageView
                    android:id="@id/like_icon"
                    android:layout_width="44.0dip"
                    android:layout_height="44.0dip"
                    android:layout_alignParentTop="true"
                    android:layout_centerHorizontal="true"
                    android:scaleType="centerCrop"
                    android:src="@drawable/account_icon_messages_liked_light" />
    
                <TextView
                    android:id="@id/like_num"
                    android:layout_width="wrap_content"
                    android:layout_height="18.0dip"
                    android:layout_alignLeft="@id/like_icon"
                    android:layout_marginLeft="26.0dip"
                    android:background="@drawable/profile_notification_count_bg"
                    android:gravity="center"
                    android:paddingLeft="6.0dip"
                    android:paddingRight="6.0dip"
                    android:text="11"
                    android:textColor="@color/white"
                    android:textSize="10.0dip"
                    android:visibility="gone" />
            </RelativeLayout>
    
            <RelativeLayout
                android:id="@id/my_msg_comment"
                android:layout_width="0.0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1.0"
                android:orientation="vertical">
    
                <TextView
                    android:id="@id/comment_txt"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/comment_icon"
                    android:layout_centerHorizontal="true"
                    android:text="@string/str_comment"
                    android:textColor="@color/jimeng_black"
                    android:textSize="12.0dip" />
    
                <ImageView
                    android:id="@id/comment_icon"
                    android:layout_width="44.0dip"
                    android:layout_height="44.0dip"
                    android:layout_alignParentTop="true"
                    android:layout_centerHorizontal="true"
                    android:scaleType="centerCrop"
                    android:src="@drawable/account_icon_messages_commend_light" />
    
                <TextView
                    android:id="@id/comment_num"
                    android:layout_width="wrap_content"
                    android:layout_height="18.0dip"
                    android:layout_alignLeft="@id/comment_icon"
                    android:layout_marginLeft="26.0dip"
                    android:background="@drawable/profile_notification_count_bg"
                    android:gravity="center"
                    android:paddingLeft="6.0dip"
                    android:paddingRight="6.0dip"
                    android:text="999+"
                    android:textColor="@color/white"
                    android:textSize="10.0dip"
                    android:visibility="gone" />
            </RelativeLayout>
    
            <RelativeLayout
                android:id="@id/my_msg_chat"
                android:layout_width="0.0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1.0"
                android:orientation="vertical">
    
                <TextView
                    android:id="@id/chat_txt"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/chat_icon"
                    android:layout_centerHorizontal="true"
                    android:text="@string/str_chat"
                    android:textColor="@color/jimeng_black"
                    android:textSize="12.0dip" />
    
                <ImageView
                    android:id="@id/chat_icon"
                    android:layout_width="44.0dip"
                    android:layout_height="44.0dip"
                    android:layout_alignParentTop="true"
                    android:layout_centerHorizontal="true"
                    android:src="@drawable/account_icon_messages_chat_light" />
    
                <TextView
                    android:id="@id/chat_num"
                    android:layout_width="wrap_content"
                    android:layout_height="18.0dip"
                    android:layout_alignLeft="@id/chat_icon"
                    android:layout_marginLeft="26.0dip"
                    android:background="@drawable/profile_notification_count_bg"
                    android:gravity="center"
                    android:paddingLeft="6.0dip"
                    android:paddingRight="6.0dip"
                    android:text="999+"
                    android:textColor="@color/white"
                    android:textSize="10.0dip"
                    android:visibility="gone" />
            </RelativeLayout>
    
            <RelativeLayout
                android:id="@id/my_msg_notification"
                android:layout_width="0.0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1.0"
                android:orientation="vertical">
    
                <TextView
                    android:id="@id/notification_txt"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/notification_icon"
                    android:layout_centerHorizontal="true"
                    android:text="@string/str_notification"
                    android:textColor="@color/jimeng_black"
                    android:textSize="12.0dip" />
    
                <ImageView
                    android:id="@id/notification_icon"
                    android:layout_width="44.0dip"
                    android:layout_height="44.0dip"
                    android:layout_alignParentTop="true"
                    android:layout_centerHorizontal="true"
                    android:scaleType="centerCrop"
                    android:src="@drawable/account_icon_messages_notification_light" />
    
                <TextView
                    android:id="@id/notification_num"
                    android:layout_width="wrap_content"
                    android:layout_height="18.0dip"
                    android:layout_alignLeft="@id/notification_icon"
                    android:layout_marginLeft="26.0dip"
                    android:background="@drawable/profile_notification_count_bg"
                    android:gravity="center"
                    android:paddingLeft="6.0dip"
                    android:paddingRight="6.0dip"
                    android:text="999+"
                    android:textColor="@color/white"
                    android:textSize="10.0dip"
                    android:visibility="gone" />
            </RelativeLayout>
        </LinearLayout>
    
        <LinearLayout
            android:id="@id/ll_msg_layout"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/jimeng_dp_16"
            android:layout_marginTop="@dimen/jimeng_dp_10"
            android:layout_marginRight="@dimen/jimeng_dp_16"
            android:background="@color/jimeng_white"
            android:orientation="horizontal">
    
            <RelativeLayout
                android:id="@id/ll_my_history"
                android:layout_width="0.0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1.0"
                android:orientation="vertical">
    
                <TextView
                    android:id="@id/foot_print_txt"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/iv_foot_print_txt"
                    android:layout_centerHorizontal="true"
                    android:text="@string/str_footprint"
                    android:textColor="@color/jimeng_black"
                    android:textSize="12.0dip" />
    
                <ImageView
                    android:id="@id/iv_foot_print_txt"
                    android:layout_width="44.0dip"
                    android:layout_height="44.0dip"
                    android:layout_alignParentTop="true"
                    android:layout_centerHorizontal="true"
                    android:scaleType="centerCrop"
                    android:src="@drawable/account_icon_messages_footprint_light" />
            </RelativeLayout>
    
            <RelativeLayout
                android:id="@id/ll_draft_box"
                android:layout_width="0.0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1.0"
                android:orientation="vertical">
    
                <TextView
                    android:id="@id/tv_draft_"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/iv_draft_icon"
                    android:layout_centerHorizontal="true"
                    android:text="@string/str_drafts"
                    android:textColor="@color/jimeng_black"
                    android:textSize="12.0dip" />
    
                <ImageView
                    android:id="@id/iv_draft_icon"
                    android:layout_width="44.0dip"
                    android:layout_height="44.0dip"
                    android:layout_alignParentTop="true"
                    android:layout_centerHorizontal="true"
                    android:scaleType="centerCrop"
                    android:src="@drawable/account_icon_messages_drafts_light" />
            </RelativeLayout>
    
            <RelativeLayout
                android:id="@id/ll_question_box"
                android:layout_width="0.0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1.0"
                android:orientation="vertical">
    
                <TextView
                    android:id="@id/question_txt"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/question_icon"
                    android:layout_centerHorizontal="true"
                    android:text="@string/str_question_box"
                    android:textColor="@color/jimeng_black"
                    android:textSize="12.0dip" />
    
                <ImageView
                    android:id="@id/question_icon"
                    android:layout_width="44.0dip"
                    android:layout_height="44.0dip"
                    android:layout_alignParentTop="true"
                    android:layout_centerHorizontal="true"
                    android:src="@drawable/account_icon_messages_question_light" />
    
                <ImageView
                    android:id="@id/tv_question_box_count"
                    android:layout_width="8.0dip"
                    android:layout_height="8.0dip"
                    android:layout_alignLeft="@id/question_icon"
                    android:layout_marginLeft="33.0dip"
                    android:layout_marginTop="@dimen/jimeng_dp_4"
                    android:background="@drawable/common_icon_notification_small"
                    android:gravity="center"
                    android:paddingLeft="6.0dip"
                    android:paddingRight="6.0dip"
                    android:textSize="10.0dip"
                    android:visibility="gone" />
            </RelativeLayout>
    
            <RelativeLayout
                android:id="@id/user_customer_layout"
                android:layout_width="0.0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1.0"
                android:orientation="vertical">
    
                <TextView
                    android:id="@id/user_customer_title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/feedback_icon"
                    android:layout_centerHorizontal="true"
                    android:ellipsize="middle"
                    android:singleLine="true"
                    android:text="@string/str_help_and_feedback"
                    android:textColor="@color/jimeng_black"
                    android:textSize="12.0dip" />
    
                <ImageView
                    android:id="@id/feedback_icon"
                    android:layout_width="44.0dip"
                    android:layout_height="44.0dip"
                    android:layout_alignParentTop="true"
                    android:layout_centerHorizontal="true"
                    android:scaleType="centerCrop"
                    android:src="@drawable/account_icon_messages_help_light" />
    
                <ImageView
                    android:id="@id/qiyu_tip"
                    android:layout_width="8.0dip"
                    android:layout_height="8.0dip"
                    android:layout_alignLeft="@id/feedback_icon"
                    android:layout_marginLeft="33.0dip"
                    android:layout_marginTop="@dimen/jimeng_dp_4"
                    android:background="@drawable/common_icon_notification_small"
                    android:gravity="center"
                    android:paddingLeft="6.0dip"
                    android:paddingRight="6.0dip"
                    android:visibility="gone" />
            </RelativeLayout>
    
            <RelativeLayout
                android:id="@id/rl_view_stub"
                android:layout_width="0.0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1.0"
                android:orientation="vertical"
                android:visibility="gone" />
    
            <RelativeLayout
                android:id="@id/rl_view_stub1"
                android:layout_width="0.0dip"
                android:layout_height="wrap_content"
                android:layout_weight="1.0"
                android:orientation="vertical"
                android:visibility="gone" />
        </LinearLayout>
    </LinearLayout>
    

    四、注意

    第三步代码中,有8张UI图,一张小红点图,以及一个红框样式文件(用来在java代码实现提示效果,如不需要可删除)。

    五、使用

    <include layout="@layout/user_profile_all_msg_layout" />
    

    总结

    如需交流,可于公众号内联系计蒙(看到消息就回)。

    展开全文
  • 企业级API网关的设计

    千次阅读 2017-06-26 10:39:25
    转载本文需注明出处:微信公众号EAWorld,违者必究。 本文目录: 一、网关简介 二、网关的作用和价值 三、企业级API网关需要具备的条件 四、业界常用的API网关方案

    https://mp.weixin.qq.com/s/RuN5RfQfksQZRPACloqHEg?utm_source=tuicool&utm_medium=referral

    转载本文需注明出处:微信公众号EAWorld,违者必究。

    本文目录:

    一、网关简介

    二、网关的作用和价值

    三、企业级API网关需要具备的条件

    四、业界常用的API网关方案

    五、如何设计一个好的企业级API网关产品

    六、小结


    一、网关简介


    1.1  API网关背景介绍


    API Gateway(APIGW / API 网关),顾名思义,是出现在系统边界上的一个面向API的、串行集中式的强管控服务,这里的边界是企业IT系统的边界,主要起到隔离外部访问与内部系统的作用。在微服务概念的流行之前,API网关的实体就已经诞生了,例如银行、证券等领域常见的前置机系统,它也是解决访问认证、报文转换、访问统计等问题的。


    API网关的流行,源于近几年来,移动应用与企业间互联需求的兴起。移动应用、企业互联,使得后台服务支持的对象,从以前单一的Web应用,扩展到多种使用场景,且每种使用场景对后台服务的要求都不尽相同。这不仅增加了后台服务的响应量,还增加了后台服务的复杂性。随着微服务架构概念的提出,API网关成为了微服务架构的一个标配组件。


    1.2  网关的几种使用场景


    我司王延炯博士的文章《谈API网关的背景、架构以及落地方案》中,提到了网关的几种使用场景:



    1、面向Web App的网关

    这类场景,在物理形态上类似前后端分离,此时的Web App已经不是全功能的Web App,而是根据场景定制、场景化的App。


    2、面向MobileApp的网关

    这类场景,移动App是后端Service的使用者,此时的APIGW还需要承担一部分MDM(此处是指移动设备管理,不是主数据管理)的职能。


    3、面向PartnerOpenAPI的网关

    这类场景,主要为了满足业务形态对外开放,与企业外部合作伙伴建立生态圈,此时的API GW需要增加配额、流控、令牌等一系列安全管控功能。


    4、面向PartnerExternalAPI的网关

    这类场景,主要是为了满足企业自身业务的需要,实现对企业自有业务的映射。一个典型的例子就是使用「合作方账号登录」、「使用第三方支付平台支付」等等。此时的APIGW就需要在边界上,为企业内部Service 统一调用外部的API做统一的认证、授权、以及访问控制。


    5、面向IoTSmartDevice的网关

    这类场景主要在传统企业,尤其是工业企业,传感器、物理设备从工业控制协议向IP转换,导致物理链路上会存在一部分公网链路。此时的API GW所需要满足的「内外兼修」的双向数据流,设备一般通过一个「客户侧」的集中网关在和企业的接入网关进行通信。


    在我们讲的微服务架构下的API网关,一般指的是前两种使用场景。即,主要是把企业内部的API能力,暴露给其他应用或合作伙伴使用。


    二、网关的作用和价值


    网关层作为客户端与服务端的一层挡板,主要起到了三大类作用:


    第一类作用是隔离作用,作为企业系统边界,隔离外网系统与内网系统。

    第二类作用是解耦作用,通过解耦,使得微服务系统的各方能够独立、自由、高效、灵活地调整,而不用担心给其他方面带来影响。

    第三类作用是脚手架作用,提供了一个地点,方便通过扩展机制对请求进行一系列加工和处理。


    2.1  内外的隔离


    企业为了保护内部系统的安全性,内网与外网都是隔离的,企业的服务应用都是运行在内网环境中,为了安全的考量,一般都不允许外部直接访问。API网关部署在防火墙外面,起到一层挡板作用,内部系统只接受API网关转发过来的请求。网关通过白名单或校验规则,对访问进行了初步的过滤。相比防火墙,这种软件实现的过滤规则,更加动态灵活。


    2.2  多方的解耦


    在微服务架构下,整个环境包括服务的提供者、服务的消费者、服务运维人员、安全管理人员等,每个角色的职责和述求都不同。例如:服务消费者已经需要提出一些新的服务需求,以快速应对业务变化;服务提供者,作为业务服务的沉淀方,希望保持服务的通用性与稳定性,很难应对快速的变化。有了API网关这一层,可以很好的解耦各方的相互依赖关系,让各方更加专注自己的目标。


    1、解耦功能与非功能


    企业在把服务提供给外部访问时,除了实现业务逻辑功能外,还面临许多非功能性的要求。例如:需要防范黑客攻击,需要应对突发的访问量、需要确认用户的权限,需要对访问进行监控等。这些非功能逻辑,不能与业务逻辑的开发混在一起,需要有专业的人员甚至专业的团队来处理。


    2、解耦客户端与服务提供者


    客户端与服务提供者分属于不同的团队,工作性质要求也不相同。对于服务提供者来说,他主要的职责是对业务进行抽象,提供可复用的业务功能,他们需要对业务模型进行深入的思考和沉淀,不能轻易为了响应外部的需求而破坏业务模型的稳定性。而业务的快速变化,又要求企业快速提供接口来满足客户端需求。这就需要一个中间层,来对服务层的接口进行封装,以及时响应客户端的需求。


    通过解耦,服务层可以使用统一的接口、协议和报文格式来暴露服务,而不必考虑客户端的多种形态。


    3、网关层是否需要实现服务的编排?


    在介绍API网关的一些文章中,提到了网关层的服务编排能力。从解耦的角度出发,服务的编排不适合在网关层进行。对服务的编排,其实是提供了一种业务能力,如果把服务的编排放在了网关层,实际上是把一部分业务能力放在了网关层,这样一来,服务层、网关层都有一些业务能力,造成团队职责的不清,也不利于业务能力的沉淀。


    2.3  插件的脚手架


    网关层除了请求的路由、转发外,还需要负责安全、鉴权、限流、监控等。这些功能的实现方式,往往随着业务的变化不断调整。例如权限控制方面,早期可能只需要简单的用户+密码方式,后续用户量大了后,可能会使用高性能的第三方解决方案。又例如,针对不同的监控方案,需要记录不同的日志文件。


    所以,这些能力不能一开始就固化在网关平台上,而应该是一种可配置的方式,便于修改和替换。这就要求网关层提供一套机制,可以很好地支持这种动态扩展。


    2.4  带来的好处


    这里总结下网关的价值:


    • 网关层对外部和内部进行了隔离,保障了后台服务的安全性。

    • 对外访问控制由网络层面转换成了运维层面,减少变更的流程和错误成本

    • 减少客户端与服务的耦合,服务可以独立发展。通过网关层来做映射。

    • 通过网关层聚合,减少外部访问的频次,提升访问效率。

    • 节约后端服务开发成本,减少上线风险。

    • 为服务熔断,灰度发布,线上测试提供简单方案。

    • 便于扩展。


    三、企业级API网关需要具备的条件


    3.1  微服务架构下,企业API网关的定位


    API网关作为对外提供服务的入口,就像企业服务的大门。一方面,要有足够的能力,应对大量的对外访问,另一方面,还要给对内的服务提供一定的安全保障。


    除此之外,企业提供的API服务多种多样,API网关要能够对这些API的全生命周期进行便捷的管理,例如服务发布、调整、下架、计费、监控等。


    3.2  企业环境下,API网关需要考虑哪些要素


    1、安全性问题


    企业在把服务暴露给外部使用时,首先要确保服务使用的安全,防止外部的恶意访问对公司业务的影响,特别是涉及交易方面的服务,更是要全面考虑安全性。为确保安全,需要考虑在通讯链路的建立、通讯数据的加密、数据的完整性、不可抵赖性等方面。


    2、性能问题


    作为企业API的入口,所有的请求都会经过API网关进行转发,可想而知,对API网关的访问压力是巨大的,有的网站甚至达到每分钟上千万的访问量。特别是在一些互联网企业,海量的移动终端每时每刻都需要与后端的服务进行交互,如果不能保证网关的高性能,企业在网关层需要投入大量的设备和成本。曾在一家互联网公司发生过,由于网关性能问题,网关的机器数量,需要与后台服务器的数量保持同步增长。这种情况显然是企业服务忍受的。


    3、高可用问题


    API网关作为逻辑上的单点,一旦发生问题,将造成企业服务的不可用,对企业来说可能造成的致命的影响。计算短时间的不可用,也会给企业带来直接的经济损失。所以,如何保证API网关的7*24小时的稳定运行,网关的自动伸缩、API的热更新等问题,都是企业级的网关需要考虑的。


    4、扩展性问题


    前面说到,企业网关提供了一个脚手架,一些非功能性的问题,例如日志、安全、负载均衡策略、鉴权等。这些插件会随着企业业务规模等的变化进行不断的强化与调整。这就需要网关层提供这样一种机制,使得可以灵活地进行这些调整和变化,而不用频繁对网关层进行改动,确保网关层的稳定性。


    5、API高效运维的问题


    API在上线、发布过程中,都需要涉及到网关层的配合,例如,需要网关层知道API发布的地址,API的接口形式、报文格式,也需要网关层对后台API进行封装。在API调整后,需要作出相应的修改。所以,API网关设计时,需要明确网关层与服务层的职责切分与协作模式,使得API的管理、发布更加高效。


    6、API全生命周期管理的问题


    API服务的全生命周期,包括服务的开发、测试、上线发布;服务使用的申请、开通;服务分类分级别的管理、服务使用情况的监控、计费等等。


    一个企业可能会暴露成百上千个API,日常也会经常进行API的发布、升级、改造、下架等操作。对不同的服务,不同的访问者,需要提供不同的服务访问策略。有的商业API公司,还需要对API的使用进行付费。所以,与API网关配套的,需要一套完善的自助系统,提供给服务的提供者、管理者、使用者,来对服务的发布、使用、和运营。


    四、业界常用的API网关方案


    业界API网关解决方案有很多,包括商业的、开源的。例如Tyk、Kong、api-umbrella、apiaxle、Netflix zuul、WSO2 API Manager、clydeio等。下面介绍三种常见的 API 网关方案。


    4.1  Nginx+ Lua


    Nginx是由IgorSysoev为俄罗斯访问量第二的Rambler.ru站点开发的,一个高性能的HTTP和反向代理服务器。2012年,Nginx荣获年度云计算开发奖,并成长为世界第二大Web服务器。全世界流量最高的前1000名网站中,超过25%都使用Nginx来处理海量的互联网请求。


    Nginx基本功能:

    • 静态web资源服务器,能够缓存打开的文件描述符

    • 支持http/imap/pop3/smtp的反向代理;支持缓存、负载均衡

    • 支持fastcgi(fpm)

    • 模块化,非DSO机制,支持过滤器zip压缩,SSI以及图像大小调整

    • 支持SSL


    Nginx通过插件的扩展功能:

    • 基于名称和IP的虚拟主机

    • 支持keepalive的保持机制

    • 支持平滑升级

    • 定制访问日志,支持使用日志缓存区提高日志存储性能

    • 支持url rewrite

    • 支持路径别名(root或alias指定)

    • 支持基于IP以及用户的访问控制

    • 支持传输速率限制,并发限制


    Nginx在性能和高可用性上的表现:

    Nginx性能极高,Nginx先天的事件驱动型设计、全异步的网络I/O处理机制、极少的进程间切换以及许多优化设计,都使得Nginx天生善于处理高并发压力下的互联网请求。Nginx的稳定性也在各大网站得到验证。官方提供的常用模块都非常稳定,每个worker进程相对独立,master进程在1个worker进程出错时可以快速“拉起”新的worker子进程提供服务。支持热部署,可以不停机更新配置文件、更新日志文件、更新服务器程序版本。


    Nginx的扩展性:

    Nginx的设计极具扩展性,它完全是由多个不同功能、不同层次、不同类型且耦合度极低的模块组成。因此,当对某一个模块修复Bug或进行升级时,可以专注于模块自身,无须在意其他。    


    Nginx的易用性:

    Nginx使用最自由的BSD许可协议,允许用户在自己的项目中直接使用或修改Nginx源码,有大量的插件可以利用。但是,Nginx模块需要用C开发,而且必须符合一系列复杂的规则。虽然通过第三方模块,可以支持Nginx与Perl、Lua等脚本语言集成工作,但对使用者的要求还是很高。


    Nginx可以说是一款能够工业化API网关,在国内的很多互联网公司,例如阿里、新浪等都得到很好的应用。


    4.2  SpringCloud Zuul


    Zuul Netflix公司开源的一个API网关组件。提供了认证&鉴权、限流、动态路由,监控,弹性,安全、负载均衡、协助单点压测、静态响应等边缘服务的框架。


    Zuul的基本功能:

    • 验证与安全保障: 识别面向各类资源的验证要求并拒绝那些与要求不符的请求。

    • 审查与监控: 在边缘位置追踪有意义数据及统计结果,从而为我们带来准确的生产状态结论。

    • 动态路由: 以动态方式根据需要将请求路由至不同后端集群处。

    • 压力测试: 逐渐增加指向集群的负载流量,从而计算性能水平。

    • 负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。

    • 静态响应处理: 在边缘位置直接建立部分响应,从而避免其流入内部集群。

    • Netflix公司还利用Zuul的功能通过金丝雀版本实现精确路由与压力测试。

    • 虽然提供的功能还算丰富,但都比较弱,很难满足高要求的场景。


    Zuul在性能和高可用性上的表现:

    Zuul处理每个请求的方式是针对每个请求是用一个线程来处理。通常情况下,为了提高性能,所有请求会被放到处理队列中,从线程池中选取空闲线程来处理该请求。2016年底,Netflix将它们的网关服务Zuul进行了升级,全新的Zuul 2将HTTP请求的处理方式从同步变成了异步,以提升其处理性能。除了Netflix公司,目前Zuul在企业中用的还比较少,性能和稳定性方面还有待进一步观察。


    Zuul的扩展性:

    从Zuul的架构图上可以看出,Zuul更像是一个过滤器框架,其自身的路由、日志、反向代理、ddos预防等功能都是通过过滤器实现的。提供了PRE、ROUTING、POST和ERROR四个扩展点,可以很容易的添加自定义的过滤器。  


    Zuul的易用性:

    Zuul的搭建非常简便,使用和配置也很简单。Zuul的开源社区比较活跃,一直在更新状态,但版本不算太稳定,在使用的过程中,还有一些坑要踩。例如重定向问题、异常处理问题,还没有解决的很好,需要自己重写一些filter。

    如果从通盘考虑, 这种方案不是最佳方案。但如果自己的团队对整体技术设施把控有限,且团队规模不大,没有专门的网关开发人员的情况下,Zuul是一款快速上手的最佳方案。


    4.3  MashapeKong


    Kong是Mashape提供的一款API管理软件,它本身是基于Ngnix+lua的,但比nginx提供了更简单的配置方式,数据采用了 ApacheCassandra/PostgreSQL存储,并且提供了一些优秀的插件,比如验证,日志,调用频次限制等。


    Kong的一个非常诱人的地方就是提供了大量的插件来扩展应用,通过设置不同的插件可以为服务提供各种增强的功能。Kong默认插件插件包括:


    • 身份认证:Kong提供了Basic Authentication、Key authentication、OAuth2.0authentication、HMAC authentication、JWT、LDAP authentication认证实现。

    • 安全:ACL(访问控制)、CORS(跨域资源共享)、动态SSL、IP限制、爬虫检测实现。

    • 流量控制:请求限流(基于请求计数限流)、上游响应限流(根据upstream响应计数限流)、请求大小限制。限流支持本地、Redis和集群限流模式。

    • 分析监控:Galileo(记录请求和响应数据,实现API分析)、Datadog(记录API Metric如请求次数、请求大小、响应状态和延迟,可视化API Metric)、Runscope(记录请求和响应数据,实现API性能测试和监控)。

    • 转换:请求转换、响应转换


    Kong本身也是基于Nginx的,所以在性能和稳定性上都没有问题。Kong作为一款商业软件,在Nginx上做了很扩展工作,而且还有很多付费的商业插件。Kong本身也有付费的企业版,其中包括技术支持、使用培训服务以及API 分析插件。

     


    从对上面三种方案的比较中可以看到,Spring Cloud Zuul非常适合创业初期的团队,快速搭建一个“基本可用”的API网关。Nginx适合有较强研发团队,自主开发企业自己的API网关。Kong适合于没有自身研发团队,但需要拥有企业级API网关能力的公司。


    五、如何设计一个

    好的企业级API网关产品


    5.1  功能上的考量


    API 生命周期管理功能:

    • 覆盖 API 的定义、测试、发布的整个生命周期管理,便捷的日常管理、版本管理,支持热升级和快速回滚。


    开发和使用支持功能:

    • 提供页面调试工具,自动生成 API 文档和 SDK,大大降低人力成本。


    安全防护功能:

    • API 请求到达网关需要经过严格的身份认证、权限认证,才能到达后端服务。支持算法签名,支持 SSL 加密。


    流量控制功能:

    • 可控制单位时间内 API 允许被调用次数。用来保护企业的后端服务,实现业务分级和用户分级。

    • 支持对 API 流控,您可以根据 API 的重要程度来配置不同流控,从而保障重要业务的稳定运行;

    • 支持用户、应用和例外流控,您可以根据用户的重要性来配置不同流控,从而可以保证大用户的权益;

    • 流控粒度:分钟、小时、天。


    请求管理功能:

    • 可根据配置进行参数类型、参数值(范围、枚举、正则、Json Schema)的校验,减少后端对非法请求、无效请求的资源消耗和处理成本。

    • 可以在 API 网关定义参数映射规则,网关通过映射规则将后端服务通过映射翻译成任何形式,以满足不同用户的不同需求,从而避免功能重复开发。


    监控告警功能:

    • 提供实时、可视化的 API 监控,包括:调用量、调用方式、响应时间、错误率,让您能够清楚的了解API 的运行状况和用户的行为习惯。

    • 支持自定义报警规则,来针对异常情况进行报警,降低故障处理时间。

    • 提供可订阅的数据分析报表和智能分析。


    API交易功能:

    • 提供API交易市场,计量计费、Quota 控制、运营售卖等需求。


    5.2 网关的高性能设计


    传统的基于线程的并发模型(Thread-based concurrency),为每一个请求分配一个线程或进程。这种模型编程简单,可以将处理一个完整请求的代码编写在一个代码路径中。这种模型的弊端是,随着线程(进程)数的上升,操作系统在这些线程(进程)之间的频繁切换,将急剧降低系统的性能。

    另一种更高效的并发模型是事件驱动的并发模型(Event-driven concurrency)。在这种模型中,每一个请求在系统被表示成一个有限状态机(FSM)。每一个FSM的状态表示请求的一系列的操作。服务器由一组线程/进程(一般是 one per CPU)循环处理各种来自队列的事件(Event)。

    这种模型要求每一个状态的操作是短暂的并且是非阻塞的,所以 Event-driven concurrency模型一般都用了非阻塞的I/O接口(NIO)。


    普元的产品中,为增加系统的吞吐量,是采用了基于事件的并发模型的SEDA的架构。SEDA架构的核心思想是:把一个请求处理过程分成几个Stage,每个Stage可由不同的handle进行处理,不同资源消耗的Stage使用不同数量的线程来处理,handle之间采用异步通讯的模式。



    详细的SEDA架构介绍可以参见普元同事的一篇文章《选择SEDA作为云平台的基础消息处理架构》


    5.3  网关的高可用设计


    保证高可用一般做法是解决单点故障给系统整体带来的影响。普元在产品设计时,为确保高可用,考虑了如下几点要素:


    1、无状态设计原则:网关层为保证高可以,易于伸缩,快速启动,需要设计成无状态的。用户的状态数据我们通常使用session对象来封装,网关层要设计成无状态的,也就是说,不能由网关来负责session的维护。那由谁来维护session相关的信息呢?我们是采用cookie+session服务器的方式;



    1. 用户在登录页完成登录操作后,服务器会生成一个登录session信息,保存起来,设置个失效时间,并设置到用户的cookie里

    2. 用户后续的每次请求里会带着这个cookie信息,服务端会对这个cookie信息进行校验,通过了就认为是合法用户,执行请求操作


    2、优雅下线原则:当网关发现某一个节点不可用时(例如请求响应时间超过阀值),不是直接断开与此节点的连接,而是先把此节点标记为不可用(后续不在发送请求到此节点),但还会留出一段时间让之前的请求都响应完毕。


    3、Slow start特性:当网关监听到有一台新的服务注册上来时,考虑到有些服务启动后,刚开始会有许多初始化的工作,此时服务对请求的响应速度是比较慢的。如果一开始就给这台服务分配太多的压力,有可能导致服务瞬间被压垮。为了避免这种情况,网关层需要考虑支持SlowStart特性。即,经过一段时间,逐渐把压力增加到预设的值。


    5.4  网关的扩展性设计


    网关的扩展性设计时,需要考虑下面几点:


    1. 在哪些地点进行拦截处理

    2. 拦截器的处理顺序

    3. 如何在拦截器间传递数据

    4. 支持在线关闭或启动一个拦截器


    在哪些地点进行拦截处理

    我们知道,网关对请求的处理,可以分为三个阶段:接受请求、路由并转发请求、接受服务的返回数据并返回给请求者,除此之外,还有一种情况是处理错误。所以我们也可以在这四个地方添加扩展点。


    • 接受到请求后

    • 定位到一个服务,并准备转发之前

    • 接受到服务的返回数据,返回给客户端之前

    • 当服务调用失败后


    拦截器的处理顺序

    拦截器的处理顺序,可以分为两大类:一类为网关平台自带的拦截器,例如安全校验、日志记录等;一类为网关层逻辑开发的,例如格式转换等。一般来说,网关先执行网关平台自带的拦截器,再执行为了业务逻辑编写的拦截器。当然,网关也需要提供一种机制,可以较容易地调整拦截器的执行顺序。最简单的一种方法,就是给每个拦截器定义一个优先级,网关按优先级顺序依次调用各拦截器。


    如何在拦截器间传递数据

    对网关层来说,它接收和处理的数据都是Request对象,网关层在接收到请求后,把请求封装为Request对象,为了让后续的filter能够获得这个对象,可以考虑把Request对象保存在线程变量中。


    支持在线关闭或启用一个拦截器

    有些拦截器,例如一些调试日志的拦截器,通常情况下都是关闭的,只有在出现问题的时候才需要打开。为了保证网关的高可用,网关层必须具备在线启用或关闭拦截器的能力。一般,网关需要提供restful接口方式,来关闭和启用一个拦截器。类似这样的命令:PUT/apigateway/v1/filters/filterName?enable=value


    5.5  API管理与动态发布设计


    对服务管理来说,分为前端服务管理与后端服务管理。前端服务指的是网关层暴露给客户端使用的服务API,后端服务指的是服务层提供的业务服务API。一个服务暴露给客户端使用,除了网关层和服务层提供服务的代码外,还需要配置前端服务与后端服务的映射关系。


    API的描述

    要对API进行管理,首先要对API进行描述。我们常见的接口描述语言有yaml、json、xml、PB等,这几种语言各有优劣。普元选择的对API契约的描述方式,是参考swagger spec规范,使用yaml语言来描述。当然,swagger的描述是针对restful接口的,我们可以针对自己接口定义的需要,自定义自己的描述属性。例如,普元在对微服务描述的时候,扩展了x-primeton-service、x-primeton-operation等属性来对服务进行描述。例如:



    有了API接口契约,除了用来描述服务接口外,还可以:


    1. 使用契约,自动生成服务的API文档。

    2. 使用契约,自动生成客户端的调用代码。

    3. 使用契约,生成服务接口的测试框架代码。


    前后端服务映射

    网关层API调用服务层API,有多种方式。例如,可以由按照服务层API的服务契约,生成一段客户端代码,发布给网关层使用。这种方式的弊端是,网关层代码依赖于服务层代码,服务层频繁修改和调整接口时,导致网关层的代码很难维护。

    可以通过配置前后端服务映射的方式,解耦网关层对服务层的依赖。当服务层的API(例如服务名、参数名等)发生变化时,只需调整映射关系,无需对网关层的代码进行调整。网关层按照映射,自动装配服务层API所需要的数据格式。这样,网关层团队与服务层团队可以相互不受干扰地开发各自的服务。

    映射的设置,包括服务URL的映射与参数的映射。有了前面提供的服务契约描述,可以可视化的配置这种映射关系。


    API上架

    前后端的服务发布后,并配置了映射关系后,就可以把服务暴露给外部使用了。在上架过程中,还需要设置访问权限、流量控制等信息。这一块,每个企业的业务要求都不一样,就不做过多介绍了。


    六、总结


    API网关作为企业能力开放的一个门户,除了具备基本的请求转发、协议转换、路由等功能,以及高性能和高稳定性外,还需具备良好的扩展性,已便于网关能力的不断增强。在网关实施过程中,要规划好网关层与服务层的交互方式,尽量使得网关层与服务层解耦,便于各个团队工作的独立性。另外,在API的管理上,需要提供API全生命周期的发布、配置、鉴权、流控、监控等配套的管理功能。这样,才能让API网关真正在企业中运转起来。


    展开全文
  • itunes保留appstore的版本,亲测可用

    万次阅读 2017-11-24 14:59:39
    IT之家10月9日消息 在最新的iTunes 12.7版本当中,苹果将App Store从iTunes当中完全删除,用户只能够通过手机上的App Store下载应用,这对于iOS11用户来说是一个友好的设定,这些用户无法再通过iTunes电脑版下载...

    IT之家10月9日消息 在最新的iTunes 12.7版本当中,苹果将App Store从iTunes当中完全删除,用户只能够通过手机上的App Store下载应用,这对于iOS11用户来说是一个不友好的设定,这些用户无法再通过iTunes电脑版下载iOS软件。

    对于如此激进的设定,显然不能够让全部的用户满意,数码博主@CDSQ 表示,最新的iTunes 12.7.0.166去掉了应用商店,但由于企业级用户需要,就额外发布的一个版本为12.6.3.6版的iTunes商店,该版本iTunes驱动库和支持库和最新的12.7版本相同,也就是变相让iOS11用户也能用iTunes安装软件。

    使用过iTunes的用户可能了解,如果在Windows端对iTunes进行版本正常降级可能会出现启动报错的问题,可以通过按住shift运行来创建新库或者删除“老”库就能解决这个问题(位于音乐文件夹下)。

    最新的12.7已经不再内置App Store,因此12.6.3.6版iTunes可能是最后一版支持iOS11且能通过iTunes下载软件的版本,且用且珍惜。


    下载地址

    Mac版点击下载

    Windows x86版点此下载

    Windows x64版点此下载

    展开全文
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-POJHJ3Tu-1570768849985)...Nepxion Discovery【探索】微服务企业级解决方案 Nepxion Discovery【探索】使用指南,基于Spring C...
  • “高可用性”(High Availability)通常来描述一个系统经过专门的设计,从而减少停工时间,而保持其服务的高度可用性。所以当我们一说到高可用,我们满脑子都是以负载均衡为主心骨搭建的拓扑图,以他为中心,从单...
  • 本文追溯了推送技术的发展历史,剖析了其核心原理,并对推送服务的关键技术进行深入剖析,围绕消息推送时产生的服务稳定性,消息丢失、延迟,接入复杂性,统计缺失等问题,提供了一整套平台的高可用消息推送解决...
  • 主题 开源 ...本文根据冯磊和赵星宇在“高可用架构”微信群所做的HttpDNS智能缓存库原理整理而成,转发请注
  • 企业中MySQL的高可用架构 MySQL数据库作为最流行的开源数据库产品,拥有许多成熟的高可用架构方案,其方案的可用性覆盖率为90%~99.999%,能够适用于对可用性级别的多种不同的需求。其主要是利用复制技术,多个不同...
  • amp;mid=209805123&amp;idx=1&amp;sn=ced8d67c3e2cc3ca38ef722949fa21f8&amp;3rd=MzA3MDU4NTYzMw==&...scene=6#rd主题 开源本文根据冯磊和赵星宇在“高可用架构”微信群所做的HttpDNS智能缓存库原...
  • 打开App显示文件已损坏,打开,您应该将它移到废纸篓,怎么办? 在隐私里面打开任意来源。 安全性与隐私里面无任何来源,怎么办? 请在终端中使用spctl命令:【master前面为两短-】 sudo spctl --master-disable...
  • 企业级集群架构体系实战(一)

    千次阅读 2017-08-23 22:08:56
    企业级集群架构体系实战(一)企业级集群架构体系实战一 1试验拓扑图 总体层次划分拓扑简图 2试验准备 3前端接入层调度器部署及高可用配置 node1node2 4缓存层部署及动静分离配置 node3node4 5业务层动态资源服务器...
  • 建设企业级SOA大厦

    千次阅读 2006-10-09 14:00:00
    构建企业级SOA(Enterprise service-oriented architecture, enterprise SOA)已经被提出来相当长一段时间了。究竟如何构建企业级SOA,众说纷纭。九月中旬在拉斯维加斯举行的SAP 2006年技术大会上(SAP TechEd 06)...
  • 严正声明: 1、相关破解技术仅限于技术研究使用,不得用于非法目的,...上一篇文章《因一纸设计稿,我把竞品APP扒得裤衩剩(上)》是一篇比较简单的: jsw => 技师文,呸, jsw => 记述文,呸呸, jsw =&g...
  • 本文所指的”合体”是从技术层面将Nutanix超融合基础架构和Harbor开源镜像仓库基于企业级需求进行的一次部署实践,旨在开源热潮中抛砖引玉似的分享一些新的尝试。 企业级 标题中提到的企业级这个词,并非...
  • 你也许成了独角兽,至少可以努力不要成为“独角尸”/“普通尸”。
  • 在IOS14更新完了之后我们公司app 出现了无法安装的问题, 同一个plist文件,13能,安装,14就提示无法安装,明天就开始推ios14了,所以就显得很急,下面记录下我们的解决方案: 我们没有是用apple store方式下载,我们用的...
  • IOS 企业级苹果开发者账号申请流程

    万次阅读 2016-07-29 10:14:15
    今天在公司的技术交流群里交流苹果企业级账号的申请,受大家鼓励,将几个月前申请流程整理了一下,现在想来申请苹果账号可怕,只是申请的流程信息过于琐碎。 由于笔者刚踩完坑,与苹果客服交流了一个多月,搜索...
  • 企业级 Web 网站安全解决方案揭秘

    千次阅读 2017-08-04 19:59:48
    在 3 月 10 日举办的阿里云网站热点研讨会上,阿里云资深安全业务架构师蕴藉就网站 Web 应用的安全性及业务可用性进行了一系列细致的讲解和介绍,接下来我们就来共同了解一下他分享的内容。 以下内容根据现场分享...
  • 企业级RAC+DG架构部署

    千次阅读 2017-05-26 14:15:24
    中文译为“实时应用集群”,是ORACLE甲骨文公司提供的在低成本服务器上构建高可用性数据库系统的解决方案,部署自由,无需购买额外部件,就可以实现多节点的负载均衡和故障转移功能,满足7*24业务间断的需求,而且...
  • 何为Web App,何为Hybird App

    千次阅读 2016-07-15 16:20:15
    何为Web App,何为Hybird App 这些概念听起来很火,当下也很流行,真正理解起来却并非易事。如果让我来全面的解释Web App和Hybird App,我觉得还有些困难。
  • Hybrid App 开发快速指南

    万次阅读 多人点赞 2018-08-14 00:42:57
    结合以上特性,混合应用开发平台实际上已经将 Hybrid App 开发完全变成了前端开发者“一个人的事”,普通原生需求都内置了,扩展原生需求可以借助插件生态实现,前端转场流畅可以用原生效果代替,甚至还提供 App ...
  • 据介绍,AppHouse为国内首家免费企业级私有镜像仓库,以安全可靠简单易用为导向,为企业容器运行平台提供了一种集镜像管理、镜像安全、镜像高可用、镜像高速访问为一体的企业级镜像仓库管理方案。
  • 基于Docker和Kubernetes的企业级DevOps实践训练营 课程准备 离线镜像包 百度:https://pan.baidu.com/s/1N1AYGCYftYGn6L0QPMWIMw 提取码:ev2h 天翼云:https://cloud.189.cn/t/ENjUbmRR7FNz CentOS7.4版本以上...
  • 企业级Docker镜像仓库的管理和运维

    千次阅读 2016-10-20 23:20:18
    作者介绍:张海宁,VMware中国研发中心云原生应用首席架构师,Harbor企业级容器Registry开源项目负责人,Cloud Foundry中国社区最早的技术布道师之一。目前着重关注云原生应用的研发工作,内容包括Container、PaaS、...
  • 之前简单的介绍了Docker Registry的使用,但是真正的...Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,通过添加一些企业必须的功能特性,例如安全、标识和管理等,扩展了开源Docker Distribution。...
  • DR负载均衡群集部署)企业级调度器LVS(Linux Virtual Server)集群和分布式1.1 集群 Cluster1.2 分布式系统1.3 集群和分布式1.4 集群设计原则1.5 集群设计实现1.5.1 基础设施层面1.5.2 业务层面1.6 LB Cluster 负载...
  • #2242 数据量大时导出能自动分批 #2243 部门表太大导致的问题 #2204 请求url里面带分号,绕过token校验 #2256 字典【是否启用】按钮会错误的保存状态 #2311 微服务部署下代码生成失效,单体模式下代码生成可用 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 29,857
精华内容 11,942
关键字:

企业级app不可用