当前位置: 首页 > news >正文

简述网站建设基本流程如何搭建个人博客

简述网站建设基本流程,如何搭建个人博客,顺德网站建设哪家好,电商网站开发流程list概述 ZooKeeper的应用场景依赖于ZNode节点特性和Watch监听机制。 应用场景 数据发布/订阅 常用于实现配置中心#xff0c;类似的有nacos。数据发布/订阅的一个常见的场景是配置中心#xff0c;发布者把数据发布到ZooKeeper的一个或一系列的节点上#xff0c;供订阅者进行…概述 ZooKeeper的应用场景依赖于ZNode节点特性和Watch监听机制。 应用场景 数据发布/订阅 常用于实现配置中心类似的有nacos。数据发布/订阅的一个常见的场景是配置中心发布者把数据发布到ZooKeeper的一个或一系列的节点上供订阅者进行数据订阅达到动态获取数据的目的。配置信息一般有几个特点: 数据量小的KV数据内容在运行时会发生动态变化集群机器共享配置一致 ZooKeeper采用的是推拉结合的方式。 推: 服务端会推给注册了监控节点的客户端Watcher事件通知不会将值数据推给客户端拉: 客户端获得通知后然后主动到服务端拉取最新的数据 负载均衡 同一个服务下关联多个服务节点。在Zookeeper中记录每台服务器的访问数让访问数最少的服务器去处理最新的客户端请求。 命名服务 命名服务是为系统中的资源提供标识能力。ZooKeeper的命名服务主要是利用ZooKeeper节点的树形分层结构和子节点的顺序维护能力来为分布式系统中的资源命名。哪些应用场景需要用到分布式命名服务呢典型的有 分布式API目录分布式节点命名分布式ID生成器 分布式API目录注册中心 为分布式系统中各种API接口服务的名称、链接地址提供类似JNDIJava命名和目录接口中的文件系统的功能。借助于ZooKeeper的树形分层结构就能提供分布式的API调用功能。著名的Dubbo分布式框架就是应用了ZooKeeper的分布式的JNDI功能。在Dubbo中使用ZooKeeper维护的全局服务接口API的地址列表。大致的思路为 服务提供者Service Provider在启动的时候向ZooKeeper上的指定节点/dubbo/${serviceName}/providers写入自己的API地址这个操作就相当于服务的公开。服务消费者Consumer启动的时候订阅节点/dubbo/{serviceName}/providers下的服务提供者的URL地址获得所有服务提供者的API。 分布式节点的命名 一个分布式系统通常会由很多的节点组成节点的数量不是固定的而是不断动态变化的。比如说当业务不断膨胀和流量洪峰到来时大量的节点可能会动态加入到集群中。而一旦流量洪峰过去了就需要下线大量的节点。再比如说由于机器或者网络的原因一些节点会主动离开集群。如何为大量的动态节点命名呢一种简单的办法是可以通过配置文件手动为每一个节点命名。但是如果节点数据量太大或者说变动频繁手动命名则是不现实的这就需要用到分布式节点的命名服务。可用于生成集群节点的编号的方案 使用数据库的自增ID特性用数据表存储机器的MAC地址或者IP来维护。使用ZooKeeper持久顺序节点的顺序特性来维护节点的NodeId编号。 在第2种方案中集群节点命名服务的基本流程是 启动节点服务连接ZooKeeper检查命名服务根节点是否存在如果不存在就创建系统的根节点。在根节点下创建一个临时顺序ZNode节点取回ZNode的编号把它作为分布式系统中节点的NODEID。如果临时节点太多可以根据需要删除临时顺序ZNode节点。 分布式ID生成器 在分布式系统中分布式ID生成器的使用场景非常之多 大量的数据记录需要分布式ID。大量的系统消息需要分布式ID。大量的请求日志如restful的操作记录需要唯一标识以便进行后续的用户行为分析和调用链路分析。分布式节点的命名服务往往也需要分布式ID。其他。。。 传统的数据库自增主键已经不能满足需求。在分布式系统环境中迫切需要一种全新的唯一ID系统这种系统需要满足以下需求 全局唯一不能出现重复ID。高可用ID生成系统是基础系统被许多关键系统调用一旦宕机就会造成严重影响。 有哪些分布式的ID生成器方案呢大致如下 Java的UUID没有规律。分布式缓存Redis生成ID利用Redis的原子操作INCR和INCRBY生成全局唯一的ID。Twitter的SnowFlake算法。ZooKeeper生成ID利用ZooKeeper的顺序节点生成全局唯一的ID。MongoDb的ObjectId:MongoDB是一个分布式的非结构化NoSQL数据库每插入一条记录会自动生成全局唯一的一个“_id”字段值它是一个12字节的字符串可以作为分布式系统中全局唯一的ID。 基于Zookeeper实现分布式ID生成器 在ZooKeeper节点的四种类型中其中有以下两种类型具备自动编号的能力 PERSISTENT_SEQUENTIAL持久化顺序节点。EPHEMERAL_SEQUENTIAL临时顺序节点。 ZooKeeper的每一个节点都会为它的第一级子节点维护一份顺序编号会记录每个子节点创建的先后顺序这个顺序编号是分布式同步的也是全局唯一的。可以通过创建ZooKeeper的临时顺序节点的方法生成全局唯一的ID。示例 Slf4j public class IDMaker extends CuratorBaseOperations {private String createSeqNode(String pathPefix) throws Exception {CuratorFramework curatorFramework getCuratorFramework();// 创建一个临时顺序节点String destPath curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(pathPefix);return destPath;}public String makeId(String path) throws Exception {String str createSeqNode(path);if(null ! str){// 获取末尾的序号int index str.lastIndexOf(path);if(index0){indexpath.length();return indexstr.length() ? str.substring(index):;}}return str;} }测试 Test public void testMarkId() throws Exception {IDMaker idMaker new IDMaker();idMaker.init();String pathPrefix /idmarker/id-;for(int i0;i5;i){new Thread(()-{for (int j0;j10;j){String id null;try {id idMaker.makeId(pathPrefix);log.info({}线程第{}个创建的id为{},Thread.currentThread().getName(),j,id);} catch (Exception e) {e.printStackTrace();}}},threadi).start();}Thread.sleep(Integer.MAX_VALUE);}ZooKeeper实现雪花算法生产ID 参考雪花算法文章。 传送门https://blog.csdn.net/u010355502/article/details/132337630 分布式协调/通知 集群管理 分布式环境中实时掌握每个节点的状态是必要的可根据节点实时状态做出一些调整。ZooKeeper可以实现实时监控节点状态变化 可将节点信息写入ZooKeeper上的一个ZNode。监听这个ZNode可获取它的实时状态变化。 场景 master监控wokers的状态。 实现 # master服务 create /workers # 让master服务监控/workers下的子节点 ls -w /workers# worker1 create -e /workers/w1 w1:001 # 创建子节点master服务会收到子节点变化通知# master服务 ls -w /workers # master需要再次监听 # worker2 create -e /workers/w2 w2:001 # 创建子节点master服务会收到子节点变化通知# master服务 ls -w /workers # master需要再次监听 # worker2 quit # worker2退出master服务会收到子节点变化通知Master选举 场景 设计一个master-worker的组成员管理系统要求系统中只能有一个master , master能实时获取系统中worker的情况。 实现 # master1 create -e /master m1:001 # master2 create -e /master m2:001 # /master已经存在创建失败 Node already exists: /master # 监听/master节点 stat -w /master# master1删除后master2收到如下通知 WATCHER::WatchedEvent state:SyncConnected type:NodeDeleted path:/master # 再次发起创建节点操作 create -e /master m2:001分布式锁 参考ZooKeeper实现分布式锁文章。 传送门https://blog.csdn.net/u010355502/article/details/132343432 分布式队列 顺序节点特性可实现队列的先进先出。 条件更新 场景 设想用2个客户端操作/c节点实现一个counter使用set命令来实现自增1操作。条件更新场景∶ 客户端1把/c更新到版本1实现/c的自增1。客户端2把/c更新到版本2实现/c的自增1。客户端1不知道/c已经被客户端⒉更新过了还用过时的版本1去更新/c更新失败。如果客户端1使用的是无条件更新/c就会更新为2其实应该是3没有实现自增1。 实现 使用条件更新可以避免出现客户端基于过期的数据进行数据更新的操作。 # 客户端1 get -s -w /c # 得到结果/c0,version0 # 客户端2 set -s -v 0 /c 1 # 设置有序节点版本号为0的值自增到1 # 客户端1会收到/c修改的通知 get -s -w /c # 得到结果/c1,version1 # 客户端1 set -s -v 0 /c 1 # 此时是更新不成功的因为客户端2已经将/c的版本号更新为1了 客户端 ZooKeeper应用的开发主要通过Java客户端API去连接和操作ZooKeeper集群。可供选择的Java客户端API有 ZooKeeper官方的Java客户端API。第三方的Java客户端API比如Curator。 ZooKeeper官方的客户端API提供了基本的操作。例如创建会话、创建节点、读取节点、更新数据、删除节点和检查节点是否存在等。不过对于实际开发来说ZooKeeper官方API有一些不足之处具体如下 ZooKeeper的Watcher监测是一次性的每次触发之后都需要重新进行注册。会话超时之后没有实现重连机制。异常处理烦琐ZooKeeper提供了很多异常对于开发人员来说可能根本不知道应该如何处理这些抛出的异常。仅提供了简单的byte[]数组类型的接口没有提供Java POJO级别的序列化数据处理接口。创建节点时如果抛出异常需要自行检查节点是否存在。无法实现级联删除。 总之ZooKeeper官方API功能比较简单在实际开发过程中比较笨重一般不推荐使用。 原生Java客户端使用 引入zookeeper client依赖 !-- zookeeper client -- dependencygroupIdorg.apache.zookeeper/groupIdartifactIdzookeeper/artifactIdversion3.8.0/version /dependency注意保持与服务端版本一致不然会有很多兼容性的问题。 ZooKeeper原生客户端主要使用org.apache.zookeeper.ZooKeeper这个类来使用ZooKeeper服务。ZooKeeper常用构造器 ZooKeeper (connectString, sessionTimeout, watcher)参数说明 connectString使用逗号分隔的列表每个ZooKeeper节点是一个host.port对host是机器名或者IP地址port是ZooKeeper节点对客户端提供服务的端口号。客户端会任意选取connectString中的一个节点建立连接。 sessionTimeoutsession timeout时间。 watcher用于接收到来自ZooKeeper集群的事件。 使用zookeeper原生API连接zookeeper集群 public class ZkClientDemo {private static final String CONNECT_STRlocalhost:2181;private final static String CLUSTER_CONNECT_STR192.168.65.156:2181,192.168.65.190:2181,192.168.65.200:2181;public static void main(String[] args) throws Exception {final CountDownLatch countDownLatchnew CountDownLatch(1);ZooKeeper zooKeeper new ZooKeeper(CLUSTER_CONNECT_STR,4000, new Watcher() {Overridepublic void process(WatchedEvent event) {if(Event.KeeperState.SyncConnectedevent.getState() event.getType() Event.EventType.None){// 如果收到了服务端的响应事件连接成功countDownLatch.countDown();System.out.println(连接建立);}}});System.out.printf(连接中);countDownLatch.await();// CONNECTEDSystem.out.println(zooKeeper.getState());// 创建持久节点zooKeeper.create(/user, jay.getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);} }Zookeeper主要方法 create(path, data, acl,createMode)创建一个给定路径的znode并在znode保存data[]的数据createMode指定znode的类型。 delete(path, version)如果给定path上的znode的版本和给定的version匹配删除znode。 exists(path, watch)判断给定path上的znode是否存在并在znode设置一个watch。 getData(path, watch)返回给定path上的znode数据并在znode设置一个watch。 setData(path, data, version)如果给定path上的znode的版本和给定的version匹配设置znode数据。 getChildren(path, watch)返回给定path上的znode的孩子znode名字并在znode设置一个watch。 sync(path)把客户端session连接节点和leader节点进行同步。 方法特点 所有获取znode数据的API都可以设置一个watch用来监控znode的变化。所有更新znode数据的API都有两个版本无条件更新版本和条件更新版本。如果version为-1更新为无条件更新。否则只有给定的version和znode当前的version一样才会进行更新这样的更新是条件更新。所有的方法都有同步和异步两个版本。同步版本的方法发送请求给ZooKeeper并等待服务器的响应。异步版本把请求放入客户端的请求队列然后马上返回。异步版本通过callback来接受来自服务端的响应。 同步创建节点 Test public void createTest() throws KeeperException, InterruptedException {String path zooKeeper.create(ZK_NODE, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);log.info(created path: {},path); }创建异步节点 Test public void createAsycTest() throws InterruptedException {zooKeeper.create(ZK_NODE, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT,(rc, path, ctx, name) - log.info(rc {},path {},ctx {},name {},rc,path,ctx,name),context);TimeUnit.SECONDS.sleep(Integer.MAX_VALUE); }修改节点数据 Test public void setTest() throws KeeperException, InterruptedException {Stat stat new Stat();byte[] data zooKeeper.getData(ZK_NODE, false, stat);log.info(修改前: {},new String(data));zooKeeper.setData(ZK_NODE, changed!.getBytes(), stat.getVersion());byte[] dataAfter zooKeeper.getData(ZK_NODE, false, stat);log.info(修改后: {},new String(dataAfter)); }Curator开源客户端使用 官网https://curator.apache.org/ Curator是Netflix公司开源的一套ZooKeeper客户端框架和ZkClient一样它解决了非常底层的细节开发工作包括连接、重连、反复注册Watcher的问题以及NodeExistsException异常等。Curator是Apache基金会的顶级项目之一Curator具有更加完善的文档另外还提供了一套易用性和可读性更强的Fluent风格的客户端API框架。Curator还为ZooKeeper客户端框架提供了一些比较普遍的、开箱即用的、分布式开发用的解决方案例如Recipe、共享锁服务、Master选举机制和分布式计算器等帮助开发者避免了“重复造轮子”的无效开发工作。在实际的开发场景中使用Curator客户端就足以应付日常的ZooKeeper集群操作的需求。 引入依赖 Curator包含了几个包 curator-framework是对ZooKeeper的底层API的一些封装。curator-client提供了一些客户端的操作例如重试策略等。curator-recipes封装了一些高级特性如Cache事件监听、选举、分布式锁、分布式计数器、分布式Barrier等。 !-- zookeeper client -- dependencygroupIdorg.apache.zookeeper/groupIdartifactIdzookeeper/artifactIdversion3.8.0/version /dependency!--curator-- dependencygroupIdorg.apache.curator/groupIdartifactIdcurator-recipes/artifactIdversion5.1.0/versionexclusionsexclusiongroupIdorg.apache.zookeeper/groupIdartifactIdzookeeper/artifactId/exclusion/exclusions /dependency创建一个客户端实例 在使用curator-framework包操作ZooKeeper前首先要创建一个客户端实例。这是一个CuratorFramework类型的对象有两种方法 使用工厂类CuratorFrameworkFactory的静态newClient()方法。 // 重试策略 RetryPolicy retryPolicy new ExponentialBackoffRetry(1000, 3) // 创建客户端实例 CuratorFramework client CuratorFrameworkFactory.newClient(zookeeperConnectionString, retryPolicy); // 启动客户端 client.start();使用工厂类CuratorFrameworkFactory的静态builder构造者方法。 RetryPolicy retryPolicy new ExponentialBackoffRetry(1000, 3); CuratorFramework client CuratorFrameworkFactory.builder().connectString(192.168.128.129:2181).sessionTimeoutMs(5000) // 会话超时时间.connectionTimeoutMs(5000) // 连接超时时间.retryPolicy(retryPolicy).namespace(base) // 包含隔离名称.build(); client.start();参数说明 connectionString服务器地址列表在指定服务器地址列表的时候可以是一个地址也可以是多个地址。如果是多个地址那么每个服务器地址列表用逗号分隔, 如host1:port1,host2:port2,host3:port3。 retryPolicy重试策略当客户端异常退出或者与服务端失去连接的时候可以通过设置客户端重新连接ZooKeeper服务端。而Curator提供了一次重试、多次重试等不同种类的实现方式。在Curator内部可以通过判断服务器返回的keeperException的状态代码来判断是否进行重试处理如果返回的是OK表示一切操作都没有问题而SYSTEMERROR表示系统或服务端错误。 超时时间Curator客户端创建过程中有两个超时时间的设置。一个是sessionTimeoutMs会话超时时间用来设置该条会话在ZooKeeper服务端的失效时间。另一个是connectionTimeoutMs客户端创建会话的超时时间用来限制客户端发起一个会话连接到接收ZooKeeper服务端应答的时间。sessionTimeoutMs作用在服务端而 connectionTimeoutMs作用在客户端。 retryPolicy如下选项 策略名称描述ExponentialBackoffRetry重试一组次数重试之间的睡眠时间增加RetryNTimes重试最大次数RetryOneTime只重试一次RetryUntilElapsed在给定的时间结束之前重试 创建节点 创建节点的方式如下面的代码所示回顾我们之前课程中讲到的内容描述一个节点要包括节点的类型即临时节点还是持久节点、节点的数据信息、节点是否是有序节点等属性和性质。 Test public void testCreate() throws Exception {String path curatorFramework.create().forPath(/curator-node);curatorFramework.create().withMode(CreateMode.PERSISTENT).forPath(/curator-node,some-data.getBytes())log.info(curator create node :{} successfully.,path); }在Curator中可以使用create函数创建数据节点并通过withMod 函数指定节点类型持久化节点临时节点顺序节点临时顺序节点持久化顺序节点等默认是持久化节点之后调用forPath函数来指定节点的路径和数据信息。一次性创建带层级结构的节点 Test public void testCreateWithParent() throws Exception {String pathWithParent/node-parent/sub-node-1;String path curatorFramework.create().creatingParentsIfNeeded().forPath(pathWithParent);log.info(curator create node :{} successfully.,path); }获取数据 Test public void testGetData() throws Exception {byte[] bytes curatorFramework.getData().forPath(/curator-node);log.info(get data from node :{} successfully.,new String(bytes)); }更新节点 我们通过客户端实例的setData()方法更新ZooKeeper服务上的数据节点在setData方法的后边通过forPath函数来指定更新的数据节点路径以及要更新的数据。 Test public void testSetData() throws Exception {curatorFramework.setData().forPath(/curator-node,changed!.getBytes());byte[] bytes curatorFramework.getData().forPath(/curator-node);log.info(get data from node /curator-node :{} successfully.,new String(bytes)); }删除节点 Test public void testDelete() throws Exception {String pathWithParent/node-parent;curatorFramework.delete().guaranteed().deletingChildrenIfNeeded().forPath(pathWithParent); }参数说明 guaranteed该函数的功能如字面意思一样主要起到一个保障删除成功的作用其底层工作方式是只要该客户端的会话有效就会在后台持续发起删除请求直到该数据节点在ZooKeeper服务端被删除。 deletingChildrenIfNeeded指定了该函数后系统在删除该数据节点的时候会以递归的方式直接删除其子节点以及子节点的子节点。 异步接口 Curator 引入了BackgroundCallback接口用来处理服务器端返回来的信息这个处理过程是在异步线程中调用默认在EventThread中调用也可以自定义线程池。 public interface BackgroundCallback {/*** Called when the async background operation completes** param client the client* param event operation result details* throws Exception errors*/public void processResult(CuratorFramework client, CuratorEvent event) throws Exception; }如上接口主要参数为client客户端和服务端事件event。inBackground异步处理默认在EventThread中执行。 Test public void test() throws Exception {curatorFramework.getData().inBackground((item1, item2) - {log.info( background: {}, item2);}).forPath(ZK_NODE);TimeUnit.SECONDS.sleep(Integer.MAX_VALUE); }指定线程池 Test public void test() throws Exception {ExecutorService executorService Executors.newSingleThreadExecutor();curatorFramework.getData().inBackground((item1, item2) - {log.info( background: {}, item2);},executorService).forPath(ZK_NODE);TimeUnit.SECONDS.sleep(Integer.MAX_VALUE); }Curator监听器 /*** Receives notifications about errors and background events*/ public interface CuratorListener {/*** Called when a background task has completed or a watch has triggered** param client client* param event the event* throws Exception any errors*/public void eventReceived(CuratorFramework client, CuratorEvent event) throws Exception; }针对background通知和错误通知。使用此监听器之后调用inBackground方法会异步获得监听。 Curator Caches Curator引入了Cache来实现对ZooKeeper服务端事件监听Cache事件监听可以理解为一个本地缓存视图与远程 ZooKeeper视图的对比过程。Cache提供了反复注册的功能。Cache分为两类注册类型节点监听和子节点监听。 节点监听 NodeCache对某一个节点进行监听 public NodeCache(CuratorFramework client, String path) Parameters: client - the client path - path to cache可以通过注册监听器来实现对当前节点数据变化的处理 public void addListener(NodeCacheListener listener) Add a change listener Parameters: listener - the listener测试 Slf4j public class NodeCacheTest extends AbstractCuratorTest{public static final String NODE_CACHE/node-cache;Testpublic void testNodeCacheTest() throws Exception {createIfNeed(NODE_CACHE);NodeCache nodeCache new NodeCache(curatorFramework, NODE_CACHE);nodeCache.getListenable().addListener(new NodeCacheListener() {Overridepublic void nodeChanged() throws Exception {log.info({} path nodeChanged: ,NODE_CACHE);printNodeData();}});nodeCache.start();}public void printNodeData() throws Exception {byte[] bytes curatorFramework.getData().forPath(NODE_CACHE);log.info(data: {},new String(bytes));} }子节点监听 PathChildrenCache会对子节点进行监听但是不会对二级子节点进行监听 public PathChildrenCache(CuratorFramework client,String path,boolean cacheData) Parameters: client - the client path - path to watch cacheData - if true, node contents are cached in addition to the stat可以通过注册监听器来实现对当前节点的子节点数据变化的处理 public void addListener(PathChildrenCacheListener listener) Add a change listener Parameters: listener - the listener测试 Slf4j public class PathCacheTest extends AbstractCuratorTest{public static final String PATH/path-cache;Testpublic void testPathCache() throws Exception {createIfNeed(PATH);PathChildrenCache pathChildrenCache new PathChildrenCache(curatorFramework, PATH, true);pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {Overridepublic void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {log.info(event: {},event);}});// 如果设置为true则在首次启动时就会缓存节点内容到Cache中pathChildrenCache.start(true);} }TreeCache使用一个内部类TreeNode来维护这个一个树结构。并将这个树结构与ZK节点进行了映射。所以TreeCache可以监听当前节点下所有节点的事件。 public TreeCache(CuratorFramework client,String path,boolean cacheData) Parameters: client - the client path - path to watch cacheData - if true, node contents are cached in addition to the stat可以通过注册监听器来实现对当前节点的子节点及递归子节点数据变化的处理 public void addListener(TreeCacheListener listener) Add a change listener Parameters: listener - the listener测试 Slf4j public class TreeCacheTest extends AbstractCuratorTest{public static final String TREE_CACHE/tree-path;Testpublic void testTreeCache() throws Exception {createIfNeed(TREE_CACHE);TreeCache treeCache new TreeCache(curatorFramework, TREE_CACHE);treeCache.getListenable().addListener(new TreeCacheListener() {Overridepublic void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {log.info( tree cache: {},event);}});treeCache.start();} }
http://www.dnsts.com.cn/news/121713.html

相关文章:

  • 网站流量怎么做的营销网络建设四个阶段
  • 网站优化方案ppt电脑做服务器发布网站吗
  • 桥梁建设杂志网站湖州市建设培训中心网站
  • 网站访问量怎么做郴州网站建设
  • 网站建设职业主要做什么在线绘制流程图的网站
  • 权威的南昌网站建设网站被k 原因
  • 企业网站建设的研究开发方法及技术路线wordpress视频模版
  • 滨江道做网站公司郑州app开发公司
  • 让网站对搜索引擎友好免费html5中文网站素材
  • 网站注册页面设计厦门响应式网站制作
  • 做货代用什么网站找客户长沙房地产市场分析
  • 北京建设主管部门官方网站网站ui设计怎么做
  • 贷款网站平台有哪些建网站手机怎么做
  • 哪项不属于网站架构登录页面设计模板
  • 手机建网站 教程长春个人网站制作公司
  • 网站文字格式wordpress idp
  • 非洲用什么网站做采购wordpress评论首页显示第一
  • 河南省城乡建设厅网站北湖建设局网站
  • 企业网站模板建设黄页免费领取
  • 做代炼的网站关于网站开发的自我评价
  • 哪种浏览器可以打开所有网站怎样生成链接
  • 高校网站建设的文章网站降权怎么恢复
  • 重庆最便宜的网站建设公司免费网站服务器域名
  • 怎么免费做网站不要域名毕业设计做网站还是系统好
  • 网站推广的目的和意义商业设计师是做什么的
  • 网站需要数据库吗在线的crm系统软件
  • iis 网站目录权限设置上海网站建设公司怎么样
  • 郑州网站制作公司名单怎么用wix做网站
  • 网站查询域名ip入口电子商务网站建设首页流程
  • 做目的旅游网站的ui首页界面设计