首页 文章 精选 留言 我的

精选列表

搜索[SpringBoot4],共10000篇文章
优秀的个人博客,低调大师

[Spring cloud 一步步实现广告系统] 4. 通用代码模块设计

一个大的系统,在代码的复用肯定是必不可少的,它能解决: 统一的响应处理(可以对外提供统一的响应对象包装) graph LR HTTP-->|HttpRequest|RestController RestController-->|HttpResponse -> JSON|HTTP 统一的异常处理(可以将业务异常统一收集处理) graph TB subgraph 处理过程 AdCommonException -->|RestControllerAdvice| HttpRequest end subgraph HttpResponse RestControllerAdvice -->|统一返回| JSON end 通用代码定义、配置定义(通用的配置信息放在统一的代码管理中,便于维护和更新) 创建项目 mscx-ad-common POM文件 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>mscx-ad</artifactId> <groupId>com.sxzhongf</groupId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> <packaging>jar</packaging> <groupId>com.sxzhongf</groupId> <artifactId>mscx-ad-common</artifactId> <version>1.0-SNAPSHOT</version> <name>Common-Service</name> <description>公共逻辑 and 帮助类</description> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.58</version> </dependency> <!-- --> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> </dependencies> <!--maven编译插件--> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 项目结构 vo (统一响应对象package) advice (bean 增强package ) > Spring支持五种类型的增强或通知(Advice) > - Before(方法执行前) `org.apringframework.aop.MethodBeforeAdvice` > - AfterReturning(方法返回后) `org.springframework.aop.AfterReturningAdvice` > - After-throwing(异常抛出后) `org.springframework.aop.ThrowsAdviceArround`环绕,即方法前后 `org.aopaliance.intercept.MethodInterceptor` > 引介,不常用 `org.springframework.aop.IntroductionInterceptor` > 具体可参考:[细说advice,advisor](https://www.jianshu.com/p/1dd6a26c881b) annotation config exception utils export 通用响应编码 创建通用返回对象 /** * @Data是下属注解的组合注解 * * @see Getter * @see Setter * @see RequiredArgsConstructor * @see ToString * @see EqualsAndHashCode * @see lombok.Value */ @Data @NoArgsConstructor //无参构造函数 @AllArgsConstructor //全参构造函数 public class CommonResponse<T> implements Serializable { private Integer code = 0; private String message = "success"; /** * 具体的数据对象信息 */ private T data; public CommonResponse(Integer code, String message) { this.code = code; this.message = message; } public CommonResponse(T data) { this.data = data; } } 在advice包中实现对响应的统一拦截com.sxzhongf.ad.common.advice.CommonResponseDataAdvice,参考 ResponseBodyAdvice, RestControllerAdvice 可查看源码org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice @RestControllerAdvice public class CommonResponseDataAdvice implements ResponseBodyAdvice<Object> { /** * 判断是否需要对响应进行处理 * * @return false -> 不处理,true -> 处理 */ @Override public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> converterType) { // // //获取当前处理请求的controller的方法 // String methodName = methodParameter.getMethod().getName().toLowerCase(); // // 不拦截/不需要处理返回值 的方法 // String method = "login"; //如登录 // //不拦截 // return !method.equals(methodName); // 如果类上标记了@IgnoreResponseAdvice,则不拦截 if (methodParameter.getDeclaringClass().isAnnotationPresent(IgnoreResponseAdvice.class)) { return false; } // 如果方法上标记了@IgnoreResponseAdvice,则不拦截 if (methodParameter.getMethod().isAnnotationPresent(IgnoreResponseAdvice.class)) { return false; } //对响应进行处理,执行beforeBodyWrite方法 return true; } /** * 目的 拦截CommonResponse * * @param body 原始的Controller需要返回的数据 */ @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { CommonResponse<Object> commonResponse = new CommonResponse<>(); if (null == body) { return commonResponse; } else if (body instanceof CommonResponse) { commonResponse = (CommonResponse<Object>) body; } else { commonResponse.setData(body); } return commonResponse; } } 我们在annotation包下面添加一个注解com.sxzhongf.ad.common.annotation.IgnoreResponseAdvice,用它来标柱是否需要支持上面的统一返回拦截。 /** * IgnoreResponseAdvice for 标示需要忽略拦截动作 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a> */ //ElementType.TYPE 表示该注解可用于class //ElementType.METHOD 表示可用于方法 @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface IgnoreResponseAdvice { } 通用异常处理 异常处理也是统一的,那么同样就要使用到RestControllerAdvice,同时,需要使用的Spring 的ExceptionHandler进行异常处理 创建统一异常拦截类 /** * GlobalExceptionAdvice for 全局统一异常拦截 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a> * @see RestControllerAdvice * @see ExceptionHandler */ @RestControllerAdvice public class GlobalExceptionAdvice { /** * 对 {@link AdException} 进行统一处理 * {@link ExceptionHandler} 对指定的异常进行拦截 * 可优化: * 定义多种类异常,实现对应的异常处理, * 例如: * <ul> * <li> * 推广单元操作异常,抛出 AdUnitException * </li> * <li> * Binlog 解析异常,抛出 BinlogException * </li> * </ul> * 拦截Spring Exception 使用 {@link ExceptionHandler}注解 */ @ExceptionHandler(value = AdException.class) public CommonResponse<String> handlerAdException(HttpServletRequest request, AdException ex) { CommonResponse<String> response = new CommonResponse<>(-1, "business error"); response.setData(ex.getMessage()); return response; } } 创建通用异常类 /** * AdException for 统一异常处理类 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a> */ public class AdException extends Exception { public AdException(String message) { super(message); } } 通用配置信息 通过HTTP消息转换器HttpMessageConverter,实现对象转换,Java Object -> HTTP 数据流 新增WebConfiguration,我们通过实现org.springframework.web.servlet.config.annotation.WebMvcConfigurer来定制和修改Spring MVC的配置信息。 /** * WebConfiguration for 对Spring的配置和行为进行定制修改 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a> * @see WebMvcConfigurer */ @Configuration public class WebConfiguration implements WebMvcConfigurer { /** * 匹配路由请求规则 */ @Override public void configurePathMatch(PathMatchConfigurer configurer) { } /** * 注册自定义的Formatter 和 Convert */ @Override public void addFormatters(FormatterRegistry registry) { } /** * 添加静态资源处理器 */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { } /** * 添加自定义视图控制器 */ @Override public void addViewControllers(ViewControllerRegistry registry) { } /** * 添加自定义方法参数处理器 */ @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { } /** * 配置消息转换器 */ @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { //清空所有转换器 converters.clear(); // Java Obj -> Json Obj (http header: application/json) converters.add(new MappingJackson2HttpMessageConverter()); } }

优秀的个人博客,低调大师

程序员笔记|编写高性能的Java代码需要注意的4个问题

一、并发 Unable to create new native thread …… 问题1:Java中创建一个线程消耗多少内存? 每个线程有独自的栈内存,共享堆内存 问题2:一台机器可以创建多少线程? CPU,内存,操作系统,JVM,应用服务器 我们编写一段示例代码,来验证下线程池与非线程池的区别: //线程池和非线程池的区别 public class ThreadPool { public static int times = 100;//100,1000,10000 public static ArrayBlockingQueue arrayWorkQueue = new ArrayBlockingQueue(1000); public static ExecutorService threadPool = new ThreadPoolExecutor(5, //corePoolSize线程池中核心线程数 10, 60, TimeUnit.SECONDS, arrayWorkQueue, new ThreadPoolExecutor.DiscardOldestPolicy() ); public static void useThreadPool() { Long start = System.currentTimeMillis(); for (int i = 0; i < times; i++) { threadPool.execute(new Runnable() { public void run() { System.out.println("说点什么吧..."); } }); } threadPool.shutdown(); while (true) { if (threadPool.isTerminated()) { Long end = System.currentTimeMillis(); System.out.println(end - start); break; } } } public static void createNewThread() { Long start = System.currentTimeMillis(); for (int i = 0; i < times; i++) { new Thread() { public void run() { System.out.println("说点什么吧..."); } }.start(); } Long end = System.currentTimeMillis(); System.out.println(end - start); } public static void main(String args[]) { createNewThread(); //useThreadPool(); } } 启动不同数量的线程,然后比较线程池和非线程池的执行结果: 非线程池 线程池 100次 16毫秒 5ms的 1000次 90毫秒 28ms 10000次 1329ms 164ms 结论:不要new Thread(),采用线程池 非线程池的缺点: 每次创建性能消耗大 无序,缺乏管理。容易无限制创建线程,引起OOM和死机 1.1 使用线程池要注意的问题 避免死锁,请尽量使用CAS 我们编写一个乐观锁的实现示例: public class CASLock { public static int money = 2000; public static boolean add2(int oldm, int newm) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } if (money == oldm) { money = money + newm; return true; } return false; } public synchronized static void add1(int newm) { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } money = money + newm; } public static void add(int newm) { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } money = money + newm; } public static void main(String args[]) { Thread one = new Thread() { public void run() { //add(5000) while (true) { if (add2(money, 5000)) { break; } } } }; Thread two = new Thread() { public void run() { //add(7000) while (true) { if (add2(money, 7000)) { break; } } } }; one.start(); two.start(); try { one.join(); two.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(money); } } 使用ThreadLocal要注意 ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal没有外部强引用来引用它,那么系统 GC 的时候,这个ThreadLocal势必会被回收,这样一来,ThreadLocalMap中就会出现key为null的Entry,就没有办法访问这些key为null的Entry的value,如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永远无法回收,造成内存泄漏。 我们编写一个ThreadLocalMap正确使用的示例: //ThreadLocal应用实例 public class ThreadLocalApp { public static final ThreadLocal threadLocal = new ThreadLocal(); public static void muti2() { int i[] = (int[]) threadLocal.get(); i[1] = i[0] * 2; threadLocal.set(i); } public static void muti3() { int i[] = (int[]) threadLocal.get(); i[2] = i[1] * 3; threadLocal.set(i); } public static void muti5() { int i[] = (int[]) threadLocal.get(); i[3] = i[2] * 5; threadLocal.set(i); } public static void main(String args[]) { for (int i = 0; i < 5; i++) { new Thread() { public void run() { int start = new Random().nextInt(10); int end[] = {0, 0, 0, 0}; end[0] = start; threadLocal.set(end); ThreadLocalApp.muti2(); ThreadLocalApp.muti3(); ThreadLocalApp.muti5(); //int end = (int) threadLocal.get(); System.out.println(end[0] + " " + end[1] + " " + end[2] + " " + end[3]); threadLocal.remove(); } }.start(); } } } 1.2 线程交互—线程不安全造成的问题 经典的HashMap死循环造成CPU100%问题 我们模拟一个HashMap死循环的示例: //HashMap死循环示例 public class HashMapDeadLoop { private HashMap hash = new HashMap(); public HashMapDeadLoop() { Thread t1 = new Thread() { public void run() { for (int i = 0; i < 100000; i++) { hash.put(new Integer(i), i); } System.out.println("t1 over"); } }; Thread t2 = new Thread() { public void run() { for (int i = 0; i < 100000; i++) { hash.put(new Integer(i), i); } System.out.println("t2 over"); } }; t1.start(); t2.start(); } public static void main(String[] args) { for (int i = 0; i < 1000; i++) { new HashMapDeadLoop(); } System.out.println("end"); } } https://coolshell.cn/articles/9606.html HashMap死循环发生后,我们可以在线程栈中观测到如下信息: /HashMap死循环产生的线程栈 Thread-281" #291 prio=5 os_prio=31 tid=0x00007f9f5f8de000 nid=0x5a37 runnable [0x0000700006349000] java.lang.Thread.State: RUNNABLE at java.util.HashMap$TreeNode.split(HashMap.java:2134) at java.util.HashMap.resize(HashMap.java:713) at java.util.HashMap.putVal(HashMap.java:662) at java.util.HashMap.put(HashMap.java:611) at com.example.demo.HashMapDeadLoop$2.run(HashMapDeadLoop.java:26) 应用停滞的死锁,Spring3.1的deadlock 问题 我们模拟一个死锁的示例: //死锁的示例 public class DeadLock { public static Integer i1 = 2000; public static Integer i2 = 3000; public static synchronized Integer getI2() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return i2; } public static void main(String args[]) { Thread one = new Thread() { public void run() { synchronized (i1) { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (i2) { System.out.println(i1 + i2); } } } }; one.start(); Thread two = new Thread() { public void run() { synchronized (i2) { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (i1) { System.out.println(i1 + i2); } } } }; two.start(); } } 死锁发生后,我们可以在线程栈中观测到如下信息: //死锁时产生堆栈 "Thread-1": at com.example.demo.DeadLock$2.run(DeadLock.java:47) - waiting to lock (a java.lang.Integer) - locked (a java.lang.Integer) "Thread-0": at com.example.demo.DeadLock$1.run(DeadLock.java:31) - waiting to lock (a java.lang.Integer) - locked (a java.lang.Integer) Found 1 deadlock. 1.3 基于JUC的优化示例 一个计数器的优化,我们分别用Synchronized,ReentrantLock,Atomic三种不同的方式来实现一个计数器,体会其中的性能差异 //示例代码 public class SynchronizedTest { public static int threadNum = 100; public static int loopTimes = 10000000; public static void userSyn() { //线程数 Syn syn = new Syn(); Thread[] threads = new Thread[threadNum]; //记录运行时间 long l = System.currentTimeMillis(); for (int i = 0; i < threadNum; i++) { threads[i] = new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < loopTimes; j++) { //syn.increaseLock(); syn.increase(); } } }); threads[i].start(); } //等待所有线程结束 try { for (int i = 0; i < threadNum; i++) threads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("userSyn" + "-" + syn + " : " + (System.currentTimeMillis() - l) + "ms"); } public static void useRea() { //线程数 Syn syn = new Syn(); Thread[] threads = new Thread[threadNum]; //记录运行时间 long l = System.currentTimeMillis(); for (int i = 0; i < threadNum; i++) { threads[i] = new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < loopTimes; j++) { syn.increaseLock(); //syn.increase(); } } }); threads[i].start(); } //等待所有线程结束 try { for (int i = 0; i < threadNum; i++) threads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("userRea" + "-" + syn + " : " + (System.currentTimeMillis() - l) + "ms"); } public static void useAto() { //线程数 Thread[] threads = new Thread[threadNum]; //记录运行时间 long l = System.currentTimeMillis(); for (int i = 0; i < threadNum; i++) { threads[i] = new Thread(new Runnable() { @Override public void run() { for (int j = 0; j < loopTimes; j++) { Syn.ai.incrementAndGet(); } } }); threads[i].start(); } //等待所有线程结束 try { for (int i = 0; i < threadNum; i++) threads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("userAto" + "-" + Syn.ai + " : " + (System.currentTimeMillis() - l) + "ms"); } public static void main(String[] args) { SynchronizedTest.userSyn(); SynchronizedTest.useRea(); SynchronizedTest.useAto(); } } class Syn { private int count = 0; public final static AtomicInteger ai = new AtomicInteger(0); private Lock lock = new ReentrantLock(); public synchronized void increase() { count++; } public void increaseLock() { lock.lock(); count++; lock.unlock(); } @Override public String toString() { return String.valueOf(count); } } 结论,在并发量高,循环次数多的情况,可重入锁的效率高于Synchronized,但最终Atomic性能最好。 二、通信 2.1 数据库连接池的高效问题 一定要在finally中close连接 一定要在finally中release连接 2.2 OIO/NIO/AIO OIO NIO AIO 类型 阻塞 非阻塞 非阻塞 使用难度 简单 复杂 复杂 可靠性 差 高 高 吞吐量 低 高 高 结论:我性能有严苛要求下,尽量应该采用NIO的方式进行通信。 2.3 TIME_WAIT(client),CLOSE_WAIT(server)问题 反应:经常性的请求失败 获取连接情况 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' TIME_WAIT:表示主动关闭,优化系统内核参数可。 CLOSE_WAIT:表示被动关闭。 ESTABLISHED:表示正在通信 解决方案:二阶段完成后强制关闭 2.4 串行连接,持久连接(长连接),管道化连接 结论: 管道连接的性能最优异,持久化是在串行连接的基础上减少了打开/关闭连接的时间。 管道化连接使用限制: 1、HTTP客户端无法确认持久化(一般是服务器到服务器,非终端使用); 2、响应信息顺序必须与请求信息顺序一致; 3、必须支持幂等操作才可以使用管道化连接. 三、数据库操作 必须要有索引(特别注意按时间查询) 单条操作or批量操作 注:很多程序员在写代码的时候随意采用了单条操作的方式,但在性能要求前提下,要求采用批量操作方式。 四、JVM 4.1 CPU标高的一般处理步骤 top查找出哪个进程消耗的cpu高 top –H –p查找出哪个线程消耗的cpu高 记录消耗cpu最高的几个线程 printf %x 进行pid的进制转换 jstack记录进程的堆栈信息 找出消耗cpu最高的线程信息 4.2 内存标高(OOM)一般处理步骤 jstat命令查看FGC发生的次数和消耗的时间,次数越多,耗时越长说明存在问题; 连续查看jmap –heap 查看老生代的占用情况,变化越大说明程序存在问题; 使用连续的jmap –histo:live 命令导出文件,比对加载对象的差异,差异部分一般是发生问题的地方。 4.3 GC引起的单核标高 单个CPU占用率高,首先从GC查起。 4.4 常见SY标高 线程上下文切换频繁 线程太多 锁竞争激烈 4.5 Iowait标高 如果IO的CPU占用很高,排查涉及到IO的程序,比如把OIO改造成NIO。 4.6 抖动问题 原因:字节码转为机器码需要占用CPU时间片,大量的CPU在执行字节码时,导致CPU长期处于高位; 现象:“C2 CompilerThread1” daemon,“C2 CompilerThread0” daemon CPU占用率最高; 解决办法:保证编译线程的CPU占比。 作者:梁鑫 来源:宜信技术学院

优秀的个人博客,低调大师

Istio流量管理实践之(4): 基于CoreDNS Plugin扩展实现Istio Service Entry的DNS寻址

CoreDNS 及其Plugin扩展 CoreDNS是一个CNCF下的孵化级项目,它的前身是SkyDNS,主要目的是构建一个快速灵活的 DNS 服务器,让用户可以通过不同方式访问和使用 DNS 内的数据。基于 Caddy 服务器框架,CoreDNS 实现了一个插件链的架构,将大量逻辑抽象成插件Plugin的形式暴露给使用者,每个插件都执行DNS功能,例如Kubernetes 的 DNS 服务发现、Prometheus 监控等。 除了插件化之外,CoreDNS还有以下特性: 配置简单化: 引入表达力更强的 DSL,即 Corefile 形式的配置文件(也是基于 Caddy 框架开发); 一体化的解决方案:区别于 kube-dns,CoreDNS 编译出来就是一个单独的二进制可执行文件,内置了 cache,backend storage ,h

优秀的个人博客,低调大师

大数据小视角4:小议Lambda 与 Kappa 架构,不可变数据的计算探索

这个系列文章之前因为私事荒废了很久,继续更新~~之前与老大谈论架构时,老大和我聊了聊分布式数据处理之中的Lambda结构,之前在《Designing Data-Intensive Applications》这本书之中,作者 Martin Kleppmann也在文中涉及到了通过重型批处理与灵活的流处理相结合的方式来构建分布式计算系统。所以这次也是借这个机会重新梳理Lambda架构与后续由Jay Kreps提出改进的Kappa架构,结合个人对于数据系统的思考,展开聊一聊分布式计算系统的一些设计思路。由不足之处,望多多指教........ 1.Lambda架构 首先我们来看看什么是Lambda架构,Lambda演算在编程语言之中是一个编程范式,它遵循如下几个特点: 1、数据的不可变性,任何对于数据的操作是没有副作用。 2、数据的无依赖性,即对函数提供同样的输入,那么函数总是返回同样的结果。 3、函数是First Class,函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。 来自Twitter的Nathan Marz,Marz认为进行计算处理的大数据框架的本质逻辑与函数式编程的思路是不谋而合,所以Marz根据自己多年进行分布式数据系统开发的经验总结提出了Lambda架构。(Marz大神是AFS顶级项目Storm的作者,Storm作为一个优秀的分布式流处理系统)所以接下来我们来看看Marz所提出的Lambda架构是怎么样: Lambda架构说起来也很简单,就是通过分布式系统的组件搭建,设计出一个具有鲁棒性,可扩展,低延时的分布式计算系统。之所以称之为Lambda架构,就是它最为核心的点就是理由了数据处理过程之中的不可变性与无依赖性。下图展现了一个典型的Lambda架构的分层逻辑: 由上图可以看到,一个典型的Lambda架构的核心分为三个层次:Batch Layer,Speed Layer和Serving Layer。 Batch Layer Speed Layer Serving Layer 我们来梳理一下他们是如何分工协助的:首先new data作为整个数据系统的数据源头,Batch Layer作为数据的批处理层次对原始数据进行加工与处理,并且将处理的数据结果的Batch View输入到Serving Layer。(这里对应的是全量数据)Speed Layer对于实时增加的数据进行处理,生成对增量数据计算结果的Realtime Views。(这里对应的是增量数据)最终用户查询是通过Batch View与Realtime View相结合的形式将最终结果呈现出来。 并且随着时间的推移,Batch View的计算结果会逐渐替代Realtime View,而业务层可以低延迟的访问由Serving Layer提供的Batch View,也可以通过Realtime View实时反馈业务结果。 我们可以看到在Lambda架构之中,所有的数据都需要满足满足不可变性与无依赖性,出现任何数据问题时,(如出错,丢失等)只需要重新跑一遍算法就可以恢复所需的数据了。 业务场景理解 下面笔者利用一个业务场景简单阐述一下Lambda模式,如下的业务场景只是基于笔者对电商推荐的理解所表述的,对应电商未必实际之中就是采取笔者所阐述的模式: 1:下图是笔者访问x宝网首页所展示的广告页面: 对于这个推荐数据,可以理解为通过Batch Layer对我个人历史数据进行处理之后得出的Batch View推荐。(例如跑Spark Mllib或是Hadoop Mahout对历史数据进行分析推荐的结果,跑这类算法通常费时费力,可以通过提前计算的方式存入MySQL等,后续用户访问时可以直接调用) 2:接下来笔者在x宝网搜索了MacBook pro和ThinkPad x207,对于实时搜索的数据,可以作为流数据实时的通过Speed Layer进行处理。(例如Storm这样的流处理器) 3: 笔者切换回到x宝网的首页,发现多了一个推荐广告项目:Dell 8代CPU专业级显卡,晒单还送爱奇艺半年卡。显然实时流的Realtime View与Batch View共同组成的x宝网的推荐首页内容,很好的反馈了用户的实时需求: 小结 Lambda架构结合了实时处理与批处理的结果,很好的反馈了查询需求,并且在速度和可靠性之间求取了平衡,具有足够的扩展性。在Lambda架构之中,所有的查询都可以定位成一个函数: Query = Function(Data) 而Lambda架构将数据和计算系统进行细分: Query = Batch(Old_Data) + RealTime(New_Data) 但是这种架构同样存在一些问题:需要运维两套不同的计算系统,并且合并查询结果,这一定程序上带来了复杂性的增加 2.Kappa架构 Lambda架构诞生之后,来自Linkedln的技术主管Jay Kreps提出了一些质疑,并在Lambda架构之上提出自己的改进版本,将其命名为Kappa架构。 Lambda架构最麻烦的问题就在于:新的逻辑需要两次编码,并且在两个系统中运行和调试代码,需要多运维一个额外的系统。所以Kreps认为Lambda架构试图在两个不同编程范式的顶部建立一个抽象层是非常难的。 而Kappa架构尝试通过一个流处理系统来处理上述两种逻辑,我们来看看Kappa架构是怎么样去设计的: Kappa架构通过流处理系统的并行机制,来提高并行以实现重复处理。但是很多人会觉得流式处理对于历史数据的高吞吐量会力不从心,这里Kreps给出的解决方案是:仅仅重复处理的完整日志数据。加入需要重复处理30天数据,就利用Kafka保留到30天。 所以这里是开辟另个流式处理来处理新的数据,输出数据是直接输出到一个新的输出表。当这第二个流式处理完成之后,切换到新的表中进行读取,然后停止旧的流式处理,再删除旧的输出表。 同样的,笔者上文举的例子,同样也能通过Kappa架构来实现购物的广告展示。Kappa架构最为核心的是通过一个范式解决需要共同解决的问题。同时不需要引入额外计算系统进行运维。 3.小结 到此为止,笔者也大致聊完两种不同分布式计算系统的架构。笔者认为Lambda架构是一个优秀的解决分布式计算的架构,但需要处理运维不同的大数据系统,并且额外编码逻辑,对于开发者与运维人员都是一个较大的考验。而Kappa架构简化了这个模型,但是对于数据处理总归很难拿出重型的批处理做一个完整数据计算,所以计算结果的准确性是有所限缩的。(也就是对于业务场景是挑剔的,我想也没有一种架构是解决问题的银弹,之间的取舍需要我们开发人员进行完整的评估~~)而Spark能够通过一个计算框架同时解决批处理计算与流计算的问题,是很值得开发与运维人员所关注的.........

优秀的个人博客,低调大师

云为信息化节成本4成 第8届云计算大会发布

我国云市场己近1500亿元,其中公有云占47%,私有云达26%,为大众创业万众创新提供了双创基础平台,为企业信息化节约了四成成本。这是昨天上午开幕的第八届云计算大会上,信息化工业部软件服务司谢少峰司長在主题报告中发布的。 由中国电子学会主办,ZD至顶网协办的第八届中国云计算大会为期三天,怀进鹏部長到会并首先致辞之后在谢少峰司長做主题报告,他全面总结了当前中国云计算纳现状,他特别提出中国云计算处理并发业务峰值达到了世界先进水、云计算中心综合利用节能、在行业应用中广泛带动产业升级、成为助推传统产业创新的能量。但是他也指出,且前中国云计算面临三个挑战,一是云计算的需求并沒有完全释放出来;二是云产业市场规规模有限,中国云市场目前仅占全球市场的5%,产品种类有限;三是云生志糸统、测评安全体糸没有完成。 上海交大副校長、中科院院士梅宏教授则从学术维度总结了云计算这十年的发展,他认为2006年是云计算的元年,当时定义硬件即服务,到2011年软件定义计算,2015年之后开始提出公有、私有云,微云、虚拟云、移动云等多云的联合云,引发了云操作系统应运而生。 之后,来自美国的Bill Franks以互联网升级到智联网的观点做了驾驭物联网数据价值的报告、中国电信中国联通也相关大V也做了云计算的进展报告。中国移动有关专家在报告中提出通信4.0概念,他认为IP+光+云统一网络基于云服务,他说软件定义计算、软件定义存储己经成熟,软件定义网络还刚刚开始,而开源是云计算标准化的新形态,提出软件定义一切。而之后李德毅教授则以智能驾驶为例,提出数据定义软件,让数据驱动了人工智能,人工智能汽车成为了定义软件的机器。 大会上有专家认为,大数据、互联网+都靠云服务落地,并预测,到2018年中国云市场会达8000亿元,平均年增長35%。 原文出处:科技行者 转载请与作者联系,同时请务必标明文章原始出处和原文链接及本声明。

优秀的个人博客,低调大师

java.lang.Exception: 资源处理失败,失败原因:com.mysql.jdbc.exceptions.jdbc4.MySQL...

1:Unknown column '?????‰' in 'where clause',这个问题,百度一搜,挺多的,但是貌似好像没有解决我的问题。贴一下我是如何拼接sql的。解决这个sql拼接bug的。希望可以帮助到有幸看到的人,谢谢。 1 TbUser.USER_NO.name + " = " + "'" + userNo + "'" ; 也许看不懂,哈哈,公司自己封装的,没关系,解决这个错误的关键在于+ "'" + userNo + "'" ;这句话,将自己传过来的动态值替换到userNo 即可。

优秀的个人博客,低调大师

Android应用开发提高系列(4)——Android动态加载(上)——加载未安装APK中的类

正文 一、前提 目的:动态加载SD卡中Apk的类。 注意:被加载的APK是未安装的。 相关:本文是本博另外一篇文章:Android动态加载jar/dex的升级版。 截图: 成功截图: 二、准备 准备被调用Android工程:TestB ITest public interfaceITest{ StringgetMoney(); } TestBActivity public classTestBActivity extendsActivity implementsITest{ /** Calledwhentheactivityisfirstcreated. */ @Override public voidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override publicStringgetMoney(){ return"1"; } } 代码说明:很简单的代码。将生成后的TestB.apk拷贝到SD卡的根目录下。 三、调用 调用工程TestA public classTestAActivity extendsActivity{ /** Calledwhentheactivityisfirstcreated. */ @Override public voidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); Stringpath=Environment.getExternalStorageDirectory()+"/"; Stringfilename="TestB.apk"; DexClassLoaderclassLoader= newDexClassLoader(path+filename,path, null,getClassLoader()); try{ ClassmLoadClass=classLoader.loadClass("com.nmbb.TestBActivity"); Constructorconstructor=mLoadClass.getConstructor( newClass[]{}); ObjectTestBActivity=constructor.newInstance( newObject[]{}); MethodgetMoney=mLoadClass.getMethod("getMoney", null); getMoney.setAccessible( true); Objectmoney=getMoney.invoke(TestBActivity, null); Toast.makeText( this,money.toString(),Toast.LENGTH_LONG).show(); } catch(ClassNotFoundExceptione){ e.printStackTrace(); } catch(SecurityExceptione){ e.printStackTrace(); } catch(NoSuchMethodExceptione){ e.printStackTrace(); } catch(IllegalArgumentExceptione){ e.printStackTrace(); } catch(InstantiationExceptione){ e.printStackTrace(); } catch(IllegalAccessExceptione){ e.printStackTrace(); } catch(InvocationTargetExceptione){ e.printStackTrace(); } } } 执行的时候可以发现会自动生成TestB.dex文件。动态加载方面还可以搜索一下"Java动态加载"方面的资料,很有参考价值。可以发现比Android动态加载jar/dex使用起来方便得多。 四、下载 TestA.zip TestB.zip 五、注意 6.1 别忘了加上SDCARD的写权限: android.permission.WRITE_EXTERNAL_STORAGE 6.2 同样注意,不要再两个工程包含package和名称相同的接口,否则报错。(参见Android动态加载jar/dex的后期维护) 六、扩展阅读 探秘腾讯Android手机游戏平台之不安装游戏APK直接启动法 (强烈推荐:QQ游戏动态调用Activity的方法:通过ClassLoader,loadClass Activity类,然后分别在主工程的onDestroy、onKeyDown、onPause、onRestart、onResume等生命周期方法中反射调用(Method、invoke)子工程的类方法来模拟实现整个生命周期。此外巧妙的通过解压缩APK文件来获取游戏的资源) Android中文Wiki:DexFile 七、缺点 6.1 由于是使用反射,无法取得Context,也就是TestBActivity与普通的类毫无区别,没有生命周期。 八、推荐 Android版 程序员专用搜索 结束 忙着换工作、忙着把翻译组转动Wiki平台、忙着推广翻译组...忙这忙那的,博客已经有近2个月没有写Android方面的文章,终于又可以回来,继续挤时间来写博客,与大家一同探讨与分享。 本文转自over140 51CTO博客,原文链接:http://blog.51cto.com/over140/844928,如需转载请自行联系原作者

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册