1.Dubbo

1.1RPC

RPC全称是remote procedure call,即远程过程调用。比如有两台服务器A和B,它们上面分别部署了一个服务。此时B服务器想调用A服务器上提供的方法,由于不在同一台服务器,就不能直接调用,那就需要通过网络的方式来表达调用的语义和传达调用的数据。需要注意的是它不是一种技术,而是远程过程调用。

1.2Dubbo基本介绍

官网:http://dubbo.apache.org
Dubbo是一个高性能的java RPC框架。它的三大核心能力是:面向接口的远程方法调用、智能容错和负载均衡、服务自动注册与发现。

SOA(Service-Oriented Architecture)是一种面向服务的架构。它将应用程序的不同功能单元(称为服务)进行拆分,并通过这些服务之间定义良好的接口和契约联系起来.

Dubbox 是一个分布式服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有dubbox这样的分布式服务框架的需求。

1.3调用过程

调用过程图如下:

调用过程说明:(数字代表调用顺序,与图对应)

0.服务容器负责启动、加载、运行服务提供者。
1.服务提供者在启动时,向注册中心注册自己提供的服务。
2.服务消费者在启动时,向注册中心订阅自己所需的服务。
3.注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
4.服务消费者从提供者地址列表中,基于软负载均衡算法,选一台提供者通过网络进行调用,如果调用失败,再选另一台调用。
5.在调用过程中,监控中心会时刻监控调用的情况。

在调用的过程中,可以发现需要一个注册中心,Dubbo官方推荐使用Zookeeper作为注册中心。

2.Zookeeper

2.1Zookeeper简介

Zookeeper是一个基于观察者模式而设计的分布式服务管理框架。它负责存储和管理数据,接受观察者的注册,一旦这些数据发生变化,就通知已经注册的观察者做出相应的操作。
简单来说,它就是一个注册中心。换句话说,注册中心是负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小。

2.2特点与应用场景

2.2.1特点

1)集群中只要有半数以上节点存活,集群就可以正常服务。
2)全局数据一致。即每个服务器保存一份相同的数据副本。
3)数据更新原子性。

2.2.2应用场景

统一命名服务、统一配置管理、统一集群管理、服务器动态上下线、软负载均衡。

2.3下载与安装

2.3.1下载

官网下载:http://Zookeeper.apache.org/releases.html
网盘下载:链接:https://pan.baidu.com/s/1c1SQCwYpMWrnAhw2ux5iYA 提取码:vw1z

2.3.2安装

2.3.2.1 安装
Zookeeper是安装在linux中的。在安装之前默认linux中已安装了JDK。

1)把 zookeeper 的压缩包上传到 linux 系统,这里以3.6.0版本为例。

2)解压到指定目录

tar -zxvf zookeeper-3.6.0.tar.gz -C /usr/local

3)进入 zookeeper-3.4.6 目录,创建 data 文件夹。

cd zookeeper-3.6.0
mkdir data

4)进入conf目录 ,把 zoo_sample.cfg 改名为 zoo.cfg

cd conf
mv zoo_sample.cfg zoo.cfg

5)打开zoo.cfg ,  修改 data 属性:

vi zoo.cfg
#dataDir修改属性如下
dataDir=/usr/local/zookeeper-3.4.6/data

2.3.2.2Zookeeper启动与停止

启动zookeeper服务

cd ..
bin/zkServer.sh start

输出以上内容表示启动成功

关闭服务:

bin/zkServer.sh stop

查看状态:

bin/zkServer.sh status

如果启动状态,提示

如果未启动状态,提示

启动客户端

bin/zkCli.sh

查看注册的服务

ls /

退出客户端

quit

2.3.2.3参数配置解读

tickTime=5000 通信心跳数,Zookeeper服务器与客户端的心跳时间(ms)
initLimit=10 LF初始通信时限。即集群中跟随者与领导者服务器之间初始连接时最多能容忍的心跳数。
syncLimit=5 LF同步通信时限。即集群中跟随者与领导者服务器之间的最大响应时间单位。
clientPort=2181 客户端端口号
dataDir 数据文件目录+数据持久化路径

2.4Zookeeper内部原理

2.4.1选举机制

1)半数机制:集群中半数以上机器存活,那么集群就可以正常服务(主要是根据myid中尽可能大的进行选举)。故Zookeeper适合安装奇数台服务器。
2)选举流程
目前有5台服务器,每台服务器均没有数据,它们的编号分别是1,2,3,4,5,按编号依次启动,它们的选择举过程如下:
服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于Looking(选举状态)。
服务器2启动,给自己投票,同时与之前启动的服务器1交换结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是LOOKING。
服务器3启动,给自己投票,同时与之前启动的服务器1,2交换信息,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为领导者,服务器1,2成为小弟。
服务器4启动,给自己投票,同时与之前启动的服务器1,2,3交换信息,尽管服务器4的编号大,但之前服务器3已经胜出,所以服务器4只能成为小弟。
服务器5启动,给自己投票,同时与之前启动的服务器1,2,3,4交换信息,尽管服务器5的编号大,但之前服务器3已经胜出,所以服务器5只能成为小弟。

2.4.2Zookeeper的监听器原理

1)首先有一个主线程,它会在主线程中创建Zookeeper客户端,那么就会创建两个线程,一个负责网络连接通信(connect),一个负责监听(listener);
2)通过connect线程把注册的监听事件发送给Zookeeper;
3)把注册的监听事件添加到Zookeeper的监听器列表中;
4)Zookeeper监听到有数据或路径变化就会把这个消息发送给listener线程,listener线程内部调用process()方法。

2.4.3Zookeeper面试题

Zookeeper的部署方式:单机和集群;
集群的角色:Loader和Follower;
集群的最少机器数:3

3.结合spring开发

项目地址:https://github.com/zhongyushi-git/dubbo-demo.git

3.1服务提供者开发

1)新建一个空项目,名为dubbo-demo,然后在这个空项目中创建一个maven的web工程(名为dubbo-provider)作为服务提供者。

2)在pom.xml中导入相关的依赖和插件。需要注意的是Zookeeper的版本必须和导入的dubbo依赖的版本一致。(版本不一致,这是一个大坑)。

 <!--指定版本-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.5.RELEASE</spring.version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.0</version>
</dependency>
<!-- zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.7</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.11.0.GA</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 指定端口 -->
<port>8081</port>
<!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>

3)在webapp/WEB-INF/web.xml中配置spring容器

<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 加载spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>

4)在mian目录下新建java和resources的资源目录,然后在java目录成绩包com.zys.dubbo。

5)创建业务接口

创建包com.zys.dubbo.service,用于存放业务接口。

package com.zys.dubbo.service;

public interface UserService {
public String getName();
}

6)创建业务实现类

创建包com.gh.dubbodemo.service.impl ,用于存放业务实现类。

package com.zys.dubbo.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.zys.dubbo.service.UserService; @Service
public class UserServiceImpl implements UserService {
@Override
public String getName() {
return "success";
}
}

注意:Service注解与原来不同,需要引入com.alibaba包下的。

7)创建配置文件applicationContext-service.xml

在src/main/resources下创建applicationContext-service.xml ,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <!--指定dubbo应用的名称-->
<dubbo:application name="dubbo-provider"/>
<!--指定服务的注册中心-->
<dubbo:registry address="zookeeper://101.37.23.71:2181"/>
<!--配置协议和端口-->
<dubbo:protocol name="dubbo" port="20881"></dubbo:protocol>
<!--指定服务的包扫描-->
<dubbo:annotation package="com.zys.dubbo.service.impl"/>
</beans>

3.2服务消费者开发

1)在空项目中再创建一个maven的web工程(名为dubbo-consumer)作为服务消费者。

2)在pom.xml中导入相关的依赖和插件。

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.5.RELEASE</spring.version>
</properties> <dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.0</version>
</dependency>
<!-- zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.7</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.11.0.GA</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 指定端口 -->
<port>8082</port>
<!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>

3)在webapp/WEB-INF/web.xml中配置servlet

<web-app>
<display-name>Archetype Created Web Application</display-name> <servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-web.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>

4)在mian目录下新建java和resources的资源目录,然后在java目录成绩包com.zys.dubbo。

5)创建业务接口

创建包com.zys.dubbo.service,用于存放业务接口。

package com.zys.dubbo.service;

public interface UserService {
public String getName();
}

6)编写Controller

创建包com.zys.dubbo.controller

package com.zys.dubbo.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.zys.dubbo.service.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; @Controller
@RequestMapping("/user")
public class UserController { //调用远程接口
@Reference
private UserService userService; @RequestMapping("/get")
@ResponseBody
public String showName(){
return userService.getName();
}
}

7)创建配置文件applicationContext-web.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <mvc:annotation-driven >
<mvc:message-converters register-defaults="false">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 引用dubbo 服务 -->
<dubbo:application name="dubbo-web" />
<dubbo:registry address="zookeeper://101.37.23.71:2181"/>
<dubbo:annotation package="com.zys.dubbo.controller" />
</beans>

3.3测试运行

在maven插件中运行tomcat插件。先启动服务提供者,再启动消费者。然后在浏览器输入http://127.0.0.1:8082/user/get.do可访问成功。

3.4配置参数解读

3.4.1启动时检查

在测试运行时,是先启动服务提供者再启动的服务消费者,但是如果先启动服务消费者,就会报错。原因是在启动服务消费者的时候,它会去检查依赖的服务是否可用,由于没有服务提供者,就会抛出异常。如何解决这个 问题呢?只需要在消费者的配置文件(applicationContext-web.xml)中设置check为false即可,默认值是true。

<dubbo:consumer check="false"/>

3.4.2负载均衡

负载均衡:将请求分摊到多个操作单元上执行,共同完成任务。

在集群中,Dubbo的均衡策略包括随机,轮询、最少活跃调用数和一致性Hash,默认是随机策略。可以在服务提供者设置均衡策略,也可以在服务消费者这是均衡策略。

1)在服务提供者中设置

@Service(loadbalance = "random")
public class UserServiceImpl implements UserService {
@Override
public String getName() {
return "success";
}
}

2)在服务消费者中设置

@Controller
@RequestMapping("/user")
public class UserController { //调用远程接口
@Reference(loadbalance = "random")
private UserService userService; @RequestMapping("/get")
@ResponseBody
public String showName(){
return userService.getName();
} }

4.Dubbo管理控制台安装

4.1下载

github:https://github.com/apache/dubbo

网盘:链接:https://pan.baidu.com/s/1E7-YZiveKjk1xgDwO5Bp4w   提取码:sdl8

4.2打包运行

把下载的war包直接放到tomcat的webapps下,然后启动tomcat。这里把它部署到本地的tomcat中。

需要注意的是,如果控制台和Zookeeper不是在同一台 服务器上,那么在启动tomcat的过程中会报错。这时需要修改dubbo-admin项目的WEB-INF/dubbo.properties 文件,把下面的ip换成Zookeeper服务器的ip即可。

dubbo.registry.address=zookeeper://127.0.0.1:2181

修改之后重启tomcat。

4.3基本使用

(1)启动tomcat后在浏览器输入http://localhost:8080/dubbo-admin-2.6.0/ ,登录用户名和密码均为root 进入首页。

(2)启动服务提供者工程,即可在服务治理-提供者查看到该服务。

(3)启动服务消费者工程,运行页面,观察“消费者”列表

Dubbo与Zookeeper开发的更多相关文章

  1. dubbo连接zookeeper注册中心因为断网导致线程无限等待问题【转】

    最近维护的系统切换了网络环境,由联通换成了电信网络,因为某些过滤规则导致系统连不上zookeeper服务器(应用系统机器在深圳,网络为电信线路,zookeeper服务器在北京,网络为联通线路),因为我 ...

  2. (转)Dubbo与Zookeeper、SpringMVC整合和使用

    原文地址: https://my.oschina.net/zhengweishan/blog/693163 Dubbo与Zookeeper.SpringMVC整合和使用 osc码云托管地址:http: ...

  3. Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)

    互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...

  4. 160906、Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)

    互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...

  5. Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)转

    互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...

  6. 【转载】Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)

    http://blog.csdn.net/congcong68/article/details/41113239 互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及 ...

  7. Dubbo、Zookeeper、SpringMVC的整合使用

    互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...

  8. Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)(转)

    互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...

  9. Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)(转)

    互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...

随机推荐

  1. BGP总结(二)

    BGP属性 路由器发送关于目标网络的BGP更新消息,更新的度量值被称为路径属性.属性可以是公认的或可选的.强制的或自由决定的.传递的或非传递的.属性也可以是部分的.并非组织的和有组合都是合法的,路径属 ...

  2. Scala集合库、模式匹配和样例类

    package com.yz8 import org.junit.Test class test { @Test def test: Unit = { val ints = List(1,5,7,6, ...

  3. Educational Codeforces Round 91 (Rated for Div. 2) D. Berserk And Fireball

    题目链接:https://codeforces.com/contest/1380/problem/D 题意 给出一个大小为 $n$ 的排列 $a$ 和一个序列 $b$,有两种操作: 花费 $x$ 消除 ...

  4. python的threading的使用(join方法,多线程,锁threading.Lock和threading.Condition

    一.开启多线程方法一 import threading,time def write1(): for i in range(1,5): print('1') time.sleep(1) def wri ...

  5. 二叉树增删改查 && 程序实现

    二叉排序树定义 一棵空树,或者是具有下列性质的二叉树:(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值:(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值:(3)左.右子树也 ...

  6. 无所不能的Embedding6 - 跨入Transformer时代~模型详解&代码实现

    上一章我们聊了聊quick-thought通过干掉decoder加快训练, CNN-LSTM用CNN作为Encoder并行计算来提速等方法,这一章看看抛开CNN和RNN,transformer是如何只 ...

  7. windows hook + pyhook3 + python win32api hook + C 键盘hook

    安装pyhook3见:https://www.cnblogs.com/lqerio/p/12096710.html 使用见:https://www.cnblogs.com/lqerio/p/12106 ...

  8. hdu-1941 Find the Shortest Common Superstring

    The shortest common superstring of 2 strings S 1 and S 2 is a string S with the minimum number of ch ...

  9. [USACO15JAN]Moovie Mooving G

    [USACO15JAN]Moovie Mooving G 状压难题.不过也好理解. 首先我们根据题意: she does not want to ever visit the same movie t ...

  10. image cache service

    image cache service 图床 https://images.weserv.nl/ https://github.com/weserv/images meta & referre ...