• LongAdder简单介绍
    LongAdder类似于AtomicLong是原子性递增或者递减类,AtomicLong已经通过CAS提供了非阻塞的原子性操作,相比使用阻塞算法的同步器来说性能已经很好了,但是JDK开发组并不满足,因为在非常高的并发请求下AtomicLong的性能不能让他们接受,虽然AtomicLong使用CAS但是CAS失败后还是通过无限循环的自旋锁不断尝试的 public final long incrementAndGet() { for (;;) { long current = get(); long next = current + 1; if (compareAndSet(current, next)) return next; } }在高并发下N多线程同时去操作一个变量会造成大量线程CAS失败然后处于自旋状态,这大大浪费了cpu资源,降低了并发性。那么既然AtomicLong性能由于过多线程同时去竞争一个变量的更新而降低的,那么如果把一个变量分解为多个变量,让同样多的线程去竞争多个资源那么性能问题不就解决了?是的,JDK8提供的LongAdder就是这个思路。LongAdder维护了一个延迟初始化的原子性更新数组和一个基值变量base.数组的大小保持是2的N次方大小,数组表的下标使用每个线程的hashcode值的掩码表示,数组里面的变量实体是Cell类型,Cell类型是AtomicLong的一个改进,用来减少缓存的争用,对于大多数原子操作字节填充是浪费的,因为原子性操作都是无规律的分散在内存中进行的,多个原子性操作彼此之间是没有接触的,但是原子性数组元素彼此相邻存放将能经常共享缓存行,所以这在性能上是一个提升。另外由于Cells占用内存是相对比较大的,所以一开始并不创建,而是在需要时候在创建,也就是惰性加载,当一开始没有空间时候,所有的更新都是操作base变量,自旋锁cellsBusy用来初始化和扩容数组表使用,这里没有必要用阻塞锁,当一次线程发现当前下标的元素获取锁失败后,会尝试获取其他下表的元素的锁。
  • [技术交流] 35+ 个 Java 代码性能优化总结
    前言代码优化,一个很重要的课题。可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是,吃的小虾米一多之后,鲸鱼就被喂饱了。代码优化也是一样,如果项目着眼于尽快无BUG上线,那么此时可以抓大放小,代码的细节可以不精打细磨;但是如果有足够的时间开发、维护代码,这时候就必须考虑每个可以优化的细节了,一个一个细小的优化点累积起来,对于代码的运行效率绝对是有提升的。代码优化的目标是:1、减小代码的体积2、提高代码运行的效率本文的内容有些来自网络,有些来自平时工作和学习,当然这不重要,重要的是这些代码优化的细节是否真真正正地有用。那本文会保持长期更新,只要有遇到值得分享的代码优化细节,就会不定时地更新此文。代码优化细节1、尽量指定类、方法的final修饰符带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String,整个类都是final的。为类指定final修饰符可以让类不可以被继承,为方法指定final修饰符可以让方法不可以被重写。如果指定了一个类为final,则该类所有的方法都是final的。Java编译器会寻找机会内联所有的final方法,内联对于提升Java运行效率作用重大,具体参见Java运行期优化。此举能够使性能平均提高50%。2、尽量重用对象特别是String对象的使用,出现字符串连接时应该使用StringBuilder/StringBuffer代替。由于Java虚拟机不仅要花时间生成对象,以后可能还需要花时间对这些对象进行垃圾回收和处理,因此,生成过多的对象将会给程序的性能带来很大的影响。3、尽可能使用局部变量调用方法时传递的参数以及在调用中创建的临时变量都保存在栈中速度较快,其他变量,如静态变量、实例变量等,都在堆中创建,速度较慢。另外,栈中创建的变量,随着方法的运行结束,这些内容就没了,不需要额外的垃圾回收。4、及时关闭流Java编程过程中,进行数据库连接、I/O流操作时务必小心,在使用完毕后,及时关闭以**资源。因为对这些大对象的操作会造成系统大的开销,稍有不慎,将会导致严重的后果。5、尽量减少对变量的重复计算明确一个概念,对方法的调用,即使方法中只有一句语句,也是有消耗的,包括创建栈帧、调用方法时保护现场、调用方法完毕时恢复现场等。所以例如下面的操作:for (int i = 0; i < list.size(); i++){...}建议替换为:for (int i = 0, int length = list.size(); i < length; i++){...}这样,在list.size()很大的时候,就减少了很多的消耗6、尽量采用懒加载的策略,即在需要的时候才创建例如:String str = "aaa";if (i == 1){  list.add(str);}建议替换为:if (i == 1){  String str = "aaa";  list.add(str);}7、慎用异常异常对性能不利。抛出异常首先要创建一个新的对象,Throwable接口的构造函数调用名为fillInStackTrace()的本地同步方法,fillInStackTrace()方法检查堆栈,收集调用跟踪信息。只要有异常被抛出,Java虚拟机就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。异常只能用于错误处理,不应该用来控制程序流程。8、不要在循环中使用try...catch...,应该把其放在最外层根据网友们提出的意见,这一点我认为值得商榷9、如果能估计到待添加的内容长度,为底层以数组方式实现的**、工具类指定初始长度比如ArrayList、LinkedLlist、StringBuilder、StringBuffer、HashMap、HashSet等等,以StringBuilder为例:(1)StringBuilder()      // 默认分配16个字符的空间(2)StringBuilder(int size)  // 默认分配size个字符的空间(3)StringBuilder(String str) // 默认分配16个字符+str.length()个字符空间可以通过类(这里指的不仅仅是上面的StringBuilder)的构造函数来设定它的初始化容量,这样可以明显地提升性能。比如StringBuilder吧,length表示当前的StringBuilder能保持的字符数量。因为当StringBuilder达到最大容量的时候,它会将自身容量增加到当前的2倍再加2,无论何时只要StringBuilder达到它的最大容量,它就不得不创建一个新的字符数组然后将旧的字符数组内容拷贝到新字符数组中----这是十分耗费性能的一个操作。试想,如果能预估到字符数组中大概要存放5000个字符而不指定长度,最接近5000的2次幂是4096,每次扩容加的2不管,那么:(1)在4096 的基础上,再申请8194个大小的字符数组,加起来相当于一次申请了12290个大小的字符数组,如果一开始能指定5000个大小的字符数组,就节省了一倍以上的空间(2)把原来的4096个字符拷贝到新的的字符数组中去这样,既浪费内存空间又降低代码运行效率。所以,给底层以数组实现的**、工具类设置一个合理的初始化容量是错不了的,这会带来立竿见影的效果。但是,注意,像HashMap这种是以数组+链表实现的**,别把初始大小和你估计的大小设置得一样,因为一个table上只连接一个对象的可能性几乎为0。初始大小建议设置为2的N次幂,如果能估计到有2000个元素,设置成new HashMap(128)、new HashMap(256)都可以。10、当复制大量数据时,使用System.arraycopy()命令11、乘法和除法使用移位操作例如:for (val = 0; val < 100000; val += 5){  a = val * 8;  b = val / 2;}用移位操作可以极大地提高性能,因为在计算机底层,对位的操作是最方便、最快的,因此建议修改为: for (val = 0; val < 100000; val += 5){  a = val > 1;}移位操作虽然快,但是可能会使代码不太好理解,因此最好加上相应的注释。12、循环内不要不断创建对象引用例如:for (int i = 1; i
  • 华为云数据库参数组详解
    用户使用数据库服务时,系统会给用户配置默认的参数组(一种数据库引擎一套,如下图),默认参数组是无法修改的。那么用户怎么修改自己的数据库参数呢?用户如果想修改自己数据库的参数,需要自己新建参数组。例如我新建一个mysql的参数组(my-mysql):点击编辑,就可以编辑里边的参数了。编辑完保存后,选择要修改的实例修改参数组即可。
  • 如何优雅的分析 Redis 里存了啥?
    文章来自:InfoQ,作者:董明鑫 雪球 SRE 工程师[/backcolor]Redis 是互联网产品开发中不可缺少的常备武器,它性能高、数据结构丰富、简单易用,但同时也是因为太容易用了,我们的开发同学不管什么数据、不管这数据有多大、不管数据有多少通通塞进去,最后导致的问题就是 Redis 内存使用持续上升,但是又不知道里面的数据是不是有用,是否可以拆分和清理。为了更好地使用 Redis,除了对 Redis 做一些使用规范,还需要对线上使用的 Redis 有充分的了解。那么问题来了:一个 Redis 的实例用了那么大的内存,里边到底存了啥?都有哪些 key?每个 key 占用了多少空间?雪球当前有几十个 Redis 集群,近千个 Redis 实例,5T 的内存数据,我们也想要分析业务是否有误用,以提高资源利用率。当然,曾经我们也深深地被这个问题所困扰,今天我就来和大家分享下我是如何解决这个问题的,希望能给各位一些启发。那有没有什么办法让我们安全高效的看到 Redis 内存消耗的详细报表呢?办法总比问题多,有需求就有解决方案。雪球 SRE 团队针对这个问题实现了一个 Redis 数据可视化平台 RDR (Redis Data Reveal)。RDR 可以非常方便的对 Reids 的内存进行分析,了解一个 Redis 实例里都有哪些 key,哪类 key 占用的空间是多少,最耗内存的 key 有哪些,占比如何,非常直观。设计思路我们先梳理下,有什么办法可以拿到 Redis 的所有数据。从我的角度看,大概有以下几种方法,我们分析一下个字的优缺点:1. 先通过 keys * 命令,拿到所有的 key,然后根据 key 再获取所有的内容。优点:可以不使用 Redis 机器的硬盘,直接网络传输缺点:如果 key 数量特别多,keys 命令可能会导致 Redis 卡住影响业务;需要对 Redis 请求非常多次,资源消耗多;遍历数据太慢2. 开启 aof,通过 aof 文件获取到所有数据。优点:无需影响 Redis 服务,完全离线操作,足够安全;缺点:有一些 Redis 实例写入频繁,不适合开启 aof,普适性不强;aof 文件有可能特别大,传输、解析起来太慢,效率低。3. 使用 bgsave,获取 rdb 文件,解析后获取数据。优点:机制成熟,可靠性好;文件相对小,传输、解析效率高;缺点:bgsave 虽然会 fork 子进程,但还是有可能导致主进程卡住一段时间,对业务有产生影响的风险;以上几种方式我们评估之后,决定采用低峰期在从节点做 bgsave 获取 rdb 文件,相对安全可靠,也可以覆盖所有业务的 Redis 集群。也就是说每个实例每天在低峰期自动生成一个 rdb 文件,即使报表数据有一天的延迟也是可以接受的。拿到了 rdb 文件就相当于拿到了 Redis 实例的所有数据,接下来就是生成报表的过程了:1.解析 rdb 文件,获取到 Key 和 Value 的内容;2.根据相对应的数据结构及内容,估算内存消耗等;3.统计并生成报表;逻辑很简单,所以设计思路很清晰。数据流图如下:我们再看下具体该如何实现,首先是语言选型,雪球 SRE 自研的组件基本都是用 Go 语言做的后端,所以语言选型没什么纠结,直接用 Go。然后就是刚刚说的那几个流程。1. 解析 RDB按照 Redis 的协议来做就可以了,这个在 GitHub 上搜索 parse rdb 就可以找到许多解析 rdb 文件的库,拿过来使用即可。2. 估算内存消耗一条记录会有哪些内存使用呢?我们知道 Redis 的实现里面有一些基础的数据结构,就是用这些结构来实现了对外暴露的各种数据类型:比如 sds、dict、intset、zipmap、adlist、ziplist、quicklist、skiplist 等等。只要根据这条记录的数据类型,找出使用了哪些数据结构,再计算出这些基础数据结构的内存消耗,再加上数据的内存使用,以及一些额外开销比如过期时间等,就可以估算出一条记录到底使用了多少内存。但是由于 Redis 做了非常多的优化,同样的一种数据类型,在不同场景下使用的数据结构有可能是不同的。比如 List ,比较老版本的 Redis,会根据 list 元素的数量来决定来使用哪种结构,较短的时候使用 adlist,长之后使用 ziplist,数值可以通过 list-max-ziplist-entries 来配置。3.2 版本以后全都使用了 quicklist。而不同结构对于内存的使用其实是有区别的,我们计算的时候也没办法拿到具体的配置,所以都按默认配置来计算,最后得出的值是一个估算的值,不过也基本可以反应使用情况了。如果大家对于 Redis 使用的各种数据结构感兴趣,想了解其设计及适用场景,可以多搜索一下相关的资料以及阅读 Redis 源码。举个计算内存使用的例子:假如我们通过解析 rdb,获取到了一个 key 为 hello,value 为 world,类型为 string ,ttl 为 1440 的一条记录,它的内存使用是这样的:一个 dictEntry 的消耗,Redis db 就是一个大 dict,每对 kv 都是其中的一个 entry ;一 个 robj 的消耗,robj 是为了在同一个 dict 内能够存储不同类型的 value,而使用的一个通用的数据结构,全名是 Redis Object;存储 key 的 sds 消耗,sds 是 Redis 中存储字符串使用的数据结构;存储过期时间消耗;存储 value 的 sds 消耗;前四项基本是存储任何一个 key 都需要消耗的,最后一项根据 value 的数据结构不同而不同。一个 dictEntry 有 2 个指针,一个 int64 的内存消耗;一个 robj 有 1 指针,一个 int,以及几个使用位域的字段共消耗 4 字节;过期时间也是存储为一个 dictEntry,时间戳为 int64;存储 sds 需要存储 header 以及字符串长度 +1 的空间,header 长度根据字符串长度不同也会有所不同;我们根据以上信息可以算出,向操作系统申请这些内存,真正需要多少内存。由于 Redis 支持多种 malloc 算法,我们就按 jemalloc 的分配方式算,这里也是可能存在误差的点。所以最后 key 为 hello 的这条记录在 64 位操作系统上一共会消耗 92 字节。其他类型的计算也大致是同样的思路,只不过根据不同的数据结构需要计算不同的内存消耗,计算的时候要记得考虑内存对齐的情况。还有由于 zset 的算法涉及到了随机生成层数,我们也使用同样的算法来随机,但是算出来的值肯定不是精确的,也是一个误差点。3. 统计计数终于可以拿到任何一个 key 的内存使用了,哪些是最有意义最有价值的数据呢?top N,毫无疑问最大的前 N 个 key 一定是要关注的;不同数据类型的 key 数量元素数量分布以及内存使用情况;按照前缀分类,统一的前缀一般意味着某个特定的业务在使用,计算各个分类的 key 数量及内存使用情况;这几个需求实现起来也都很容易:维护一个小顶堆来存储前 N 个最大的即可,最后取出堆中的数据即可;计数即可; 一般都会有特定的分隔符,比如 :|._ 等字符,按照这些字符切出公共前缀再统计,同时把所有的数字都替换为 0,便于分类;4. 报表数据可以每天打开个网页就可以看到某个 Redis 实例的内存使用的详细情况,是件非常幸福的事情,Redis 的内存使用再也不是黑盒。这个系统上线一年以来对我们优化 Redis 资源使用、提高效率、节约成本提供了非常重要的数据支撑,而且在内部完全自动化,开发同学自己就可以看到当前 Redis 的使用情况是否符合预期,对于保障业务稳定也起到了非常重要的作用。这也是雪球的工程师团队一贯的做法,SRE 提供高效的工具,开发工程师可以自己运维自己的业务系统,可以极大的提高生产效率。这个项目参考了 redis-rdb-tool 这个开源项目,但是性能上比它高效几倍,为了回馈社区,也希望有机会帮到大家,所以我们决定开源出来。雪球的内部系统根据自己的特殊场景做了自动化获取 rdb 文件并备份的逻辑,开源出来的版本去除了定制化,只保留了获取到 rdb 之后的分析逻辑以及页面。
  • Redis 和 Memcached 的区别详解
    文章内容来自“码农网”Redis的作者Salvatore Sanfilippo曾经对这两种基于内存的数据存储系统进行过比较:[*]Redis支持服务器端的数据操作:Redis相比Memcached来说,拥有更多的数据结构和并支持更丰富的数据操作,通常在Memcached里,你需要将数据拿到客户端来进行类似的修改再set回去。这大大增加了网络IO的次数和数据体积。在Redis中,这些复杂的操作通常和一般的GET/SET一样高效。所以,如果需要缓存能够支持更复杂的结构和操作,那么Redis会是不错的选择。[*]内存使用效率对比:使用简单的key-value存储的话,Memcached的内存利用率更高,而如果Redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于Memcached。[*]性能对比:由于Redis只使用单核,而Memcached可以使用多核,所以平均每一个核上Redis在存储小数据时比Memcached性能更高。而在100k以上的数据中,Memcached性能要高于Redis,虽然Redis最近也在存储大数据的性能上进行优化,但是比起Memcached,还是稍有逊色。具体为什么会出现上面的结论,以下为收集到的资料:1、数据类型支持不同与Memcached仅支持简单的key-value结构的数据记录不同,Redis支持的数据类型要丰富得多。最为常用的数据类型主要由五种:String、Hash、List、Set和Sorted Set。Redis内部使用一个redisObject对象来表示所有的key和value。redisObject最主要的信息如图所示:type代表一个value对象具体是何种数据类型,encoding是不同数据类型在redis内部的存储方式,比如:type=string代表value存储的是一个普通字符串,那么对应的encoding可以是raw或者是int,如果是int则代表实际redis内部是按数值型类存储和表示这个字符串的,当然前提是这个字符串本身可以用数值表示,比如:”123″ “456”这样的字符串。只有打开了Redis的虚拟内存功能,vm字段字段才会真正的分配内存,该功能默认是关闭状态的。1)String[*]常用命令:set/get/decr/incr/mget等;[*]应用场景:String是最常用的一种数据类型,普通的key/value存储都可以归为此类;[*]实现方式:String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr、decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。2)Hash[*]常用命令:hget/hset/hgetall等[*]应用场景:我们要存储一个用户信息对象数据,其中包括用户ID、用户姓名、年龄和生日,通过用户ID我们希望获取该用户的姓名或者年龄或者生日;[*]实现方式:Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口。如图所示,Key是用户ID, value是一个Map。这个Map的key是成员的属性名,value是属性值。这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 也就是通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据。当前HashMap的实现有两种方式:当HashMap的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,这时对应的value的redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。3)List[*]常用命令:lpush/rpush/lpop/rpop/lrange等;[*]应用场景:Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现;[*]实现方式:Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。4)Set[*]常用命令:sadd/spop/smembers/sunion等;[*]应用场景:Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的;[*]实现方式:set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。5)Sorted Set[*]常用命令:zadd/zrange/zrem/zcard等;[*]应用场景:Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是**有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。[*]实现方式:Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。2、内存管理机制不同在Redis中,并不是所有的数据都一直存储在内存中的。这是和Memcached相比一个最大的区别。当物理内存用完时,Redis可以将一些很久没用到的value交换到磁盘。Redis只会缓存所有的key的信息,如果Redis发现内存的使用量超过了某一个阀值,将触发swap的操作,Redis根据“swappability = age*log(size_in_memory)”计算出哪些key对应的value需要swap到磁盘。然后再将这些key对应的value持久化到磁盘中,同时在内存中清除。这种特性使得Redis可以保持超过其机器本身内存大小的数据。当然,机器本身的内存必须要能够保持所有的key,毕竟这些数据是不会进行swap操作的。同时由于Redis将内存中的数据swap到磁盘中的时候,提供服务的主线程和进行swap操作的子线程会共享这部分内存,所以如果更新需要swap的数据,Redis将阻塞这个操作,直到子线程完成swap操作后才可以进行修改。当从Redis中读取数据的时候,如果读取的key对应的value不在内存中,那么Redis就需要从swap文件中加载相应数据,然后再返回给请求方。 这里就存在一个I/O线程池的问题。在默认的情况下,Redis会出现阻塞,即完成所有的swap文件加载后才会相应。这种策略在客户端的数量较小,进行批量操作的时候比较合适。但是如果将Redis应用在一个大型的网站应用程序中,这显然是无法满足大并发的情况的。所以Redis运行我们设置I/O线程池的大小,对需要从swap文件中加载相应数据的读取请求进行并发操作,减少阻塞的时间。 对于像Redis和Memcached这种基于内存的数据库系统来说,内存管理的效率高低是影响系统性能的关键因素。传统C语言中的malloc/free函数是最常用的分配和释放内存的方法,但是这种方法存在着很大的缺陷:首先,对于开发人员来说不匹配的malloc和free容易造成内存泄露;其次频繁调用会造成大量内存碎片无法回收重**用,降低内存利用率;最后作为系统调用,其系统开销远远大于一般函数调用。所以,为了提高内存的管理效率,高效的内存管理方案都不会直接使用malloc/free调用。Redis和Memcached均使用了自身设计的内存管理机制,但是实现方法存在很大的差异,下面将会对两者的内存管理机制分别进行介绍。Memcached默认使用Slab Allocation机制管理内存,其主要思想是按照预先规定的大小,将分配的内存分割成特定长度的块以存储相应长度的key-value数据记录,以完全解决内存碎片问题。Slab Allocation机制只为存储外部数据而设计,也就是说所有的key-value数据都存储在Slab Allocation系统里,而Memcached的其它内存请求则通过普通的malloc/free来申请,因为这些请求的数量和频率决定了它们不会对整个系统的性能造成影响Slab Allocation的原理相当简单。 如图所示,它首先从操作系统申请一大块内存,并将其分割成各种尺寸的块Chunk,并把尺寸相同的块分成组Slab Class。其中,Chunk就是用来存储key-value数据的最小单位。每个Slab Class的大小,可以在Memcached启动的时候通过制定Growth Factor来控制。假定图中Growth Factor的取值为1.25,如果第一组Chunk的大小为88个字节,第二组Chunk的大小就为112个字节,依此类推。当Memcached接收到客户端发送过来的数据时首先会根据收到数据的大小选择一个最合适的Slab Class,然后通过查询Memcached保存着的该Slab Class内空闲Chunk的列表就可以找到一个可用于存储数据的Chunk。当一条数据库过期或者丢弃时,该记录所占用的Chunk就可以回收,重新添加到空闲列表中。从以上过程我们可以看出Memcached的内存管理制效率高,而且不会造成内存碎片,但是它最大的缺点就是会导致空间浪费。因为每个Chunk都分配了特定长度的内存空间,所以变长数据无法充分利用这些空间。如图 所示,将100个字节的数据缓存到128个字节的Chunk中,剩余的28个字节就浪费掉了。Redis的内存管理主要通过源码中zmalloc.h和zmalloc.c两个文件来实现的。Redis为了方便内存的管理,在分配一块内存之后,会将这块内存的大小存入内存块的头部。如图所示,real_ptr是redis调用malloc后返回的指针。redis将内存块的大小size存入头部,size所占据的内存大小是已知的,为size_t类型的长度,然后返回ret_ptr。当需要释放内存的时候,ret_ptr被传给内存管理程序。通过ret_ptr,程序可以很容易的算出real_ptr的值,然后将real_ptr传给free释放内存。 Redis通过定义一个数组来记录所有的内存分配情况,这个数组的长度为ZMALLOC_MAX_ALLOC_STAT。数组的每一个元素代表当前程序所分配的内存块的个数,且内存块的大小为该元素的下标。在源码中,这个数组为zmalloc_allocations。zmalloc_allocations[16]代表已经分配的长度为16bytes的内存块的个数。zmalloc.c中有一个静态变量used_memory用来记录当前分配的内存总大小。所以,总的来看,Redis采用的是包装的mallc/free,相较于Memcached的内存管理方法来说,要简单很多。3、数据持久化支持Redis虽然是基于内存的存储系统,但是它本身是支持内存数据的持久化的,而且提供两种主要的持久化策略:RDB快照和AOF日志。而memcached是不支持数据持久化操作的。1)RDB快照Redis支持将当前数据的快照存成一个数据文件的持久化机制,即RDB快照。但是一个持续写入的数据库如何生成快照呢?Redis借助了fork命令的copy on write机制。在生成快照时,将当前进程fork出一个子进程,然后在子进程中循环所有的数据,将数据写成为RDB文件。我们可以通过Redis的save指令来配置RDB快照生成的时机,比如配置10分钟就生成快照,也可以配置有1000次写入就生成快照,也可以多个规则一起实施。这些规则的定义就在Redis的配置文件中,你也可以通过Redis的CONFIG SET命令在Redis运行时设置规则,不需要重启Redis。Redis的RDB文件不会坏掉,因为其写操作是在一个新进程中进行的,当生成一个新的RDB文件时,Redis生成的子进程会先将数据写到一个临时文件中,然后通过原子性rename系统调用将临时文件重命名为RDB文件,这样在任何时候出现故障,Redis的RDB文件都总是可用的。同时,Redis的RDB文件也是Redis主从同步内部实现中的一环。RDB有他的不足,就是一旦数据库出现问题,那么我们的RDB文件中保存的数据并不是全新的,从上次RDB文件生成到Redis停机这段时间的数据全部丢掉了。在某些业务下,这是可以忍受的。2)AOF日志AOF日志的全称是append only file,它是一个追加写入的日志文件。与一般数据库的binlog不同的是,AOF文件是可识别的纯文本,它的内容就是一个个的Redis标准命令。只有那些会导致数据发生修改的命令才会追加到AOF文件。每一条修改数据的命令都生成一条日志,AOF文件会越来越大,所以Redis又提供了一个功能,叫做AOF rewrite。其功能就是重新生成一份AOF文件,新的AOF文件中一条记录的操作只会有一次,而不像一份老文件那样,可能记录了对同一个值的多次操作。其生成过程和RDB类似,也是fork一个进程,直接遍历数据,写入新的AOF临时文件。在写入新文件的过程中,所有的写操作日志还是会写到原来老的AOF文件中,同时还会记录在内存缓冲区中。当重完操作完成后,会将所有缓冲区中的日志一次性写入到临时文件中。然后调用原子性的rename命令用新的AOF文件取代老的AOF文件。AOF是一个写文件操作,其目的是将操作日志写到磁盘上,所以它也同样会遇到我们上面说的写操作的流程。在Redis中对AOF调用write写入后,通appendfsync选项来控制调用fsync将其写到磁盘上的时间,下面appendfsync的三个设置项,安全强度逐渐变强。[*]appendfsync no 当设置appendfsync为no的时候,Redis不会主动调用fsync去将AOF日志内容同步到磁盘,所以这一切就完全依赖于操作系统的调试了。对大多数Linux操作系统,是每30秒进行一次fsync,将缓冲区中的数据写到磁盘上。[*]appendfsync everysec 当设置appendfsync为everysec的时候,Redis会默认每隔一秒进行一次fsync调用,将缓冲区中的数据写到磁盘。但是当这一次的fsync调用时长超过1秒时。Redis会采取延迟fsync的策略,再等一秒钟。也就是在两秒后再进行fsync,这一次的fsync就不管会执行多长时间都会进行。这时候由于在fsync时文件描述符会被阻塞,所以当前的写操作就会阻塞。所以结论就是,在绝大多数情况下,Redis会每隔一秒进行一次fsync。在最坏的情况下,两秒钟会进行一次fsync操作。这一操作在大多数数据库系统中被称为group commit,就是组合多次写操作的数据,一次性将日志写到磁盘。[*]appednfsync always 当设置appendfsync为always时,每一次写操作都会调用一次fsync,这时数据是最安全的,当然,由于每次都会执行fsync,所以其性能也会受到影响。对于一般性的业务需求,建议使用RDB的方式进行持久化,原因是RDB的开销并相比AOF日志要低很多,对于那些无法忍数据丢失的应用,建议使用AOF日志。4、集群管理的不同Memcached是全内存的数据缓冲系统,Redis虽然支持数据的持久化,但是全内存毕竟才是其高性能的本质。作为基于内存的存储系统来说,机器物理内存的大小就是系统能够容纳的最大数据量。如果需要处理的数据量超过了单台机器的物理内存大小,就需要构建分布式集群来扩展存储能力。Memcached本身并不支持分布式,因此只能在客户端通过像一致性哈希这样的分布式算法来实现Memcached的分布式存储。下图给出了Memcached的分布式存储实现架构。当客户端向Memcached集群发送数据之前,首先会通过内置的分布式算法计算出该条数据的目标节点,然后数据会直接发送到该节点上存储。但客户端查询数据时,同样要计算出查询数据所在的节点,然后直接向该节点发送查询请求以获取数据。 相较于Memcached只能采用客户端实现分布式存储,Redis更偏向于在服务器端构建分布式存储。最新版本的Redis已经支持了分布式存储功能。Redis Cluster是一个实现了分布式且允许单点故障的Redis高级版本,它没有中心节点,具有线性可伸缩的功能。下图给出Redis Cluster的分布式存储架构,其中节点与节点之间通过二进制协议进行通信,节点与客户端之间通过ascii协议进行通信。在数据的放置策略上,Redis Cluster将整个key的数值域分成4096个哈希槽,每个节点上可以存储一个或多个哈希槽,也就是说当前Redis Cluster支持的最大节点数就是4096。Redis Cluster使用的分布式算法也很简单:crc16( key ) %HASH_SLOTS_NUMBER。 为了保证单点故障下的数据可用性,Redis Cluster引入了Master节点和Slave节点。在Redis Cluster中,每个Master节点都会有对应的两个用于冗余的Slave节点。这样在整个集群中,任意两个节点的宕机都不会导致数据的不可用。当Master节点退出后,集群会自动选择一个Slave节点成为新的Master节点。
  • [问题求助] 想问一下那个预测时去噪处理,题目的意思是说异常点一定是特殊日期吗?
    就是那个异常点我们是要通过匹配异常的日期将他们排除掉,还是通过处理图像进行去噪啊?
  • [问题求助] 题目中对于异常点的定义?
    请问异常点是指值特别大的点吗?0有没有可能是异常点?
  • [问题求助] 判题系统与题目要求有出入
    版主你好,根据题目要求和问答部分都表明,系统判分时“资源利用率”部分应该是根据不同用例所具体给出的按照“CPU资源利用率”或者“MEM资源利用率”来打分,但是目前练习阶段系统在判分时,不管用例要求优化的是“CPU”还是“MEM”,统一是按照“CPU资源利用率”来给出分数。我想问的是,这个情况是现阶段判分系统故意为之,还是工程师在编写判分系统时的疏忽。第二个问题是在之后的比赛中,正式提交答案时仍然是只按照“CPU资源利用率”来打分,还是会改正来区分“CPU资源利用率”和“MEM资源利用率”来打分。一共两个问题,请版主解答,并望回复。
  • [问题求助] 关于题目所说的资源利用率的问题
    这个得分公式应该意味着放置阶段是最小化物理服务器数量的问题。难道资源利用率不应该跟每个物理服务器的资源利用率相关吗?
  • MongoDB数据模型浅析-02
    1.1 规范化数据模型(引用) 规范化数据模型指的是通过使用 引用 来表达对象之间的关系,应用程序通过引用来访问那些具有关联关系的数据。一般来说,在下述情况下可以使用规范化模型:· 当内嵌数据会导致很多数据的重复,并且读性能的优势又不足于盖过数据重复的弊端时候。· 需要表达比较复杂的多对多关系的时候。· 大型多层次结构数据集。引用比内嵌要更加灵活一些。但客户端应用必须使用二次查询来解析文档内包含的引用。换句话说,对同样的操作来说,规范化模式会导致更多的网络请求发送到数据库服务器端。1.1.1 一对多的例子: 让我们来看一个针对于出版社和书籍关系建模的一个例子。通过这个例子中我们演示了相对于内嵌文档模型,使用文档引用模型可以有效的减少重复的出版社信息。我们可以看到,把出版社信息内嵌到每一个书籍记录里面会导致出版社信息的很多次 重复:{ title: "MongoDB: TheDefinitive Guide", author: [ "KristinaChodorow", "MikeDirolf" ], published_date: ISODate("2010-09-24"), pages: 216, language: "English", publisher: { name: "O´Reilly Media", founded: 1980, location: "CA" }}{ title: "50 Tips andTricks for MongoDB Developer", author: "KristinaChodorow", published_date: ISODate("2011-05-06"), pages: 68, language: "English", publisher: { name: "O´Reilly Media", founded: 1980, location: "CA" }}如果不希望重复出版社信息,我们可以使用 文档引用 的方式,把出版社的信息保存在一个单独的集合里面。当使用引用时,文档关系的数量级及增长性会决定我们要在哪里保存引用信息。如果每个出版社所出版的书的数量比较小并且不会增长太多,那么可以在出版社文档里保存所有该出版社所出版的书的引用。反之,如果每个出版社所出版的书籍数量很多或者可能增长很快那么这个书籍引用数组就会不断增长,如下所示:{ name: "O´ReillyMedia", founded: 1980, location: "CA", books: [12346789, 234567890, ...]}{ _id: 123456789, title: "MongoDB: TheDefinitive Guide", author: [ "KristinaChodorow", "MikeDirolf" ], published_date: ISODate("2010-09-24"), pages: 216, language: "English"}{ _id: 234567890, title: "50 Tips andTricks for MongoDB Developer", author: "KristinaChodorow", published_date: ISODate("2011-05-06"), pages: 68, language: "English"}{ _id: "oreilly", name: "O´ReillyMedia", founded: 1980, location: "CA"}{ _id: 123456789, title: "MongoDB: TheDefinitive Guide", author: [ "KristinaChodorow", "MikeDirolf" ], published_date: ISODate("2010-09-24"), pages: 216, language: "English", publisher_id: "oreilly"}{ _id: 234567890, title: "50 Tips andTricks for MongoDB Developer", author: "KristinaChodorow", published_date: ISODate("2011-05-06"), pages: 68, language: "English", publisher_id: "oreilly"}1.2 MongoDB特性和数据模型的关系MongoDB的数据建模不仅仅取决于应用程序的数据需求,也需要考虑到MongoDB本身的一些特性。例如,有些数据模型可以让查询更加有效,有些可以增加**或更新的并发量,有些则可以更有效地把事务均衡到各个分片服务器上。通常需要考虑如下特性:1.2.1 文档增长性 举例来说,如果你的程序的更新操作会导致文档大小增加, 比如说push操作,可能会新增数组中的某个元素, 或者新增一个文档中某个字段,那么你可能要重新设计下数据模型,在不同文档之间使用引用的方式而非内嵌、冗余的数据结构。1.2.2 原子性在MongoDB里面,所有操作在 document 级别具有原子性. 一个 单个 写操作最多只可以修改一个文档。 即使是一个会改变同一个集合中多个文档的命令,在同一时间也只会操作一个文档。尽可能保证那些需要在一个原子操作内进行修改的字段定义在同一个文档里面。如果你的应用程序允许对两个数据的非原子性更新操作,那么可以把这些数据定义在不同的文档内。把相关数据定义到同一个文档里面的内嵌方式有利于这种原子性操作。对于那些使用引用来关联相关数据的数据模型,应用程序必须再用额外的读和写的操作去取回和修改相关的数据。1.2.3 分片MongoDB 使用 sharding (分片)来实现水平扩展。使用分片的集群可以支持海量的数据和高并发读写。用户可以使用分片技术把一个数据库内的某一个集合的数据进行分区,从而达到把数据分布到多个mongod 实例(或分片上)的目的。Mongodb 依据 分片键 分发数据和应用程序的事务请求。 选择一个合适的分片键会对性能有很大的影响,也会促进或者阻碍MongoDB的定向分片查询和增强的写性能。所以在选择分片键时候要仔细考量分片键所用的字段。1.2.4 索引 对常用操作可以使用索引来提高性能。对查询条件中常见的字段,以及需要排序的字段创建索引。MongoDB会对 _id 字段自动创建唯一索引。创建索引时,需要考虑索引的下述特征:[*]Each index requires at least 8 kB of data space.· 每增加一个索引,就会对写操作性能有一些影响。对于一个写多读少的集合,索引会变得很费时因为每个**必须要更新所有索引。· 每个索引都会占一定的硬盘空间和内存(对于活跃的索引)。索引有可能会用到很多这样的资源,因此对这些资源要进行管理和规划,特别是在计算热点数据大小的时候。1.2.5 集合的数量 在某些情况下,你可能会考虑把相关的数据保存到多个而不是一个集合里面。我们来看一个样本集合 logs ,用来存储不同环境和应用程序的日志。 这个 logs 集合里面的文档例子:{ log: "dev", ts: ..., info: ... }{ log: "debug", ts: ..., info: ...}If the total number of documents is low, you may group documentsinto collection by type. For logs, consider maintaining distinct logcollections, such as logs_dev and logs_debug. The logs_dev collection would contain only the documents related to the devenvironment. 一般来说,很大的集合数量对性能没有什么影响,反而在某些场景下有不错的性能。使用不同的集合在高并发批处理场景下会有很好的帮助。当使用有大量集合的数据模型时,请注意一下几点:· 每一个集合有几个KB的额外开销。· Each index, including the index on _id, requires at least 8kB of data space.· 每一个MongoDB的 database 有一个且仅一个命名文件(namespace file)(i.e. .ns) 。这个命名文件保存了数据库的所有元数据。每个索引和集合在这个文件里都有一条记录。这个文件的大小是有限制的,具体信息请参见: :limit:` 命名文件大小限制 `。· MongoDB 的命名文件有大小的限制: · 一个命名文件中可以容纳的命名记录数取决于命名文件 .ns 文件的大小。 命名文件默认的大小限制是16 MB。.2 具体应用建模举例2.1 原子性事务建模 MongoDB的一些写操作如 db.collection.update(), db.collection.findAndModify(),db.collection.remove() 等 具有文档级的事务原子性。对于必须同时修改的字段,把这些字段通过建模放在同一个文档内可以保证这些字段更新的原子性: 要么全部修改,要么一个都不修改。举例来说,假设你在设计一个图书馆的借书系统,你需要管理书的库存量以及出借记录。一本书的可借数量加上借出数量的和必须等于总的保有量,那么对这两个字段的更新必须是原子性的。把available 和 checkout 两个字段放到同一个文档里,就可以做到对这两个字段的原子性事务。{ _id: 123456789, title: "MongoDB: The Definitive Guide", author: [ "Kristina Chodorow", "Mike Dirolf" ], published_date: ISODate("2010-09-24"), pages: 216, language: "English", publisher_id: "oreilly", available: 3, checkout: [ { by: "joe", date: ISODate("2012-10-15") } ]}在更新出借记录的时候,你可以用 db.collection.update() 的方法来对 available 和 checkout两个字段同时更新: db.books.update ( { _id: 123456789, available: { $gt: 0 } }, { $inc: { available: -1 }, $push: { checkout: { by: "abc", date: new Date() } } } )这个操作会返回一个包含操作结果信息的 WriteResult() 对象:WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })其中 nMatched 字段表示 1 个文档匹配指定的条件。 nModified 字段表示 1 个文档被更新。If no document matched theupdate condition, then nMatched and nModified would be 0 and would indicate that you could notcheck out the book.2.2 关键词搜索建模Onthis page注解关键词搜索和文本搜索及全文检索不同,它不提供类似于断词或者词干提取等文本处理功能如果你的应用需要对某个文本字段进行查询,你可以用完全匹配或使用正则表达式 $regex 。但是很多情境下这些手段不能够满足应用的需求。下面这个范式介绍了一种在同一个文档内使用数组来保存关键词再对数组建多键索引 (multi-key index)的方式来实现关键词搜索。为实现关键词搜索,在文档内增加一个数组字段并把每一个关键词加到数组里。然后你可以对该字段建一个 多键索引。这样你就可以对数组里面的关键词进行查询了。例子假如你希望对图书馆的藏书实现一个按主题搜索的功能。 对每一本书,你可以加一个数组字段topics 并把这本书相关的主题都加到这个数组里。对于 Moby-Dick 这本书你可能会有以下这样的文档:{ title : "Moby-Dick" , author : "Herman Melville" , published : 1851 , ISBN : 0451526996 , topics : [ "whaling" , "allegory" , "revenge" , "American" , "novel" , "nautical" , "voyage" , "Cape Cod" ]}然后对 topics 字段建多键索引:db.volumes.createIndex( { topics: 1 } )多键索引会对数组里的每一个值建立一个索引项。在这个例子里 whaling 和 allegory 个各有一个索引项。现在你可以按关键词进行搜索,如:db.volumes.findOne( { topics : "voyage" }, { title: 1 } )注解如果数组较大,达到几百或者几千以上的关键词,那么文档**操作时的索引维护开支会大大增加。2.2.1 关键词索引的局限性MongoDB 的这种关键词搜索方案和专门的全文搜索工具软件相比有以下的局限性:· 词干提取。MongoDB的关键词查询无法对相近词进行归并处理。· 同义词。 对同义词的处理目前必须在应用程序端完成。MongoDB无法支持这一点。· 权重。 关键词之间没有权重支持,所有关键词的重要性都一样,无法优化结果排序。[*]参考文档:https://docs.mongodb.com/v3.2/core/data-modeling-introduction/https://docs.mongodb.com/v3.2/tutorial/model-embedded-one-to-one-relationships-between-documents/
  • [技术干货] Mongodb常用索引介绍
    索引的作用:当一个集合数据量很大时,从这个集合中查找某条记录时,会从这个集合的第一条顺序查找起直到找到特定记录或者查找完整个集合,这个查找时间会很长,查询花费的时间几十秒到几分钟。而索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,当查找特定记录时就从这个特殊的易于遍历的数据结构中查找,查询花费的时间大大的缩短。 创建索引:MongoDB使用 createIndex () 方法来创建索引,具体命令:db.collection. createIndex ({key:1}),其中collection为要在集合上创建索引的集合名, Key 值为你要创建的索引字段,1为指定按升序创建索引,-1为指定按降序创建索引。 索引分类: 单字段索引: 只在一个字段上建立索引,db.collection. createIndex ({key:1}),这样就在集合collection上的字段key创建了升序的单字段索引。建立了单字段索引后,就能加速对key字段的查询速度。Mongodb对每个集合默认建立的_id字段就是一个单字段索引,也是唯一的主键。复合索引: db.collection.createIndex({key:1,key1:1})建立在两个字段key,key1上的复合索引,所谓复合索引就是针对多个字段联合创建的索引,先按第一个字段排序,第一个字段相同的文档按第二个字段排序,依次类推。复合索引不仅能满足多个字段组合起来的查询,也能满足所以能匹配符合索引前缀的查询。例如db.collection.createIndex({key:1,key1:1})不仅能在字段key,key1上加速查询,也能满足只查找key字段的加速查询。但如果只查找key1字段,则无法进行索引加速。如果经常在key1字段上查询,则应该建立db.collection. createIndex ({key1:1,key:1})的符合索引。除了查询的需求能够影响索引的顺序,字段的值分布也是一个重要的因素。如果 key字段的取值很有限,即拥有相同key字段的文档会有很多;而key1字段的取值则丰富很多,拥有相同key1字段的文档很少,则先按key1字段查找,再在相同key1的文档里查找key字段更为高效。hash索引:db.collection.createIndex({key: "hashed"})这样就在字段key上创建了hash索引,mongodb自动计算字段的hash值,无需用户计算,hash索引只能进行字段的完全匹配查询,不能进行范围查询。 索引的一些特殊属性:唯一索引:对于某些字段值,用户希望是唯一的不重复的,这时就可以设置索引的属性为唯一的。db.collection.createIndex({key: 1 },{ unique: true })在创建key字段为索引的时候加上属性字段unique建立的就是唯一单字段索引。db.collection.createIndex({key: 1, key1: 1 },{ unique: true })创建的就是唯一复合索引。TTL索引: 如果希望当某些记录超过一段时间后,自动从数据库里面被删除,那就可以在建立索引的时候带上TTL属性,但需要满足一个条件:建立TTL索引的那个字段必须是data类型的字段或者包含data类型的数组。db. collection.createIndex({"lastModifiedDate": 1 }, { expireAfterSeconds: 3600 }),其中lastModifiedDate字段的类型必须是data或包含data的数组,这样当lastModifiedDate字段的值距离当前时间值超过3600秒后就会被删除。 索引优化: 当一个建立索引的查询依然花费较长时间时,怎么看这个索引存在的问题呢?可以通过查询计划来决定如何优化。在查找语句后面加上.explain()例如: db.collection.find({key:18}).explain(),通过查询的执行计划可以看出索引上是否存在问题:查询的字段没有建立索引,建立了索引但执行查询时没有使用预期的索引。
  • [技术干货] Mongodb原生导入导出工具对比
    总览:当你想把某个mongodb实例中的数据导出,然后再导入到另一mongodb的实例的时候,有两种工具可以选择。导出:mongodump和mongoexport,导入mongorestore和mongoimport。那当我们想导入导出数据时到底应该选择哪种工具呢?下面我们详细分析两种工具的不同点。 mongoexport,mongoimport导出导入的数据格式更丰富 mongoexport可以把实例中的数据导出成JSON, CSV格式的数据。JSON,CSV格式的数据方便人眼阅读,并且很多程序都能处理这些格式的数据。如果要使用一些程序对实例中的数据进行分析,那么JSON,CSV格式的数据便有很大的优势,各种分析处理程序都支持这两种通用的文件格式。而mongodump只能把数据保存为BSON的格式,BSON大家可以把它想象成JSON的二进制模式,既然是二进制模式那肯定人眼是无法直接阅读的,为了能够人眼阅读,需要使用bsondump(mongodb的开源工具)将BSON格式的数据转换成JSON格式的数据,用法很简单 bsondump test.bson > test.json,即可转换成人眼能够阅读的JSON格式数据。 mongoexport导出的数据会丢掉一些数据类型前面说了mongoexport 导出的数据是JSON,CSV格式的数据,而mongodb实例本身里面的数据类型其实是BSON的数据类型。而JSON是无法真正表达所有BSON的数据类型,只能表达BSON数据类型的一个子集,精确的说JSON对某些BSON数据类型使用的是严格模式(strict mode).例如BSON里面对于时间有Date这种数据类型,而转成JSON格式的时候就是一个字符串类型来代表Date,显然这种表示方式会丢掉一些数据类型。所以对于线上正式环境,如果数据类型很多,尽量避免使用mongoexport,mongoimport导出导入数据。以免丢掉源库中的某些数据类型。 mongoexport,mongoimport需要的权限更少 mongoexport导出数据,只需要目标库的read role权限,mongoimport 导入数据只需要目标库readWrite role权限。Mongodump导出数据需要目标库read权限,admin以及local数据库read权限。Mongorestore导入数据需要readWrite权限。显示mongodump需要的权限更多。 mongodump,mongorestore能够使用oplog 如果导出过程比较长,而这段时间变更的数据怎么办呢,大家脑海里冒出来的就是使用oplog来同步这段时间的数据。如果要使用oplog那就只有mongodump和mongorestroe了,这对工具在加了—oplog参数后会将导出这段时间的任何数据变更记录到oplog.bson里面,就可以做到任意时间的数据同步了。而mongoexport和mongoimport就没有这个功能了。 mongoexport,mongoimport不会导出shard模式下的元数据信息Shard模式下。Mongodb实例分为mongos,config,shard。其中config记录的是管理整个集群数据的元数据信息,例如哪些数据存在哪些shard,各个shard的名字以及其中成员信息。对应这些信息mongoexport是不会导出来的,它只是导出数据,然后使用mongoimport将这些数据一条一条**到目标库,而不管目标库的shard个数,因为这些都是目标库自己内部处理的。而mongodump,mongorestroe则可以并行分别导出shard,config数据,这样导出导入数据速度更快,当然也有一个问题如果目标库和源库的shard成员信息不一样,mongorestore导入数据后,还需要将config里面的数据改为目标库对应的信息。否则集群是无法使用的。 总结: 上面就是两对导入导出工具在大方面的不同了,至于细节,大家可以在mongodb官网上阅读他们的使用指南,看他们各自支持的参数。当你面对你的应用环境时到底选择哪种工具,可以参考下这些大方面的不同点,然后选择合适的工具完成你的需要。
  • 【最强大脑】据说这是一道考你是否适合做IT最好的题目……
    本文来源:程序人生 作者:陈老师某公司的两位科学家(甲、乙)去吃饭,坐在一家酒店靠近街道的窗口座位吃饭,在等待上菜的过程中,闲极无聊,甲向乙出了一道猜三个女儿年龄的题目。 甲:我有3个女儿,3人年龄之积等于36; 乙:猜不出来; 甲:3个女儿年龄之和等于街道上的行人数; 乙:还是无法确定; 甲:我的大女儿叫苏珊。乙:哦,我知道了。 请问,甲的3个女儿年龄各是多少?据说这是一道最考你是否适合IT行业、有逻辑思维、逆向思维的题目你是做IT的料吗?快来挑战一下吧~
  • [教程] 使用Content-MD5上传对象出现错误的解决办法
    【问题现象描述】 上传到OBS中的对象的使用图片转码后显示不正常,经过初步分析发现上传的原图是破损的。 我们建议在上传文件时设置Content-MD5值, 以保证服务端对上传的对象进行完整性校验。进一步分析发现客户端使用Android SDK上传对象,设置Content-MD5值后上传出现如下日志:ResponseCode: 400, ResponseStatus: Bad Request, XML ErrorMessage: BadDigest The Content-MD5 you specified didnot match what we received. 101200000163D6154895799445D7A6F8 …… 根据此日志表明客户端MD5值与服务端不匹配,两端 MD5值计算方法不一样。 【问题的根因】 在客户端计算Content-MD5值时先计算MD5加密的二进制数组(128位), 再将二进制数组转成了字符串后再进行的Base64编码。 而服务端生成Content-MD5的原理是:先计算MD5加密的二进制数组(128位), 再对这个二进制进行Base64编码。 因此客户端在计算Content-MD5时需要与服务端原理一致,正确的代码(以AndroidSDK为例):public staticString getMD5File(File file) { FileInputStream in = null; try { in = new FileInputStream(file); FileChannel channel = in.getChannel(); MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0,file.length()); MessageDigest md = MessageDigest.getInstance("MD5"); md.update(buffer); return Base64.encodeToString(md.digest(), Base64.NO_WRAP); } catch (NoSuchAlgorithmException | IOException e) { e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException ignored) { } } } return "";} NO_WRAP参数说明:使用Android SDK Base64编码时要使用NO_WRAP参数【问题结果】客户端侧修改Content-MD5方法后问题解决。
  • 【RDS运维案例--004】如何对RDS慢日志进行查询
    场景描述慢日志记录执行时间超过slowms设定值的语句(默认100ms),通过该日志,可查找出执行效率低的语句,以便优化。解决方案步骤 1 登录管理控制台。步骤 2 单击管理控制台左上角的 ,选择区域和项目。您可选择自己的专属计算集群(DedicatedCoumputing Cluster ,简称DCC)创建实例。步骤 3 选择“数据库> 关系型数据库”。进入关系型数据库信息页面。步骤 4 在数据库“实例管理”页面,查看RDS实例的数据库版本。步骤 5 单击导航树“参数组管理”进入参数组管理页面。步骤 6 单击“创建参数组”,创建同数据库版本的新参数组。步骤 7 单击目标参数组名称,对参数组的参数进行编辑,选择字符串为long_query_time=1并保存。步骤 8 在“实例管理”页面单击目标实例操作栏“更多> 变更参数组”,在“变更参数组”弹框选择本次创建的参数组。单击目标实例操作栏的“更多> 重启实例‘’,重新启动实例。步骤 9 连接RDS数据库。步骤 10 执行两条语句,让执行的时间超过1s。步骤 11 查看慢日志中的记录。----结束
总条数:285 到第
上滑加载中