myspringcloud http://blog.okbase.net/iteye01 java B2B2C源码电子商务平台 -kafka架构介绍 http://blog.okbase.net/iteye01/archive/56065.html iteye01 2019/1/16 15:13:19 一、 简单介绍
kafka是分布式的,基于发布/订阅的消息系统。
需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六
1、即使对TB级以上数据也能保证常数时间复杂度的访问性能。
2、 高吞吐率:即使在非常廉价的商用机器上也能做到单机支持每秒100k条以上消息的传输。
3、 支持分区,消息分布式消费,但是只能保证每个partition内的消息顺序传输。并且支持在线水平扩展。
为何使用消息中间件呢,大家肯定接触过rabbitmq、activemq、redis等,估计有很多感触。我就不详细描述了,这个只能亲身参加过大的技术架构,自己身在其中,并且感受到不用消息中间件和用的区别。

二、 架构
了解架构之前,我们先了解一下基本名词。

Broker:安装了kafka的服务器就是一个broker。
Topic:消息的类比,最好一类数据定一个topic去存储传输。
Partition:分区,topic可以定分到几个分区中。
Producer:发送消息,发送者。
Consumer:消费消息,消费者。
Consumer Group:每个Consumer属于一个特定的Consumer Group。



从图中来看,kafka集群包含若干个producer和consumer以及broker,还有一个zk集群。Producer通过push模式将数据发送到broker,Consumer通过pull模式拉取数据。
Producer发送消息到broker时,根据partition机制选择分不到哪一个partition,设置合理的情况下,所有消息可以均匀分不到不同的partition里,实现了负载均衡。

java B2B2C 源码 多级分销Springcloud多租户电子商城系统

]]>
java B2B2C Springcloud电子商务平台源码- Zuul微服务网关的API限流 http://blog.okbase.net/iteye01/archive/56064.html iteye01 2019/1/16 15:12:12 API限流
微服务开发中有时需要对API做限流保护,防止网络攻击,比如做一个短信验证码API,限制客户端的请求速率能在一定程度上抵御短信轰炸攻击,降低损失。
使用方法
比如我们要对user-service这个服务进行限流,限制每个请求源每分钟最多只能请求10次。
需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六
首先在项目中添加 spring-cloud-zuul-ratelimit 依赖:

<dependency>
    <groupId>com.marcosbarbero.cloud</groupId>
    <artifactId>spring-cloud-zuul-ratelimit</artifactId>
    <version>1.5.0.RELEASE</version>
</dependency>


然后再添加如下配置即可:

zuul:
  ratelimit:
    enabled: true
    behind-proxy: true
    policy-list:
      user-service:
        - limit: 10 
          refresh-interval: 60
          type: 
            - user
            - origin
            - url


测试客户端如果60s内请求超过10次,服务端就抛出异常,一分钟后又可以正常请求

某个IP的客户端被限流并不影响其他客户端,即API网关对每个客户端限流是相互独立的

限流数据存储
对API限流是基于Zuul过滤器完成的,默认情况下限流数据是记录在内存中的,实际上是用ConcurrentHashMap保存,当然也提供了多种存储方式,包括Redis、Consul、Spring Data JPA,使用这三种存储方式要添加相关依赖。

然后再添加存储配置,比如使用Redis的配置:

zuul:
  ratelimit:
    repository: Redis


原理分析
限流拦截时机
限流过滤器是在请求被转发之前调用的

    @Override
    public String filterType() {
        return "pre";
    }


限流类型
限流类型主要包括url、origin、user三种

   if (types.contains(URL)) {
       joiner.add(route.getPath());
   }
   if (types.contains(ORIGIN)) {
       joiner.add(getRemoteAddr(request));
   }
   if (types.contains(USER)) {
       joiner.add(request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : ANONYMOUS);
   }


url类型的限流就是通过请求路径区分

origin是通过客户端IP地址区分

user是通过授权用户进行区分,也包括匿名用户

可以多个限流类型结合使用

如果不配置限流类型,就不做以上区分

拦截限流请求
在过滤器的run方法中判断请求剩余次数,小于0就拦截请求:

   if (rate.getRemaining() < 0) {
       ctx.setResponseStatusCode(TOO_MANY_REQUESTS.value());
       ctx.put("rateLimitExceeded", "true");
       throw new ZuulRuntimeException(new ZuulException(TOO_MANY_REQUESTS.toString(),
               TOO_MANY_REQUESTS.value(), null));
   }


可以看到,单位时间内剩余请求次数小于0时抛出ZuulRuntimeException,直接返回客户端TOO_MANY_REQUESTS异常消息,达到拦截请求的效果。

Java B2B2C多用户商城 springcloud架构
]]>
java B2B2C Springcloud电子商城系统—Feign实例 http://blog.okbase.net/iteye01/archive/56063.html iteye01 2019/1/16 15:10:53
什么是Feign
Feign是受到Retrofit,JAXRS-2.0和WebSocket的影响,它是一个jav的到http客户端绑定的开源项目。 Feign的主要目标是将Java Http 客户端变得简单。
需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六
1、配置feign
添加依赖
在maven的pom中添加feign

   <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-feign</artifactId>
    </dependency>


配置启用
在Application启动类中添加@EnableFeignClients注解。

@EnableEurekaClient
@EnableFeignClients
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }


}


2、新建feign

@FeignClient(name = "SERVICE-NAME", url = "${***}")
public interface TestFeign {
}


其中:
name:微服务的名称,一定要以eureka后台配置的保持一致。
url:可以手动指定feign的调用地址
fallback:标记容错后执行的类

在feign中定义接口的方式与正常接口并无差异,需注意参数名称等保持一致。如:

@RequestMapping(value = "/user/message", method = RequestMethod.POST)
    JSONObject sendMessage(@RequestParam("userId") String userId, @RequestParam("content") String content);


3、调用feign
在ServiceImpl中注入feign接口,正常使用即可。

@Autowired
TestFeign testFeign;


]]>
Java B2B2C多用户商城 springcloud架构-Spring Cloud Feign http://blog.okbase.net/iteye01/archive/56062.html iteye01 2019/1/16 15:09:59 1、什么是Feign?

Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直接调用。Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。
需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六
Feign被广泛应用在Spring Cloud 的解决方案中,是学习基于Spring Cloud 微服务架构不可或缺的重要组件。

2、为什么用Feign

可以与多种HTTP客户端集成
spring 已经完全集成feign
极大地简化了HTTP请求代码量
与ribbon负载均衡器、hystrix熔断器无缝集成。

3、Feign解决了什么问题?

封装了Http调用流程,更适合面向接口化的变成习惯
在服务调用的场景中,我们经常调用基于Http协议的服务,而我们经常使用到的框架可能有HttpURLConnection、Apache HttpComponnets、OkHttp3 、Netty等等,这些框架在基于自身的专注点提供了自身特性。而从角色划分上来看,他们的职能是一致的提供Http调用服务。
从现在开始,我这边会将近期研发的spring cloud微服务云架构的搭建过程和精髓记录下来,帮助更多有兴趣研发spring cloud框架的朋友,大家来一起探讨spring cloud架构的搭建过程及如何运用于企业项目。

java B2B2C Springcloud电子商务平台源码

]]>
java B2B2C 源码 多级分销Springcloud多租户电子商城系统-Spring Cloud eureka http://blog.okbase.net/iteye01/archive/56061.html iteye01 2019/1/16 15:09:05 在构建项目之前,我们先学习一下eureka,这是官方的讲解,我这边再重新帮大家回顾一下:
需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六

服务发现:Eureka客户端

服务发现是基于微服务架构的关键原则之一。尝试配置每个客户端或某种形式的约定可能非常困难,可以非常脆弱。Netflix服务发现服务器和客户端是Eureka。可以将服务器配置和部署为高可用性,每个服务器将注册服务的状态复制到其他服务器。

如何包含Eureka客户端

要在您的项目中包含Eureka客户端,请使用组org.springframework.cloud和工件ID spring-cloud-starter-eureka的启动器。

注册Eureka

当客户端注册Eureka时,它提供关于自身的元数据,例如主机和端口,健康指示符URL,主页等。Eureka从属于服务的每个实例接收心跳消息。如果心跳失败超过可配置的时间表,则通常将该实例从注册表中删除。

Eureka在springcloud中的使用

Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client是一个Java客户端,用于简化与Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。
在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
Eureka Server之间将会通过复制的方式完成数据的同步。
Eureka还提供了客户端缓存的机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。
综上,Eureka通过心跳检测、健康检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。

技术架构图:

spring cloud java b2b2c o2o分布式 微服务电子商务平台

]]>
java B2B2C源码电子商务平台 --zuul跨域访问问题 http://blog.okbase.net/iteye01/archive/56055.html iteye01 2019/1/7 16:19:37 springcloud微服务框架,是一组组件,eureka服务注册中心,zuul路由等等

一般都是在zuul上配好url路径映射到各个服务,所以对外都是访问zuul服务的端口,但是在web服务设置了跨域的Interceptor后没有起作用(我的chrome浏览器,postman正常),关掉web服务,依然有返回http

需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六

最后确定是在zuul上没有设置跨域header

跨域时,可能会先OPTIONS访问,zuul直接返回了,所以需要给zuul添加跨域header

import org.springframework.web.cors.UrlBasedCorsConfigurationSource
import org.springframework.web.cors.CorsConfiguration

@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
List<String> origins = new ArrayList<>();
origins.add("*");
config.addAllowedOrigin(origins);
List<String> headers = new ArrayList<>();
headers.add("*");
config.addAllowedHeader(headers);
List<String> methods = new ArrayList<>();
methods.add("OPTIONS");
methods.add("GET");
methods.add("POST");
config.addAllowedMethod(methods);
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}

java B2B2C springmvc mybatis多租户电子商城系统

]]>
java B2B2C源码电子商城系统-Kafka快速入门 http://blog.okbase.net/iteye01/archive/56054.html iteye01 2019/1/7 16:18:34 大家对Kafka有了一些基本了解之后,下面我们来尝试构建一个Kafka服务端,并体验一下基于Kafka的消息生产与消费。
需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六
环境安装
首先,我们需要从官网上下载安装介质。
在解压Kafka的安装包之后,可以看到其目录结构如下:

kafka
+-bin
+-windows
+-config
+-libs
+-logs
+-site-docs

由于Kafka的设计中依赖了ZooKeeper,所以我们可以在bin和config目录中除了看到Kafka相关的内容之外,还有ZooKeeper相关的内容。其中bin目录存放了Kafka和ZooKeeper的命令行工具,bin根目录下是适用于Linux/Unix的shell,而bin/windows下的则是适用于windows下的bat。我们可以根据实际的系统来设置环境变量,以方便后续的使用和操作。而在config目录中,则是用来存放了关于Kafka与ZooKeeper的配置信息。

启动测试
下面我们来尝试启动ZooKeeper和Kafka来进行消息的生产和消费。示例中所有的命令均已配置了Kafka的环境变量为例。

启动ZooKeeper,执行命令:zookeeper-server-start config/zookeeper.properties,该命令需要指定zookeeper的配置文件位置才能正确启动,kafka的压缩包中包含了其默认配置,开发与测试环境不需要修改。

[2016-09-28 08:05:34,849] INFO Reading configuration from: config\zookeeper.properties (org.apache.zookeeper.server.quorum.QuorumPeerConfig)
[2016-09-28 08:05:34,850] INFO autopurge.snapRetainCount set to 3 (org.apache.zookeeper.server.DatadirCleanupManager)
[2016-09-28 08:05:34,851] INFO autopurge.purgeInterval set to 0 (org.apache.zookeeper.server.DatadirCleanupManager)
[2016-09-28 08:05:34,851] INFO Purge task is not scheduled. (org.apache.zookeeper.server.DatadirCleanupManager)
...
[2016-09-28 08:05:34,940] INFO binding to port 0.0.0.0/0.0.0.0:2181 (org.apache.zookeeper.server.NIOServerCnxnFactory)

从控制台信息中,我们可以看到ZooKeeper从指定的config/zookeeper.properties配置文件中读取信息并绑定2181端口启动服务。有时候启动失败,可查看一下端口是否被占用,可以杀掉占用进程或通过修改config/zookeeper.properties配置文件中的clientPort内容以绑定其他端口号来启动ZooKeeper。

启动Kafka,执行命令:kafka-server-start config/server.properties,该命令也需要指定Kafka配置文件的正确位置,如上命令中指向了解压目录包含的默认配置。若在测试时,使用外部集中环境的ZooKeeper的话,我们可以在该配置文件中通过zookeeper.connect参数来设置ZooKeeper的地址和端口,它默认会连接本地2181端口的ZooKeeper;如果需要设置多个ZooKeeper节点,可以为这个参数配置多个ZooKeeper地址,并用逗号分割。比如:zookeeper.connect=127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002。

创建Topic,执行命令:kafka-topics --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test,通过该命令,创建一个名为“test”的Topic,该Topic包含一个分区一个Replica。在创建完成后,可以使用kafka-topics --list --zookeeper localhost:2181命令来查看当前的Topic。

另外,如果我们不使用kafka-topics命令来手工创建,直接进行下面的内容进行消息创建时也会自动创建Topics来使用。

创建消息生产者,执行命令:kafka-console-producer --broker-list localhost:9092 --topic test。kafka-console-producer命令可以启动Kafka基于命令行的消息生产客户端,启动后可以直接在控制台中输入消息来发送,控制台中的每一行数据都会被视为一条消息来发送。我们可以尝试输入几行消息,由于此时并没有消费者,所以这些输入的消息都会被阻塞在名为test的Topics中,直到有消费者将其消费掉位置。

创建消息消费者,执行命令:kafka-console-consumer --zookeeper localhost:2181 --topic test --from-beginning。kafka-console-consumer命令启动的是Kafka基于命令行的消息消费客户端,在启动之后,我们马上可以在控制台中看到输出了之前我们在消息生产客户端中发送的消息。我们可以再次打开之前的消息生产客户端来发送消息,并观察消费者这边对消息的输出来体验Kafka对消息的基础处理。

整合Spring Cloud Bus
在上一篇使用Rabbit实现消息总线的案例中,我们已经通过引入spring-cloud-starter-bus-amqp模块,完成了使用RabbitMQ来实现的消息总线。若我们要使用Kafka来实现消息总线时,只需要把spring-cloud-starter-bus-amqp替换成spring-cloud-starter-bus-kafka模块,在pom.xml的dependenies节点中进行修改,具体如下:

 

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-kafka</artifactId>
</dependency>



如果我们在启动Kafka时均采用了默认配置,那么我们不需要再做任何其他配置就能在本地实现从RabbitMQ到Kafka的切换。我们可以尝试把刚刚搭建的ZooKeeper、Kafka启动起来,并将修改为spring-cloud-starter-bus-kafka模块的config-server和config-client启动起来。

在config-server启动时,我们可以在控制台中看到如下输出:

2016-09-28 22:11:29.627 INFO 15144 --- [ main] o.s.c.s.b.k.KafkaMessageChannelBinder : Using kafka topic for outbound: springCloudBus
2016-09-28 22:11:29.642 INFO 15144 --- [-localhost:2181] org.I0Itec.zkclient.ZkEventThread : Starting ZkClient event thread.
...
016-09-28 22:11:30.290 INFO 15144 --- [ main] o.s.i.kafka.support.ProducerFactoryBean : Using producer properties => {bootstrap.servers=localhost:9092, linger.ms=0, acks=1, compression.type=none, batch.size=16384}
2016-09-28 22:11:30.298 INFO 15144 --- [ main] o.a.k.clients.producer.ProducerConfig : ProducerConfig values:
...
2016-09-28 22:11:30.322 INFO 15144 --- [ main] o.s.c.s.b.k.KafkaMessageChannelBinder$1 : Adding {message-handler:outbound.springCloudBus} as a subscriber to the 'springCloudBusOutput' channel
2016-09-28 22:11:31.467 INFO 15144 --- [ main] o.s.c.s.b.k.KafkaMessageChannelBinder$7 : Adding {message-handler:inbound.springCloudBus.anonymous.8b9e6c7b-6a50-48c5-b981-8282a0d5a30b} as a subscriber to the 'bridge.springCloudBus' channel
2016-09-28 22:11:31.467 INFO 15144 --- [ main] o.s.c.s.b.k.KafkaMessageChannelBinder$7 : started inbound.springCloudBus.anonymous.8b9e6c7b-6a50-48c5-b981-8282a0d5a30b

从控制台的输出内容,我们可以看到config-server连接到了Kafka中,并使用了名为springCloudBus的Topic。

此时,我们可以使用kafka-topics --list --zookeeper localhost:2181命令来查看当前Kafka中的Topic,若已成功启动了config-server并配置正确,我们就可以在Kafka中看到已经多了一个名为springCloudBus的Topic。

我们再启动配置了spring-cloud-starter-bus-kafka模块的config-client,可以看到控制台中输出如下内容:

2016-09-28 22:43:55.067 INFO 6136 --- [ main] o.s.c.s.b.k.KafkaMessageChannelBinder : Using kafka topic for outbound: springCloudBus
2016-09-28 22:43:55.078 INFO 6136 --- [-localhost:2181] org.I0Itec.zkclient.ZkEventThread : Starting ZkClient event thread.
...
2016-09-28 22:50:38.584 INFO 828 --- [ main] o.s.i.kafka.support.ProducerFactoryBean : Using producer properties => {bootstrap.servers=localhost:9092, linger.ms=0, acks=1, compression.type=none, batch.size=16384}
2016-09-28 22:50:38.592 INFO 828 --- [ main] o.a.k.clients.producer.ProducerConfig : ProducerConfig values: 
...
2016-09-28 22:50:38.615 INFO 828 --- [ main] o.s.c.s.b.k.KafkaMessageChannelBinder$1 : Adding {message-handler:outbound.springCloudBus} as a subscriber to the 'springCloudBusOutput' channel
2016-09-28 22:50:38.616 INFO 828 --- [ main] o.s.integration.channel.DirectChannel : Channel 'didispace:7002.springCloudBusOutput' has 1 subscriber(s).
2016-09-28 22:50:38.616 INFO 828 --- [ main] o.s.c.s.b.k.KafkaMessageChannelBinder$1 : started outbound.springCloudBus
...
2016-09-28 22:50:39.162 INFO 828 --- [ main] s.i.k.i.KafkaMessageDrivenChannelAdapter : started org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter@60cf855e
2016-09-28 22:50:39.162 INFO 828 --- [ main] o.s.c.s.b.k.KafkaMessageChannelBinder$7 : Adding {message-handler:inbound.springCloudBus.anonymous.f8fc9c0c-ccd3-46dd-9537-07198f4ee216} as a subscriber to the 'bridge.springCloudBus' channel
2016-09-28 22:50:39.163 INFO 828 --- [ main] o.s.c.s.b.k.KafkaMessageChannelBinder$7 : started inbound.springCloudBus.anonymous.f8fc9c0c-ccd3-46dd-9537-07198f4ee216

可以看到,config-client启动时输出了类似的内容,他们都订阅了名为springCloudBus的Topic。

在启动了config-server和config-client之后,为了更明显地观察消息总线刷新配置的效果,我们可以在本地启动多个不同端口的config-client。此时,我们的config-server以及多个config-client都已经连接到了由Kafka实现的消息总线上。我们可以先访问各个config-client上的/from请求,查看他获取到的配置内容。然后,修改Git中对应的参数内容,再访问各个config-client上的/from请求,可以看到配置内容并没有改变。最后,我们向config-server发送POST请求:/bus/refresh,此时我们再去访问各个config-client上的/from请求,就能获得到最新的配置信息,各客户端上的配置都已经加载为最新的Git配置内容。

从config-client的控制台中,我们可以看到如下内容:

2016-09-29 08:20:34.361 INFO 21256 --- [ kafka-binder-1] o.s.cloud.bus.event.RefreshListener : Received remote refresh request. Keys refreshed [from]

RefreshListener监听类记录了收到远程刷新请求,并刷新了from属性的日志。
在上面的例子中,由于Kafka、ZooKeeper均运行于本地,所以我们没有在测试程序中通过配置信息来指定Kafka和ZooKeeper的配置信息,就完成了本地消息总线的试验。但是我们实际应用中,Kafka和ZooKeeper一般都会独立部署,所以在应用中都需要来为Kafka和ZooKeeper配置一些连接信息等。Kafka的整合与RabbitMQ不同,在Spring Boot 1.3.7中并没有直接提供的Starter模块,而是采用了Spring Cloud Stream的Kafka模块,所以对于Kafka的配置均采用了spring.cloud.stream.kafka的前缀。java B2B2C Springcloud电子商城系统

]]>
java B2B2C Springcloud电子商城系统-通过消息队列传输zipkin日志 http://blog.okbase.net/iteye01/archive/56053.html iteye01 2019/1/7 16:15:50 一、zipkin服务端配置
需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六
1.引入依赖

//===========消息队列方式的依赖=============
//此依赖会自动引入spring-cloud-sleuth-stream并且引入zipkin的依赖包
compile("org.springframework.cloud:spring-cloud-sleuth-zipkin-stream")
compile("org.springframework.cloud:spring-cloud-starter-stream-rabbit")
compile('io.zipkin.java:zipkin-autoconfigure-ui')
//保存到数据库需要如下依赖
compile('mysql:mysql-connector-java')
compile('org.springframework.boot:spring-boot-starter-jdbc')

2.启动类配置
在启动类加上@EnableZipkinStreamServer

@EnableZipkinStreamServer
@SpringBootApplication
public class ZipkinApplication {

public static void main(String[] args) {
SpringApplication.run(ZipkinApplication.class, args);
}

}

3.配置文件
完整配置如下,根据自己的设置进行修改即可

#================================基础配置==============================
#应用名
spring.application.name=zipking-server-v1
#端口
server.port=9411
#================================消息队列==============================
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#================================数据源配置===========================
#zipkin数据保存到数据库中需要进行如下配置
#表示当前程序不使用sleuth
spring.sleuth.enabled=false
#表示zipkin数据存储方式是mysql
zipkin.storage.type=mysql
#数据库脚本创建地址,当有多个是可使用[x]表示集合第几个元素
spring.datasource.schema[0]=classpath:/zipkin.sql
#spring boot数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/zipkin
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.initialize=true
spring.datasource.continue-on-error=true

4.数据库文件
在本地数据库建立一个数据库,起名为zipkin。
在resources目录下新建zipkin.sql文件,内容如下

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for zipkin_annotations
-- ----------------------------
CREATE TABLE `zipkin_annotations` (
`trace_id` bigint(20) NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',
`span_id` bigint(20) NOT NULL COMMENT 'coincides with zipkin_spans.id',
`a_key` varchar(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1',
`a_value` blob COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB',
`a_type` int(11) NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',
`a_timestamp` bigint(20) DEFAULT NULL COMMENT 'Used to implement TTL; 
Annotation.timestamp or zipkin_spans.timestamp', `endpoint_ipv4` int(11) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_ipv6` binary(16) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address', `endpoint_port` smallint(6) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null', `endpoint_service_name` varchar(255) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null', UNIQUE KEY `trace_id` (`trace_id`,`span_id`,`a_key`,`a_timestamp`) COMMENT 'Ignore insert on duplicate', KEY `trace_id_2` (`trace_id`,`span_id`) COMMENT 'for joining with zipkin_spans', KEY `trace_id_3` (`trace_id`) COMMENT 'for getTraces/ByIds', KEY `endpoint_service_name` (`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames', KEY `a_type` (`a_type`) COMMENT 'for getTraces', KEY `a_key` (`a_key`) COMMENT 'for getTraces' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED; -- ---------------------------- -- Table structure for zipkin_dependencies -- ---------------------------- CREATE TABLE `zipkin_dependencies` ( `day` date NOT NULL, `parent` varchar(255) NOT NULL, `child` varchar(255) NOT NULL, `call_count` bigint(20) DEFAULT NULL, UNIQUE KEY `day` (`day`,`parent`,`child`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED; -- ---------------------------- -- Table structure for zipkin_spans -- ---------------------------- CREATE TABLE `zipkin_spans` ( `trace_id` bigint(20) NOT NULL, `id` bigint(20) NOT NULL, `name` varchar(255) NOT NULL, `parent_id` bigint(20) DEFAULT NULL, `debug` bit(1) DEFAULT NULL, `start_ts` bigint(20) DEFAULT NULL COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL', `duration` bigint(20) DEFAULT NULL COMMENT 'Span.duration(): micros used for minDuration and maxDuration query', UNIQUE KEY `trace_id` (`trace_id`,`id`) COMMENT 'ignore insert on duplicate', KEY `trace_id_2` (`trace_id`,`id`) COMMENT 'for joining with zipkin_annotations', KEY `trace_id_3` (`trace_id`) COMMENT 'for getTracesByIds', KEY `name` (`name`) COMMENT 'for getTraces and getSpanNames', KEY `start_ts` (`start_ts`) COMMENT 'for getTraces ordering and range' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED;

zipkin的服务端就配置完成了,别忘记重新刷新下项目。

二、zipkin客户端配置
引入依赖

compile("org.springframework.cloud:spring-cloud-sleuth-zipkin-stream")
compile("org.springframework.cloud:spring-cloud-starter-stream-rabbit")

然后客户端就配置完成了

三、启动
这时候分别启动客户端和服务端,在日志中可以看到初始化mq连接。
然后访问一个客户端的rest接口,看看打开服务端locahost:9411,看看有没有生成记录,这时看看数据库,会建立三个表。就说明我们配置成功了。java B2B2C Springcloud仿淘宝电子商城系统

]]>
java B2B2C Springcloud仿淘宝电子商城系统-Zipkin服务端配置 http://blog.okbase.net/iteye01/archive/56052.html iteye01 2019/1/7 16:13:29 一、引入依赖
需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六

//起步依赖
compile('org.springframework.cloud:spring-cloud-starter')
//zipkin
compile('io.zipkin.java:zipkin-server')
//zipkin的web界面
compile('io.zipkin.java:zipkin-autoconfigure-ui')
//保存到数据库需要如下依赖
compile('io.zipkin.java:zipkin-autoconfigure-storage-mysql')
compile('mysql:mysql-connector-java')
compile('org.springframework.boot:spring-boot-starter-jdbc')

二、启动类配置
加上@EnableZipkinServer注解。

@EnableZipkinServer
@SpringBootApplication
public class ZipkinApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinApplication.class, args);
}

}

二、配置文件

application.properties

#应用名
spring.application.name=zipking-server-v1
#端口
server.port=9411
#zipkin数据保存到数据库中需要进行如下配置
#表示当前程序不使用sleuth
spring.sleuth.enabled=false
#表示zipkin数据存储方式是mysql
zipkin.storage.type=mysql
#数据库脚本创建地址,当有多个是可使用[x]表示集合第几个元素
spring.datasource.schema[0]=classpath:/zipkin.sql
#spring boot数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/zipkin
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.initialize=true
spring.datasource.continue-on-error=true

需要在数据库中新建zipkin的库

三、创建sql脚本文件
在resources目录下新建zipkin.sql文件,内容如下

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for zipkin_annotations
-- ----------------------------
CREATE TABLE `zipkin_annotations` (
`trace_id` bigint(20) NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',
`span_id` bigint(20) NOT NULL COMMENT 'coincides with zipkin_spans.id',
`a_key` varchar(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1',
`a_value` blob COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB',
`a_type` int(11) NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',
`a_timestamp` bigint(20) DEFAULT NULL COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',
`endpoint_ipv4` int(11) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null',
`endpoint_ipv6` binary(16) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address',
`endpoint_port` smallint(6) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null',
`endpoint_service_name` varchar(255) DEFAULT NULL COMMENT 'Null when Binary/Annotation.endpoint is null',
UNIQUE KEY `trace_id` (`trace_id`,`span_id`,`a_key`,`a_timestamp`) COMMENT 'Ignore insert on duplicate',
KEY `trace_id_2` (`trace_id`,`span_id`) COMMENT 'for joining with zipkin_spans',
KEY `trace_id_3` (`trace_id`) COMMENT 'for getTraces/ByIds',
KEY `endpoint_service_name` (`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames',
KEY `a_type` (`a_type`) COMMENT 'for getTraces',
KEY `a_key` (`a_key`) COMMENT 'for getTraces'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED;

-- ----------------------------
-- Table structure for zipkin_dependencies
-- ----------------------------
CREATE TABLE `zipkin_dependencies` (
`day` date NOT NULL,
`parent` varchar(255) NOT NULL,
`child` varchar(255) NOT NULL,
`call_count` bigint(20) DEFAULT NULL,
UNIQUE KEY `day` (`day`,`parent`,`child`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED;

-- ----------------------------
-- Table structure for zipkin_spans
-- ----------------------------
CREATE TABLE `zipkin_spans` (
`trace_id` bigint(20) NOT NULL,
`id` bigint(20) NOT NULL,
`name` varchar(255) NOT NULL,
`parent_id` bigint(20) DEFAULT NULL,
`debug` bit(1) DEFAULT NULL,
`start_ts` bigint(20) DEFAULT NULL COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',
`duration` bigint(20) DEFAULT NULL COMMENT 'Span.duration(): micros used for minDuration and maxDuration query',
UNIQUE KEY `trace_id` (`trace_id`,`id`) COMMENT 'ignore insert on duplicate',
KEY `trace_id_2` (`trace_id`,`id`) COMMENT 'for joining with zipkin_annotations',
KEY `trace_id_3` (`trace_id`) COMMENT 'for getTracesByIds',
KEY `name` (`name`) COMMENT 'for getTraces and getSpanNames',
KEY `start_ts` (`start_ts`) COMMENT 'for getTraces ordering and range'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED;

刷新项目依赖,启动项目不报错则说明正常。java B2B2C Springcloud电子商城系统

 

]]>
java B2B2C Springcloud多租户电子商城系统-spring cloud bus原理总结 http://blog.okbase.net/iteye01/archive/56051.html iteye01 2019/1/7 16:09:31 1、spring cloud bus

  spring cloud是按照spring的配置对一系列微服务框架的集成,spring cloud bus是其中一个微服务框架,用于实现微服务之间的通信。
  需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六
  spring cloud bus整合 java的事件处理机制和消息中间件消息的发送和接受,主要由发送端、接收端和事件组成。针对不同的业务需求,可以设置不同的事件,发送端发送事件,接收端接受相应的事件,并进行相应的处理。

2、spring cloud bus实战

网上关于spring cloud bus的demo相当多,此处就不赘述了。

3、原理

spring cloud bus整合了java的事件处理机制和消息中间件,所以下面就从这两个方面来说明spring cloud bus的原理。

如图所示,作如下解释:

(1)完整流程:发送端(endpoint)构造事件event,将其publish到context上下文中(spring cloud bus有一个父上下文,bootstrap),然后将事件发送到channel中(json串message),接收端从channel中获取到message,将message转为事件event(转换过程这一块没有深究),然后将event事件publish到context上下文中,最后接收端(Listener)收到event,调用服务进行处理。整个流程中,只有发送/接收端从context上下文中取事件和发送事件是需要我们在代码中明确写出来的,其它部分都由框架封装完成。

(2)先大致描述了一下流程,关于封装的部分流程,我们基本上可以在BusAutoConfiguration.class中找到,下面的代码都是这个类中的代码

  @EventListener(classes = RemoteApplicationEvent.class)
public void acceptLocal(RemoteApplicationEvent event) {
if (this.serviceMatcher.isFromSelf(event)
&& !(event instanceof AckRemoteApplicationEvent)) {
this.cloudBusOutboundChannel.send(MessageBuilder.withPayload(event).build());
}
}

这是封装了java事件处理机制,当收到RemoteApplicationEvent时,如果这个event是从这个服务发出的,而且不是ack事件,那么就会把这个事件发送到channel中。

  @StreamListener(SpringCloudBusClient.INPUT)
public void acceptRemote(RemoteApplicationEvent event) {
if (event instanceof AckRemoteApplicationEvent) {
if (this.bus.getTrace().isEnabled() && !this.serviceMatcher.isFromSelf(event)
&& this.applicationEventPublisher != null) {
this.applicationEventPublisher.publishEvent(event);
}
// If it's an ACK we are finished processing at this point
return;
}
if (this.serviceMatcher.isForSelf(event)
&& this.applicationEventPublisher != null) {
if (!this.serviceMatcher.isFromSelf(event)) {
this.applicationEventPublisher.publishEvent(event);
}
if (this.bus.getAck().isEnabled()) {
AckRemoteApplicationEvent ack = new AckRemoteApplicationEvent(this,
this.serviceMatcher.getServiceId(),
this.bus.getAck().getDestinationService(),
event.getDestinationService(), event.getId(), event.getClass());
this.cloudBusOutboundChannel
.send(MessageBuilder.withPayload(ack).build());
this.applicationEventPublisher.publishEvent(ack);
}
}
if (this.bus.getTrace().isEnabled() && this.applicationEventPublisher != null) {
// We are set to register sent events so publish it for local consumption,
// irrespective of the origin
this.applicationEventPublisher.publishEvent(new SentApplicationEvent(this,
event.getOriginService(), event.getDestinationService(),
event.getId(), event.getClass()));
}
}

@StreamListener这个标签有兴趣的可以去了解一下。这个方法就是从channel中取出事件进行处理的过程(message转事件部分需要自行了解,我没有深入研究),根据事件的类型、发送方和接收方来处理这个事件:如果是ack事件,发送到context上下文中;如果自己是接收端且不是发送端,就会将事件发送到context上下文。

(3)消息中间件可以采用rabbitmq、kafka之类的。java B2B2C Springcloud仿淘宝电子商城系统

 

]]>