【Java应用服务体系】「序章入门」全方位盘点和总结调优技术专题指南

专题⽬标

本系列专题的目标是希望可以帮助读者们系统和全访问掌握应⽤系统调优的思路与方案以及相关的调优工具的使用,虽然未必会覆盖目前的所有的问题场景,但是还是提供了较为丰富的案例和调优理论,会帮助大家打开思维去⽀撑系统服务体系优化能力。

适合人员

Java相关的开发人员、系统架构师、数据库DB人员以及运维人员等

什么是调优

调优手段就是让计算机的硬件或软件在正常地⼯作基础上,非常出色的发挥其应有的性能,并且将所承担的负担降低到最低的技术手段。在Java应用服务体系中有大致可以分为5个维度的调优方向。

调优技术的五个维度

  • 应⽤⾃身的调优
  • 运⾏环境的调优(JVM的调优)
  • 存储上的调优(数据库的调优)
  • 操作系统的调优
  • 架构上的调优

如下图所示。

一般从上到下系统优化的层面成本越来越高,而从下到上系统优化层面的成本越来月底,而且难度也适当下降,建议自下而上的去进行调优规划。

调优技术的四条准则

借助监控预防问题、发现问题,监控 + 告警

采用监控和预防的手段去实现提前发现问题:zabbix、promethus等等

借助⼯具定位问题

问题排查工具使用机制

定期复盘,防⽌同类问题再现

定期进行排查和复盘相关的代码问题,加深我们对问题的印象以及防止问题再次发生

定好规范,⼀定程度上规避问题

制定标准规范,约束问题的发生。

调优的原则

有问题,解决问题。not broken, don't fix.

应⽤调优

应⽤调优-⼯具篇

  • ⼯具旨在帮助我们快速找到应⽤的性能瓶颈。

  • ⽇志分析⼯具⽐较与分析

  • ELK、GrayLog、SLSLog...

  • ELK搭建与使⽤

  • 现场演示

  • 调⽤链跟踪⼯具与对⽐

  • Skywalking、Sleuth + Zipkin、Jaeger...

  • Skywalking快速发现性能瓶颈

应⽤调优常⽤技巧-池化技术-对象池

通过复⽤对象,减少对象创建、垃圾回收的开销

适⽤场景

维护⼀些很⼤、创建很慢的对象,提升性能
缺点:有学习成本、增加了代码的复杂度

对象池框架

Apache Commons-Pool2
  • 官⽹:http://commons.apache.org/proper/commons-pool
  • GitHub:http://github.com/apache/commons-pool
Commons-Pool2详解

两⼤类对象池:ObjectPool & KeyedObjectPool

ObjectPool

实现类如下,其中,最重要、功能最强、使⽤最⼴泛的GenericObjectPool,这个对象池⾮常的强⼤,它⽐较的通⽤,⽽且封装得也⾮常完备。

  • BaseObjectPool:抽象类,⽤来扩展⾃⼰的对象池
  • ErodingObjectPool:“腐蚀”对象池,代理⼀个对象池,并基于factor参数,为其添加“腐蚀”⾏为。归还的对象被腐蚀后,将会丢弃,⽽不是添加到空闲容量中。
  • GenericObjectPool:⼀个可配置的通⽤对象池实现。
  • ProxiedObjectPool:代理⼀个其他的对象池,并基于动态代理(⽀持JDK代理和CGLib代理),返回⼀个代理后的对象。该对象池主要⽤来增强对池化对象的控制,⽐如防⽌在归还该对象后,还继续使⽤该对象等。
  • SoftReferenceObjectPool:基于软引⽤的对象池
  • SynchronizedObjectPool:代理⼀个其他对象池,并为其提供线程安全的能⼒。
核⼼API如下
  • borrowObject() 从对象池中借对象
  • returnObject() 将对象归还到对象池
  • invalidateObject() 失效⼀个对象
  • addObject() 增加⼀个空闲对象,该⽅法适⽤于使⽤空闲对象预加载对象池
  • clear() 清空空闲的所有对象,并释放相关资源
  • close() 关闭对象池,并释放相关资源
  • getNumIdle() 获得空闲的对象数量
  • getNumActive() 获得被借出对象数量
KeyedObjectPool

这种对象池和ObjectPool的区别在于,它是通过key找对象的,从设计上来看和ObjectPool没什么区别。实现类如下,使⽤最⼴的是GenericKeyedObjectPool。

  • ErodingKeyedObjectPool 类似ErodingObjectPool
  • GenericKeyedObjectPool 类似GenericObjectPool
  • ProxiedKeyedObjectPool 类似ProxiedObjectPool
  • SynchronizedKeyedObjectPool 类似SynchronizedObjectPool
使⽤
new GenericObjectPool(PooledObjectFactory<T> factory)
new GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig<T> config)
new GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig<T> config, AbandonedConfig abando
nedConfig)

最重要的参数是PooledObjectFactory,⼀般来说,⼯⼚是需要我们⾃⼰根据业务需求去实现的。它是⽤来创建对象的,这其实就是设计模式⾥⾯的⼯⼚模式。

⽬前PooledObjectFactory有两个实现类。

  • BasePooledObjectFactory:抽象类,⽤于扩展⾃⼰的PooledObjectFactory
  • PoolUtils.SynchronizedPooledObjectFactory:内部类,代理⼀个其他的PooledObjectFactory,实现线程同步,⽤ PoolUtils.synchronizedPooledFactory() 创建

Factory核⼼⽅法:

  • makeObject 创建⼀个对象实例,并将其包装成⼀个PooledObject
  • destroyObject 销毁对象
  • validateObject 校验对象,确保对象池返回的对象是OK的
  • activateObject 重新初始化对象
  • passivateObject 取消初始化对象。GenericObjectPool的addIdleObject、returnObject、evict调⽤该⽅法。

Commons-Pool2总体分析

  • ObjectPool:对象池,最核⼼:GenericObjectPool、 GenericKeyedObjectPool。
  • Factory:创建&管理PooledObject,⼀般要⾃⼰扩展
  • PooledObject:包装原有的对象,从⽽让对象池管理,⼀般⽤DefaultPooledObject即可
Factory示例
class MyPooledObjectFactory implements PooledObjectFactory<Model> { 
   public static final Logger LOGGER = LoggerFactory.getLogger(MyPooledObjectFactory.class); 
   @Override
   public PooledObject<Model> makeObject() throws Exception {
      DefaultPooledObject<Model> object = new DefaultPooledObject<>(new Model(1, "S")); 
      LOGGER.info("makeObject..state = {}", object.getState());
      return object; 
   }
  @Override
  public void destroyObject(PooledObject p) throws Exception{
      LOGGER.info("destroyObject..state = {}", object.getState());
   }
  @Override
  public boolean validateObject(PooledObject p) {
      LOGGER.info("validateObject..state = {}", object.getState());
      return true;
   }
  @Override
  public void activateObject(PooledObject p) throws Exception{
    LOGGER.info("activateObject..state = {}", p.getState());
   }
@Override
  public void passivateObject(PooledObject p) {
      LOGGER.info("passivateObject..state = {}", object.getState());
      return true;
   }

所有操作面向的都是PooledObject这个参数,makeObject返回的是PooledObject,其他API为什么操作的也是 PooledObject,⽽不是直接操作我们创建的对象呢?

这其实也是commons-pool设计巧妙之处。Pooledobject可以对原始对象进⾏包装,从⽽被对象池管理。⽬前 pooledobject有两个实现类:

  • DefaultPooledObject:包装原始对象,实现监控(例如创建时间、使⽤时间等)、状态跟踪等
  • PooledSoftReference:封装了DefaultPooledObject,⽤来和SoftReferenceObjectPool配合使⽤。
DefaultPooledObject定义了对象的若⼲种状态
  • IDLE 对象在队列中,并空闲。
  • ALLOCATED 使⽤中(即出借中)
  • EVICTION 对象当在队列中,正在进⾏驱逐测试
  • EVICTION_RETURN_TO_HEAD 对象驱逐测试通过后,放回到队列头部
  • VALIDATION 对象当前在队列中,空闲校验中
  • VALIDATION_PREALLOCATED 对象当前不在队列中,出借前校验中 VALIDATION_RETURN_TO_HEAD 对象当前不在队列中,校验通过后放回头部 INVALID 对象失效,驱逐测试失败、校验失败、对象销毁,都会将对象置为 INVALID。
  • ABANDONED 放逐中,如果对象上次使⽤时间超过removeAbandonedTimeout的配置,则将其标记为ABANDONED。标记为ABANDONED的对象即将变成 INVALID。
  • RETURNING 对象归还池中。

JVM调优

本系列专题将针对于Oracle Java HotSpot虚拟机为为开发者们提供不同的Java Heap内存空间的较为深入的分析介绍。对于任何接触的开发者都是非常重要的理论依据。频繁遇到的内存问题,提供生产环境的优化调整。那么适当的实战层级的Java虚拟机的内存空间分析能力是至关重要的。

前提概述

  • Java虚拟机是你的Java程序运行的基础,它为你提供动态的分配内存服务、垃圾收集、线程调度和切换、IO处理和本机操作等
  • Java堆空间是运行时Java程序的内存“容器”,它提供给您的Java应用程序所需的适当内存空间(Java堆、本机堆),并由JVM本身去管理。

JVM HotSpot内存被划分2类和5空间:

  • Heap堆内存空间:属于线程共享区域,也是我们JVM的内存管理范畴的最大的一部分运行时内存区域。
  • 方法区(永久代/元空间):属于线程共享区域,往往我们会忽略了这个区域的内存回收能力。
  • 本地堆 (C-Heap):本地方法的调用栈。
  • 虚拟机栈:Java方法的调用栈。

Heap堆内存空间

JVM的堆空间的变化在<18的版本之内,主要有一个分水岭,主要集中在8之前和8之后。

JDK8之前的对空间

JDK8之前的Heap空间如下图所示:

JDK8之后的Heap空间如下图所示:

主要时针对于方法区的实现机制:永久代 -> 元空间结构模型,接下来我们看看元数据空间在方法区中的分布结构模型。

后续版本中的-元空间和方法去的内存才能出分配关系

可以看到JDK8之后,方法去的实现有元空间和一部分堆内存组成。之前主要只有单纯的永久代去实现的。

常量池

常量池主要有静态常量池和运行时常量池组成。

  • 类信息
    • 类的版本
    • 字段描述信息
    • 方法描述信息
    • 接口和父类等描述信息
    • class文件常量池(静态常量池)
静态常量池,也叫class⽂件常量池,主要存放:
  • 字⾯量:例如⽂本字符串、 final修饰的常量。
  • 符号引⽤:例如类和接⼝的全限定名、字段的名称和描述符、⽅法的名称和描述符。
运⾏时常量池

当类加载到内存中后,JVM就会将静态常量池中的内容存放到运⾏时的常量池中;运⾏时常量池⾥⾯存储的主要是编译期间⽣成的字⾯量、符号引⽤等等。如下图对应的字符串常量在字符串常量池中的存储模式。

字符串常量池

字符串常量池,也可以理解成运⾏时常量池分出来的⼀部分,类加载到内存的时候,字符串,会存到字符串常量池⾥⾯。

对象和类在内存分布

针对于代码的执行和存储在JVM的分布,主要集中在栈空间和堆空间、方法区。它们各个的职能不同,对应的能力也是不同的。我们针对于一段代码块进行分析和介绍

虚拟机栈的基本结构模型

代码在堆栈中的存储结构信息

内存泄漏怎么排查[java内存溢出排查]

top 等查看系统内存概况

top:显示所有进程运行情况,按M键按照内存大小排序。

使用格式

top [-] [d] [p] [q] [c] [C] [S] [s] [n]

参数说明

  • d:指定每两次屏幕信息刷新之间的时间间隔,当然用户可以使用s交互命令来改变之
  • p:通过指定监控进程ID来仅仅监控某个进程的状态。
  • q:该选项将使top没有任何延迟的进行刷新。如果调用程序有超级用户权限,那么top将以尽可能高的优先级运行。
  • S:指定累计模式。
  • s:使top命令在安全模式中运行。这将去除交互命令所带来的潜在危险。
  • i:使top不显示任何闲置或者僵死进程。
  • c:显示整个命令行而不只是显示命令名。

命令说明

  • jmx 快速发现jvm中的内存异常项

【实战阶段】JVM排查问题优化参数

jps [-q] [-mlvV] [<hostid>]

参数如下:

  • -q 只显示进程号
  • -m 显示传递给main⽅法的参数
  • -l 显示应⽤main class的完整包名应⽤的jar⽂件完整路径名
  • -v 显示传递给JVM的参数
  • -V 禁⽌输出类名、JAR⽂件名和传递给main⽅法的参数,仅显示本地JVM标识符的列表

hostid的参数格式

  • hostid:想要查看的主机的标识符,格式为: [protocol:][[//]hostname][:port][/servername] ,其中:
  • protocol:通信协议,默认rmi
  • hostname:⽬标主机的主机名或IP地址
  • port:通信端⼝,对于默认 rmi 协议,该参数⽤来指定 rmiregistry 远程主机上的端⼝号。如省略该参数,并且该
  • protocol指示rmi,则使⽤默认使⽤1099端⼝。
  • servicename:服务名称,取值取决于实现⽅式,对于rmi协议,此参数代表远程主机上RMI远程对象的名称

今天就写到这里,未完待续,等待下一部分的内容。

本文来自博客园,作者:洛神灬殇,转载请注明原文链接:http://www.cnblogs.com/liboware/p/17063422.html,任何足够先进的科技,都与魔法无异。

本文转载于网络 如有侵权请联系删除

相关文章

  • 一起看看日本大隈机床智能无人工厂

    作为全球知名的“全能型制造商”,okuma(大隈株式会社)有两座无人工厂,从投料到加工完成都无需人工操作,实现了24小时每周7天不间断运转。双主轴双刀塔车床的代表者——okuma(大隈株式会社),几十年来一直坚持从核心部件(驱动器、编码器、马达、主轴等)到数控操作系统到终端,全部由自社设计开发完成,真正实现了软硬兼备。今天咱们看看大隈okuma机床智能无人工厂,大隈有两座无人工厂,DreamSite1在2013建成,负责生产复合加工机、中大型车床和立式车床。由零件加工区域和装配区域两部分构成,从投料到发货,贯穿所有环节,是一个自主体系的综合型生产工厂。DreamSite2在2017年建成,作为从小型、中型车床和磨床的生产工厂:http://mpvideo.qpic.cn/0bc3q4abiaaamman3lduovrfbb6dcsdqafaa.f10002.mp4?dis_k=4a85ca7deb45df530d584a3f5dfd65d3&dis_t=1652690207&vid=wxv_2386202579631783937&format_id=10002&

  • Android开关控件Switch的使用案例

    在很多app的设置页面,或者是一些功能的开关界面,我们常常用到Switch(开关)来展示状态,今天说说Switch控件。(1)布局文件代码<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin&q

  • 对人工智能的工作过程进行精准分析的指标(CS AI)

    在基准数据集上比较模型的性能是衡量和推动人工智能发展的重要组成部分。模型在基准数据集上的性能通常是基于单个或一小组性能指标来评估的。虽然这样可以进行快速比较,但是如果度量指标不能充分覆盖所有的性能特征,那么它也可能带来不充分反映模型性能的风险。目前,尚不清楚这会在多大程度上影响目前的基准制定工作。为了解决这个问题,我们分析了基于基于web的开放平台“带代码的论文”中涵盖3867个机器学习模型性能结果的数据的性能指标的现状。我们的结果表明,目前用于评估分类AI基准任务的大部分指标的属性可能导致分类器性能的不充分反映,特别是当使用不平衡的数据集时。虽然已经提出了解决问题属性的替代指标,但它们目前很少用于基准测试任务中的性能指标。最后,我们注意到度量的报告部分不一致,部分不明确,这可能导致在比较模型性能时的歧义。原文题目:Acriticalanalysisofmetricsusedformeasuringprogressinartificialintelligence原文:Comparingmodelperformancesonbenchmarkdatasetsisanintegralpar

  • Pytest系列(5) - 测试用例执行后的几种状态

    如果你还想从头学起Pytest,可以看看这个系列的文章哦!https://www.cnblogs.com/poloyy/category/1690628.html用例执行状态用例执行完成后,每条用例都有自己的状态,常见的状态有passed:测试通过failed:断言失败error:用例本身写的质量不行,本身代码报错(譬如:fixture不存在,fixture里面有报错)xfail:预期失败,加了@pytest.mark.xfail()error的栗子一:参数不存在defpwd(): print("获取用户名") a="yygirl" asserta=="yygirl123" deftest_1(pwd): assertuser=="yygirl"复制为啥是errorpwd参数并不存在,所以用例执行errorerror的栗子二:fixture有错@pytest.fixture() defuser(): print("获取用户名") a="yygirl" assert

  • Python 进阶之源码分析:如何将一个类方法变为多个方法?

    前一篇文章《Python中如何实现参数化测试?》中,我提到了在Python中实现参数化测试的几个库,并留下一个问题:它们是如何做到把一个方法变成多个方法,并且将每个方法与相应的参数绑定起来的呢?我们再提炼一下,原问题等于是:在一个类中,如何使用装饰器把一个类方法变成多个类方法(或者产生类似的效果)?#带有一个方法的测试类 classTestClass: deftest_func(self): pass #使用装饰器,生成多个类方法 classTestClass: deftest_func1(self): pass deftest_func2(self): pass deftest_func3(self): pass 复制Python中装饰器的本质就是移花接木,用一个新的方法来替代被装饰的方法。在实现参数化的过程中,我们介绍过的几个库到底用了什么手段/秘密武器呢?1、ddt如何实现参数化?先回顾一下上篇文章中ddt库的写法:importunittest fromddtimportddt,data,unpack @ddt classMyTest(unittest.TestCase): @

  • Akka-CQRS(8)- CQRS Reader Actor 应用实例

    前面我们已经讨论了CQRS-Reader-Actor的基本工作原理,现在是时候在之前那个POS例子里进行实际的应用示范了。假如我们有个业务系统也是在cassandra上的,那么reader就需要把从日志读出来的事件恢复成cassandra表里的数据行row。首先,我们需要在cassandra上创建相关的keyspace和table。下面是在scala中使用cassandra-java-driver的例子:importcom.datastax.driver.core._ importakka.actor.ActorSystem importakka.stream.ActorMaterializer importsdp.cql.engine._ importCQLEngine._ importCQLHelpers._ importmonix.execution.Scheduler.Implicits.global importscala.util._ objectCQLCreatTablesextendsApp{ //#init-mat implicitvalcqlsys=ActorSy

  • python3切片使用方法及一些技巧介绍+leetcode题例

    在Python中,字符串是定义为字符的有序集合,即我们可以像使用列表一样在字符串中自由翱翔-使用索引和切片操作字符串,比如通过指定的索引获取字符串某个位置的字符。#示例字符串 s='pythonstrwithslice'复制索引的简单使用在Python中字符串的索引可以是正数,正数即从左向右索引,索引从0开始,也可以是负数,负数即从右向左开始索引,索引从-1开始。如果超出了正负的索引范围,则会抛出异常#即从左边获取第一个偏移位置的字符 print(s[0]) #即从左边获取第一个偏移位置的字符 print(s[-1]) #即从左边获取第三个偏移位置的字符 print(s[4]) try: #尝试不存在于s的索引 print(s[1000]) except: print('IndexError:stringindexoutofrange')复制示例结果:p e o IndexError:stringindexoutofrange复制切片的简单使用切片,顾名思义即将一个有序序列切出一片,即从一个完整的字符串中取出一部分字符串,而怎么取?这就取决于我们

  • Redis学习系列四Hash(字典)

    一、简介Redis中的Hash字典相当于C#中的Hashtable,是一种无序字典,内存存储了很对的键值对,实现上和Hashtable一样,都是"数组+链表"二维结构,都是对关键字(键值)进行散列操作,讲关键字散列到Hashtable中的某一个槽位中去,这个过程中如果发生了碰撞,散列函数可能将不同的关键字散列到Hashtable中的同一个槽位中去,通过"链表的方式"进行连接。后续可能会写一个分类的关于C#中常用算法的文章,但这里不想介绍太多.不同的是.Redis中Hash(字典的值)只能是字符串,C#中为Hashtable为object另外关于Hashtable和List等类型,如果你阅读源码,当它们的实际容量达到初始设置的时候,一般都会创建一个新的对象,list中的原先的两倍,然后将原先的元素复制到新的对象中,这个过程如果里面的元素超级多,那么这个开销非常大,Hashtable也是如此,Hashtable中的这个过程专业术语叫rehash,而Redis为了避免这个开销,采用了"渐近式的"rhash操作,"渐进&qu

  • 网站高并发大流量访问的处理及解决方法

    1.硬件升级 普通的P4服务器一般最多能支持每天10万独立IP,如果访问量比这个还要大,那么必须首先配置一台更高性能的专用服务器才能解决问题,否则怎么优化都不可能彻底解决性能问题。 2.负载均衡 它是根据某种负载策略把请求分发到集群中的每一台服务器上,让整个服务器群来处理网站的请求。 公司比较有钱的,可以购买专门负责负载均衡的硬件(如:F5),效果肯定会很好。对于大部分公司,会选择廉价有效的方法扩展整个系统的架构,来增加服务器的吞吐量和处理能力,以及承载能力。 3.服务器集群 服务器集群就是指将N台服务器集中起来一起进行同一种服务,它们之间通过网络实现通信。让N台服务器之间相互协作,共同承载一个网站的请求压力。 在客户端看来就像是只有一个服务器。集群可以利用多个计算机进行并行计算从而获得很高的计算速度,也可以用多个计算机做备份,从而使得任何一个机器坏了整个系统还是能正常运行。 4.数据库读写分离 基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。 5.数据库分表技术(垂直分割,水平分割) 当一张的数据达到几百

  • 中国香港科技大学教授冯雁:How to Build Empathetic Machines

    主讲人:冯雁|中国香港科技大学屈鑫整理编辑量子位出品|公众号QbitAI 本文为冯雁教授8月18日于北京创新工场的分享实录整理,分享主题为《HowtoBuildEmpatheticMachines》。 冯雁现为中国香港科技大学电子及计算机工程系教授,主要研究领域包括语音理解、机器翻译、多语种处理及音乐信息检索等。 冯雁教授1988年于英国伍斯特理工学院获得电机工程学士学位,1993及1997年于美国哥伦比亚大学分别取得电脑科学硕士及博士学位。 2015年,因人机互动领域所作出的突出贡献而获颁IEEE院士荣誉,曾经担任IEEETransactionsonAudio、SpeechandLanguageProcessing、IEEESignalProcessingLetter、ACMTransactionsonSpeechandLanguageProcessing,以及TransactionsonAssociationforComputationalLinguistics等国际期刊的副主编,同时也是ACLSIGDAT的主席及董事会成员。 △冯雁教授 大家下午好,非常感谢李开复博士的邀请。今天

  • CKEditor使用

    前言本文主要使用CKEditor4版本CKEditor4下载地址https://ckeditor.com/ckeditor-4/download/官方文档https://ckeditor.com/docs/ckeditor4/latest/guide/dev_installation.htmlCKEditor5下载地址https://ckeditor.com/ckeditor-5/download/官方文档https://ckeditor.com/docs/ckeditor5/latest/installation/getting-started/quick-start.html该编辑器有以下几种模式使用CKEditorVueCli调用本地把下载的包放在public文件夹下index.html中添加<scripttype="text/javascript"src="./ckeditor/ckeditor.js"></script>复制页面中<divclass="warp_editor"> &

  • [NewLife.XCode]备份恢复与同步(数据搬运专家)

    NewLife.XCode是一个有20年历史的开源数据中间件,支持net6/net5/net45/net40,由新生命团队(2002~2020)开发完成并维护至今,以下简称XCode。 整个系列教程会大量结合示例代码和运行日志来进行深入分析,蕴含多年开发经验于其中,代表作有百亿级大数据实时计算项目。 开源地址:https://github.com/NewLifeX/X (求star,1450+) Nuget包:NewLife.XCode 源代码:https://github.com/NewLifeX/X/blob/master/XCode/DataAccessLayer/DbPackage.cs 数据应用开发中,经常需要用到备份、恢复和同步功能,XCode内置支持跨数据库备份同步。特别在分析线上问题时,经常是恨不得把线上某些表数据“弄”回来本地。所以,你需要XCode。 码神工具跨库数据同步 把数据从一个库同步到另一个库,以下视频从MySql库同步数据到SQLite库,包括创建数据表。 此处为语雀视频卡片,点击链接查看:码神数据同步.mp4 DbPackage类 数据

  • 研究Electron主进程、渲染进程、webview之间的通讯

    背景 由于某个Electron应用,需要主进程、渲染进程、webview之间能够互相通讯。 不过因为Electron仅提供了主进程与渲染进程的通讯,没有渲染进程之间或渲染进程与webview之间通讯的办法,所以只能寻找其他方案来解决。 研究一:ipcMain/ipcRenderer Electron主进程与渲染进程的通讯,就是用ipcMain/ipcRenderer这两个对象。 //在主进程中. const{ipcMain}=require('electron') ipcMain.on('asynchronous-message',(event,arg)=>{ console.log(arg)//prints"ping" event.reply('asynchronous-reply','pong') }) ipcMain.on('synchronous-message',(event,arg)=>{ console.log(arg)//prints"ping" event.returnValue='pong' }) //在渲染器进程(网页)中。 const{ip

  • mysqld_safe启动报错 mysqld_safe The file /usr/local/mysql/bin/mysqld does not exist or is not executable

    报错(如下),但是使用mysqld直接启动没有问题。 150718 00:03:38 mysqld_safe Logging to '/var/log/mysqld.log'.   150718 00:03:38 mysqld_safe The file /usr/local/mysql/bin/mysqld   does not exist or is not executable. Please cd to the mysql installation   directory and restart this script from there as follows:   ./bin/mysqld_safe

  • python里几个神奇的库(未完待续)

    1.bisect:使用二分法,在一个已排序的序列查找合适的插入位置。 >>>importbisect >>>l=[10,19,88,90] >>>bisect.bisect(l,22) >>>2#适合插入的位置为2 bisect.bisect_left(l,22)#如果已经在列表中存在,返回左边的位置 bisect.insort_left(l,22)#插入复制 2.heapq:完全平衡二叉树,所有节点都小于其子节点。 fromheapqimport* fromrandomimport* l=sample(xrange(1000),10) heap=[] printl foriinl:heappush(heap,i) printheappop(heap)#弹出的是列表里最小的。 复制 nlargest(5,l)从列表中返回有序的最大的N个元素 nsmallest(5,l)返回最小的N个元素 复制   

  • 这10个TypeScript高级技巧,助你成为更好的开发者!

    在使用了一段时间的Typescript之后,我深深地感受到了Typescript在大中型项目中的必要性。可以提前避免很多编译期的bug,比如烦人的拼写问题。并且越来越多的包都在使用TS,所以学习它势在必行。 以下是我在工作中学到的一些更实用的Typescript技巧,今天把它整理了一下,分享给各位,希望对各位有帮助。 1.keyof keyof与Object.keys稍有相似,只是keyof采用了接口的键。 interfacePoint{ x:number; y:number; } //typekeys="x"|"y" typekeys=keyofPoint;复制 假设我们有一个如下所示的对象,我们需要使用typescript实现一个get函数来获取其属性的值。 constdata={ a:3, hello:'max' } functionget(o:object,name:string){ returno[name] }复制 我们一开始可能是这样写的,但它有很多缺点: 无法确认返回类型:这将失去ts的最大类型检查能力。 无法约束密钥:可能会出现拼写错误。 在这种情况下,可

  • JS数据结构第六篇 --- 二叉树力扣练习题

    1、第226题:翻转二叉树 递归+迭代两种实现方式: /**反转二叉树 *Definitionforabinarytreenode. *functionTreeNode(val){ *this.val=val; *this.left=this.right=null; *} */ /** *@param{TreeNode}root *@return{TreeNode} *第一种方式迭代 *执行用时:72ms,在所有JavaScript提交中击败了87.29%的用户 *内存消耗:33.8M,在所有JavaScript提交中击败了24.26%的用户 */ varinvertTree=function(root){ if(!root)returnroot; vararr=[root]; while(arr.length){ varcurrent=arr.shift();//取出节点,交换左右子节点 vartemp=current.right; current.right=current.left; current.left=temp; //将左右子节点push到数组中 if(cur

  • Dubbo学习系列之十八(Skywalking服务跟踪)

      我们知道,微服务不是独立的存在,否则就不需要微服务这个架构了,那么当发起一次请求,如何知道这次请求的轨迹,或者说遇到响应缓慢、 请求出错的情况,我们该如何定位呢?这就涉及到APM(ApplicationPerformanceManagement)组件了,主流的选型有Zipkin、Pinpoint、Jaeger、 Skywalking,我在VehicleAdmin项目中试用了Dubbo+Zipkin组合,但发现当服务既是生产者又是消费者时有不兼容问题,于是我在此做了个Dubbo+ Skywalking的演示版本,仅供参考。 原创文章,谢绝一切形式转载,违者必究! 本文只发表在"公众号"和"博客园",其他均属复制粘贴!如果觉得排版不清晰,请查看公众号文章。  准备: Idea2019.03/Gradle6.0.1/Maven3.6.3/JDK11.0.4/Lombok0.28/SpringBoot2.2.4RELEASE/mybatisPlus3.3.0/Soul2.1.2/Dubbo2.7.5/Druid1.2.21/ Zookeeper3.5.5/Mysql8.0.11/

  • glGenBuffers与glBindBuffer理解

    创建VBO 创建VBO需要3个步骤: 使用glGenBuffers()生成新缓存对象。 使用glBindBuffer()绑定缓存对象。 使用glBufferData()将顶点数据拷贝到缓存对象中。 1.glGenBuffers官方解释:generatebufferobjectnames意思是该函数用来生成缓冲区对象的名称。 函数原型:voidglGenBuffers(GLsizein,GLuint*buffers); 第一个参数是要生成的缓冲对象的数量,第二个是要输入用来存储缓冲对象名称的数组 该函数会在buffers里返回n个缓冲对象的名称。 个人理解如下,可以声明一个GLuint变量,然后使用glGenBuffers后,它就会把缓冲对象保存在vbo里,当然也可以声明一个数组类型,那么创建的3个缓冲对象的名称会依次保存在数组里。 GLuintvbo;glGenBuffers(1,&vbo);GLuintvbo[3];glGenBuffers(3,vbo);注意:这里我用的是VBO做的示范,解释一下,glGenBuffers()函数仅仅是生成一个缓冲对象的名称,这个缓冲对象

  • c++ 虚函数和虚继承

    转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7883531一、虚函数的工作原理     虚函数的实现要求对象携带额外的信息,这些信息用于在运行时确定该对象应该调用哪一个虚函数。典型情况下,这一信息具有一种被称为vptr(virtualtablepointer,虚函数表指针)的指针的形式。vptr指向一个被称为vtbl(virtualtable,虚函数表)的函数指针数组,每一个包含虚函数的类都关联到vtbl。当一个对象调用了虚函数,实际的被调用函数通过下面的步骤确定:找到对象的vptr指向的vtbl,然后在vtbl中寻找合适的函数指针。     虚拟函数的地址翻译取决于对象的内存地址,而不取决于数据类型(编译器对函数调用的合法性检查取决于数据类型)。如果类定义了虚函数,该类及其派生类就要生成一张虚拟函数表,即vtable。而在类的对象地址空间中存储一个该虚表的入口,占4个字节,这个入口地址是在构造对象时由编译器

  • python3-常用模块之re

    正则表达式 定义: 正则表达式是对字符串操作的一种逻辑公式,用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。  是一种独立的规则,独立的语言。只和字符串打交道。 能做什么? 例子1:把一个文件中所有的手机号码都找出来;     #open打开文件     #读文件str     #从一长串的字符串中找到所有的11位数字 #一个字符一个字符的读 例子2:爬虫,从网页的字符串中获取你想要的数据 例子3:提取特定日志内容 规则 字符组: []写在中括号中的内容,都出现在下面的某一个字符的位置上都是符合规则的 [0-9] 匹配数字                  [a-z] 匹配小写字母 &n

相关推荐

推荐阅读