-
Notifications
You must be signed in to change notification settings - Fork 1
/
201812.txt
561 lines (476 loc) · 36.4 KB
/
201812.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
Codis is a proxy based high performance Redis cluster solution written in GO. It is production-ready and widely used at wandoujia.com and many companies.
"Resharding" means migrating the data in one slot from one redis server to another, usually happens while increading/decreasing the number of redis servers.
Codis, Twemproxy, Redis Cluser的比对:
Codis Twemproxy Redis Cluster
resharding without restartting cluster: Yes No Yes
pipeline: Yes Yes No
hash tags for multi-key operations: Yes Yes Yes
multi-key operations while resharding: Yes - No
Redis clients supporting: Any clients Any Clients Clients have to support cluster protocol
Codis other Features:
- GUI website dashboard & admin tools
- Supports most of Redis commands, Fully compatible with Twemproxy
- Proxies can register on zk/etcd, clients can avoid dead proxies.
/* An int array in which elements may be updated atomically.
*/
public class AtomicIntegerArray implements java.io.Serializable {
private static final long serialVersionUID = 2862133569453604235L;
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final int base = unsafe.arrayBaseOffset(int[].class);
private static final int shift;
private final int[] array;
static {
int scale = unsafe.arrayIndexScale(int[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
shift = 31 - Integer.numberofLeadingZeros(scale);
}
}
StampedLock的等待队列与AQS的CLH队列相比,有如下特点:
1. 当入队一个线程时,如果队尾是读节点,不会直接链接到队尾,而是链接到该读节点的cowait链中,cowait链本质是一个栈;
2. 当入队一个线程时,如果队尾是写节点,则直接链接到队尾;
3. 唤醒线程的规则和AQS类似,都是首先唤醒队首节点。区别是StampedLock中,当唤醒的节点是读节点时,会唤醒该读节点的cowait链中的所有读节点(顺序和入栈顺序相反,也就是后进先出);
另外,StampedLock使用时要特别小心,避免锁重入的操作,在使用乐观读锁时也需要遵循相应的调用模板,防止出现数据不一致问题。
Apollo Features:
- 统一管理不同环境、不同集群的配置;
- 配置修改实时生效(热发布);
- 版本发布管理
- 灰度发布
- 权限管理、发布审核、操作审计;
- 客户端配置信息监控;
- 提供Java和.Net原生客户端;
- 提供开放平台API
- 部署简单;
Apollo客户端的高可用性:通过推拉结合的机制,以及内存和本地文件双缓存的方式,有效地保证了客户端的可用性。
/* A thread managed by a ForkJoinPool, which executes ForkJoinTasks.
This class is subclassable solely fro the sake of adding functionality -- there are no overridable methods dealing with scheduling or execution. However, you can override initialization and termination methods surrounding the main task processing loop. If you do create such a subclass, you will also need to supply a custom ForkJoinPool.ForkJoinWorkerThreadFactory to ForkJoinPool use it in a ForkJoinPool.
*/
public class ForkJoinWorkerThread extends Thread {
...
}
public class AtomicReference<V> implements java.io.Serializable {
private static final long serialVersionUID = -1848883965231344442L;
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long vauleOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset(AtomicReference.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex);}
}
private volatile V value;
...
public final void lazySet(V newValue) {
unsafe.putOrderedObject(this, valueOffset, newValue);
}
}
可以从几个维度对分布式事务进行区分和比较:
1. 一致性:强一致性,最终一致性;
2. 事务:一般都是全局事务;
3. 吞吐量
4. 实现复杂度;
比如常见的:2PC, 3PC,saga长事务,补偿型,可靠事件,TCC。
1987年普林斯顿大学的Hector Garcia-Molina和Kenneth Salem发表了一篇Paper Sagas, 讲述的是如何处理long lived transaction(长活事务)。Saga是一个长活事务可被分解成可以交错运行的子事务集合。其中每个子事务都是一个保持数据库一致性的真实事务。
------------------------------------------------------------------------
Saga和TCC的对比:
Saga相比TCC的缺点是缺少预留动作,导致补偿动作的实现比较麻烦:Ti就是commit,比如一个业务是发送邮件,在TCC模式下,先保存草稿(Try)再发送(Confirm),撤销的话直接删除草稿(Cancel)就可以。而Saga则就直接发送邮件了(Ti),如果要撤销则得再发送一个邮件说明撤销(Ci),实现起来有一些麻烦。
如果把例子换成:A服务在完成Ti后立即发送Event到ESB(企业服务总线),下游服务监听到这个Event做自己的一些工作然后再发送Event到ESB,如果A服务执行补偿动作Ci,那么整个补偿动作的层级就很深。
不过没有预留动作也可以认为是优点:
- 有些业务很简单,套用TCC需要修改原来的业务逻辑,而Saga只需要添加一个补偿动作就行;
- TCC最少通信次数为2n,而Saga为n(n=sub-stransaction的数量)
- 有些第三方服务没有Try接口,TCC模式实现起来就比较tricky了,而Saga则很简单;
- 没有预留动作就意味着不必担心资源释放的问题,异常处理起来也更简单(请对比Saga的恢复策略和TCC的异常处理).
------------------------------------------------------------------------
servicecomb是华为开源的一个微服务框架,后进入Apache孵化,现已毕业,是Apache顶级开源项目,而servicecomb-pack是servicecomb孵化的三个子项目之一,是分布式事务最终一致性解决方案,0.3.0版本之前叫saga,现改名为servicecomb-pack,支持saga和TCC两种分布式事务协议。
Apache ServiceComb Pack is an eventually data consistency solution for micro-service applications. ServiceComb Pack currently provides TCC and Saga distributed transaction co-ordination solutions by using Alpha as a transaction coordinator and Omega as an transaction agent.
/* An unbounded TransfterQueue based on linked nodes. This queue orders elements FIFO with respect to any given producer. The head of the queue is that element that has been on the queue the longest time for some producer. The tail of the queue is that element that has been on the queue the shortest time for some producer.
Beware that, unlike in most collections, the size method is NOT a constant-time operation. Because of the asynchronous nature of these queues, determining the current number of elements requires a traversal of the elements, and so may report inaccurate results if this collection is modified during traversal. Additionally, the bulk operations addAll, removeAll, retainAll, containsAll, equals, and toArray are not guaranteed to be performed atomically. For example, an iterator operating concurrently with an addAll operation might view only some of the added elements.
This class and its iterator implement all of the optional methods of the Collection and Iterator interfaces.
Memory consistency effects: A with other concurrent collections, actions in a thread prior to placing an object into a LinkedTransferQueue happen-before actions subsequent to the access or removal of that element from the LinkedTransferQueue in another thread.
*/
public class LinkedTransferQueue<E> extends AbstractQueue<E>
implements TransferQueue<E>, java.io.Serializable {
...
}
HashMap的并发问题:
1. 脏读;
2. JDK7会出现链表环形,导致get查找一个不存在key时,程序会进入死循环。
3. 扩容时,有可能会出现浪费空间
4. 更新丢失/覆盖丢失的问题;
----------------------------------------------------------------------------------------
对于 LinkedTransferQueue,Doug Lea进行了尽乎极致的优化。Grizzly的采用了PaddedAtomicReference :
PaddedAtomicReference相对于父类AtomicReference只做了一件事情,就将共享变量追加到64字节。计算下,一个对象的引用占4个字节,它追加了15个变量共占60个字节,再加上父类的Value变量,一共64个字节。上面追加15个4字节对象的代码看起来是不是很奇葩?其实不是的, 这样做是为了在并发中提升效率。
为什么追加64字节能够提高并发编程的效率呢 ? 因为对于英特尔酷睿i7,酷睿,Atom和NetBurst,Core Solo和Pentium M处理器的L1L2或L3缓存的高速缓存行是64个字节宽,不支持部分填充缓存行,这意味着如果队列的头节点和尾节点都不足64字节的话,处理器会将它们都读到同一个高速缓存行中,在多处理器下每个处理器都会缓存同样的头尾节点,当一个处理器试图修改头接点时会将整个缓存行锁定,那么在缓存一致性机制的作用下,会导致其他处理器不能访问自己高速缓存中的尾节点,而队列的入队和出队操作是需要不停修改头接点和尾节点,所以在多处理器的情况下将会严重影响到队列的入队和出队效率。Doug lea使用追加到64字节的方式来填满高速缓冲区的缓存行,避免头接点和尾节点加载到同一个缓存行,使得头尾节点在修改时不会互相锁定。
那么是不是在使用Volatile变量时都应该追加到64字节呢?不是的。在两种场景下不应该使用这种方式。第一: 缓存行非64字节宽的处理器 ,如P6系列和奔腾处理器,它们的L1和L2 高速缓存行是32个字节宽。第二: 共享变量不会被频繁的写 。因为使用追加字节的方式需要处理器读取更多的字节到高速缓冲区,这本身就会带来一定的性能消耗,共享变量如果不被频繁写的话,锁的几率也非常小,就没必要通过追加字节的方式来避免相互锁定。
----------------------------------------------------------------------------------------
/* An AtomicMarkableReference maintains an object reference along with a mark bit, that can be updated atomically.
Implementation note: This implementation maintains markable references by creating internal objects representing "boxed" [reference, boolean] pairs.
*/
public class AtomicMarkableReference<V> {
...
}
public class AtomicStampedReference<V> {
private static class Pair<T> {
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
}
private volatile Pair<V> pair;
public AtomicStampedReference(V initialRef, int initialStamp) {
pair = Pair.of(initialRef, initialStamp);
}
public V getReference() {
return pair.reference;
}
public int getStamp() {
return pair.stamp;
}
public V get(int[] stampHolder) {
Pair<V> pair = this.pair;
stampHolder[0] = pair.stamp;
return pair.reference;
}
public boolean weakCompareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
return compareAndSet(expectedReference, newReference,
expectedStamp, newStamp);
}
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference && newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
}
public void set(V newReference, int newStamp) {
Pair<V> current = pair;
if (newReference != current.reference || newStamp != current.stamp)
this.pair = Pair.of(newReference, newStamp);
}
public boolean attempStamp(V expectedReference, int newStamp) {
Pair<V> current = pair;
return expectedReference == current.reference &&
(newStamp == current.stamp ||
casPair(current, Pair.of(expectedReference, newStamp)));
}
//Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long pairOffset = objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);
private boolean casPair(Pair<V> cmp, Pair<V> val) {
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) {
try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
} catch (NoSuchFieldException e) {
NoSuchFieldError error = new NoSuchFieldError(field);
error.initCause(e);
throw error;
}
}
}
写一个word-count用到哪些命令,三个方案:
1. cat xxx.txt|tr -s ' ' '\n'|sort|uniq -c|sort -r|awk '{print $2, $1}'
缺点:大小写敏感;会包含标点符号;
2. awk -F" " '{for(i=1;i<=NF;i++) {array[$i]+=1;}} END{for (s in array){print s" "array[s];}}' xxx.txt|sort -nr -k 2
缺点:大小写敏感;会包含标点符号;
3. cat xxx.txt|tr 'A-Z' 'a-z'|egrep -o "\b[[:alpha:]]+\b"
|awk '{count[$0] ++ END{for(ind in count) {printf("%-14s%d\n", ind, count[ind]);}}'
|sort -k2 -n -r
HashMap.Node:
public class HashMap<K, V> extends AbstractMap<K, V>
implements Map<K, V>, Cloneable, Serializable {
...
//Tree bins
/* Entry for Tree bins. Extends LinkedHashMap.Entry(which in turn extends Node) so can be used as extension of either regular or linked node.
*/
static final class TreeNode<K, V> extends LinkedHashMap.Entry<K, V> {
TreeNode<K, V> parent; //red-black tree links
TreeNode<K, V> left;
TreeNode<K, V> right;
TreeNode<K, V> prev; // needed to unlink next upon deletion
boolean read;
}
}
redis获取一个有序列表的前10个元素用什么命令: lrange <key> 0 9
可以通过在字段之间通过填充长整型变量的方式把热点变量隔离在不同的缓存行中,减少伪同步,在多核CPU中极大的提升效率。
Java对象中的元数据指针是一个引用类型,正常来说64位机器元数据指针为8字节,32位机器元数据指针为4字节,但是HotSpot中有一项优化是对元数据类型指针进行压缩存储,使用JVM参数:-XX:+UseCompressedOops开启压缩。
开发一个新的API,需要考虑哪些方面?
1. 哪种请求模式,get/post/put/delete; 是否符合Restful规范
2. 版本;版本兼容性:向前兼容/向后兼容
3. 应答的设计;如何标注成功/失败,失败的提示是否合理;
4. 安全性:SSL, 授权/权限,Token等;
5. 良好的接口说明文档和测试案例;
6. 接口的相关统计功能;
7. 接口调用频率的控制;
8. 应答是否需要分页;
/*
*/
public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
}
Instrumentation.getObjectSize(Object objectToSize); 这个方法不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小。
MySQL和ElasticSearch的区别:
1. ES是分布式全文搜索引擎;MySQL是关系型数据库;
2. ES天然支持分布式(shard, replicator)
3. MySQL支持事务;ES不支持事务;
4. ES支持灵活的Json格式存储,可以不用预先定义格式;
5. ES使用倒排索引;MySQL-InnoDB使用B+树索引;
6.
ParNew用于垃圾回收的线程可用参数-XX:ParalleGCThreads=n进行配置,建议与CPU数一致。ParNew是许多运行在Server模式下的虚拟机中首选的新生代收集器,除了Serial收集器外,只有它能与CMS收集器配合工作。
-XX:MaxTenuringThreshold=15
-XX:+UseConcMarkSweepGC
-XX:+DisableExplicitGC
/* Handlers all registry requests from eureka clients.
Primary operations that are performed are the Registers, Renewals, Cancels, Expirations, and status Changes. The registry also stores only the delta operations.
*/
public abstract class AbstractInstanceRegistry implements InstanceRegistry {
private static final Logger logger = LoggerFactory.getLogger(AbstractInstanceRegistry.class);
private static final String[] EMPTY_STR_ARRAY = new String[0];
private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>> registry =
new ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>();
protected Map<String, RemoteRegionRegistry> regionNameVSRemoteRegistry = new HashMap<String, RemoteRegionRegistry>();
protected final ConcurrentMap<String, InstanceStatus> overriddenInstanceStatusMap = CacheBuilder
.newBuilder().initialCapacity(500)
.expireAfterAccess(1, TimeUnit.HOURS)
.<String, InstanceStatus>build().asMap();
// CircularQueues here for debugging/statistics purposes only
private final CircularQueue<Pair<Long, String>> recentRegisteredQueue;
private final CircularQueue<Pair<Long, String>> recentCanceledQueue;
private ConcurrentLinkedQueue<RecentlyChangedItem> recentlyChangedQueue = new ConcurrentLinkedQueue<RecentlyChangedItem>();
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final Lock read = readWriteLock.readLock();
private final Lock write = readWriteLock.writeLock();
private Timer deltaRetentionTimer = new Timer("Eureka-DeltaRetentionTimer", true);
private Timer evictionTimer = new Timer("Eureka-EvictionTimer", true);
private final MeasuredRate renewsLastMin;
private final AtomicReference<EvictionTask> evictionTaskRef = new AtomicReference<EvitionTask>();
protected String[] allKnownRemoteRegions = EMPTY_STR_ARRAY;
protected volatile int numberOfRenewsPerMinThreshold;
protected volatile int expectedNumberOfRenewsPerMin;
protected final EurekaServerConfig serverConfig;
protected final EurekaClientConfig clientConfig;
protected final ServerCodecs serverCodecs;
protected volatile ResponseCache responseCache;
...
}
-XX:+PrintGCApplicationConcurrentTime: 打印应用执行的时间
-XX:+PrintGCApplicationStoppedTime: 打印应用被暂停的时间
-Djava.util.Arrays.useLegacyMergeSort=true: 使用JDK6之前的MergeSort,而不是JDK7的TimSort,因为TimSort的对象compare需要满足三个条件,其中一个很难满足:sgn(compare(x, y)) == -sgn(compare(y, x);所以为了兼容JDK6,可以使用这个标识。
-Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.EPollSelectorProvider: 启用NIO的epoll,对并发idle connection会有大幅度的性能提升。
-XX:+ExplicitGCInvokesConcurrent: 指定显式的GC,即System.gc(),也是并发执行的。而不是STW的。
-XX:SoftRefLRUPolicyMSPerMB:
-XX:+CMSClassUnloadingEnabled:
/* A reflection-based utility that enables atomic updates to designated (volatile long) fields of designed classes.
This class is designed for use in atomic data structures in which serveral fields of the same node are independently subject to atomic updates.
Note that the guarantees of the compareAndSet method in this class are weaker than in other atomic classes.Because this class cannot ensure that all uses of the field are appropriate for purpose of atomic access, it can guarantee atomicity only with respect to other invocations of compareAndSet and set on the same updater.
*/
public abstract class AtomicLongFieldUpdater<T> {
...
/* Atomically updates the field of the given object managed by this updater with the results of applying the given function to be current and given values, returning the updated value. The function should be side-effect-free, since it may be re-applied when attempted updates fails due to contention among threads. The function is applied with the current value as its first argument, and the given update as the second argument.
*/
public final long accumulateAndGet(T obj, long x, LongBinaryOperator accumulatorFunction) {
long prev, next;
do {
prev = get(obj);
next = accumulatorFunction.applyAsLong(prev, x);
} while (!compareAndSet(obj, prev, next));
return next;
}
...
}
-XX:+UseCMSInitiatingOccupancyOnly : 告知JVM不基于运行时收集的数据来启动CMS垃圾收集周期。而是,当该标志开启时,JVM通过CMSInitiatingOccupancyFraction的值进行每一次CMS收集。
-XX:+CMSInitiatingOccupancyFraction=60: 设定CMS在对内存占用率达到60%的时候,开始GC(因为CMS有浮动垃圾,所以一般都较早启动GC);
jmap -histo:live <PID>
-------------------------------------------------------
添加下面两个参数强制在remark阶段和FGC阶段之前先进行一次YGC,减少CMS-Remark的内存量。
-XX:+ScavengeBeforeFullGC
-XX:+CMSScavengeBeoreRemark
FGC阶段之前先进行一次YGC的意义是:Yong区对象引用了Old区的对象,如果在Old区进行清理之前不进行Yong区清理,就会导致Old区被Yong区引用的对象无法释放。
结论:
1. 在CMS-remark阶段需要对堆中所有的内存对象进行处理,如果在这个阶段之前强制执行一次年轻代的GC会大量减少remark需要处理的内存数量,进而降低JVM卡顿对请求的影响;
2. 对Java HTTP服务,JVM的卡顿时间应该小于HTTP客户端的调用超时时间,否则JVM卡顿对请求造成影响。
-------------------------------------------------------
-XX:+UseCMSCompactAtFullCollection: 在FGC时,对老年代进行压缩;CMS是不会移动内存的,因此,会产生碎片,导致内存不够用,因此内存的压缩这个时候就会被启用。增加这个参数是比较好的,可能会影响性能,但是可以消除碎片。
-XX:CMSFullGCsBeforeCompaction=9: 由于CMS不对内存空间进行压缩整理,所以运行一段时间以后会产生碎片,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩整理。
-----------------------------------------------------------------------------------------
CMS GC要决定是否在FGC时做压缩,会依赖几个条件。其中:
- 第一种条件:UseCMSCompactAtFullCollection与CMSFullGCsBeforeCompaction搭配使用,前者默认True,关键在后者上;
- 第二种:调用了System.gc(), 而且DisableExplicitGC没有开启;
- 第三种:YGC做增量收集失败;即YGC预估Old区没有足够空间来容纳下次YGC晋升的对象;
上述三种条件的任意一种成立都会让CMS决定这次FGC要做压缩。
CMSFullGCsBeforeCompaction 说的是,在上一次CMS并发GC执行过后,到底还要再执行多少次full GC才会做压缩。默认是0,也就是在默认配置下每次CMS GC顶不住了而要转入full GC的时候都会做压缩。 把CMSFullGCsBeforeCompaction配置为10,就会让上面说的第一个条件变成每隔10次真正的full GC才做一次压缩(而不是每10次CMS并发GC就做一次压缩,目前VM里没有这样的参数)。这会使full GC更少做压缩,也就更容易使CMS的old gen受碎片化问题的困扰。 本来这个参数就是用来配置降低full GC压缩的频率,以期减少某些full GC的暂停时间。CMS回退到full GC时用的算法是mark-sweep-compact,但compaction是可选的,不做的话碎片化会严重些但这次full GC的暂停时间会短些;这是个取舍。
-----------------------------------------------------------------------------------------
-XX:+CMSParallelRemarkEnabled: 在CMS最初的实现中,初始标记和重新标记都是单线程的,但现在都已经修改为多线程的。激活多线程的初始标记和重新标记阶段的JVM选项分别是:-XX:+CMSParalleInitialMarkEnabled和-XX:+CMSParallelRemarkEnabled。
----------------------------------------------
-XX:-ReduceInitialCardMarks: 为了解决一个JDK1.6.0_18的已知Bug,其主要原因是card-marking performance optimization算法在实现的时候有瑕疵,在某些情况下会引起heap corruption。这个情况发生在新创建的大对象和Eden space大小差不多,然后JVM做YGC的时候。解决方案:启动参数添加:-XX:-ReduceInitialCardMarks将性能优化策略关闭。
----------------------------------------------
-XX:+CMSPermGenSweepingEnabled和-XX:+CMSClassUnloadingEnabled配合同时启用,对PermGen进行GC。
-XX:CMSInitiatingPermOccupancyFraction=70:当永久代占用率达到此值时,启动CMS回收。
The Executor implementations provided in this package implement ExecutorService, which is a more extensive interface. The ThreadPoolExecutor class provided an extensible thread pool implementation. The Executors class provides convenient factory methods for these Executors.
自适应自旋锁:线程空循环等待的自旋次数并非是固定的,而是会动态根据实际情况来改变自旋等待的次数。
能否从偏向锁直接升级为重量级锁: 如果对于某个锁,一个线程自旋之后,很少成功获得该锁,那么以后这个线程获取该锁时,是有可能直接忽略掉自旋过程,直接升级为重量级锁,以免空循环等待浪费资源。
---------------------------------------------
mysql主从同步原理:主库针对写操作,顺序写binlog,从库单线程去主库顺序读”写操作的binlog”,从库取到binlog在本地原样执行(随机写),来保证主从数据逻辑上一致。
mysql的主从复制都是单线程的操作,主库对所有DDL和DML产生binlog,binlog是顺序写,所以效率很高,slave的Slave_IO_Running线程到主库取日志,效率比较高,下一步,问题来了,slave的Slave_SQL_Running线程将主库的DDL和DML操作在slave实施。DML和DDL的IO操作是随即的,不是顺序的,成本高很多,还可能可slave上的其他查询产生lock争用,由于Slave_SQL_Running也是单线程的,所以一个DDL卡主了,需要执行10分钟,那么所有之后的DDL会等待这个DDL执行完才会继续执行,这就导致了延时。
有朋友会问:“主库上那个相同的DDL也需要执行10分,为什么slave会延时?”,答案是master可以并发,Slave_SQL_Running线程却不可以。
MySQL数据库主从同步延迟是怎么产生的?
当主库的TPS并发较高时,产生的DDL数量超过slave一个sql线程所能承受的范围,那么延时就产生了,当然还有就是可能与slave的大型query语句产生了锁等待。
首要原因:数据库在业务上读写压力太大,CPU计算负荷大,网卡负荷大,硬盘随机IO太高
次要原因:读写binlog带来的性能影响,网络传输延迟。
---------------------------------------------
在数据库主从同步的情况下,如果从库同步主库的数据延迟比较高,怎么才能写到主库后立刻能够读取到数据?
1. 启用MySQL5.6支持的Semi-Sync半同步功能;
2. 启用Redis缓存,但不保证强一致的事务;另外还需要注意数据一致性;
3. 进行数据分片,分库分表,分散从库的同步压力;
4. 升级到MySQL5.7,多线程复制,几乎完美解决单线程复制引起的从库延迟;
ThreadPoolExecutor: This class provides protected overridable beforeExecute(Thread, Runnable) and afterExecute(Runnable, Throwable) methods that are called before and after execution of each task. These can be used to manipulate the execution environment; for example, reinitializing ThreadLocals, gathering statistics, or adding log entries. Additionally, method terminated can be overridden to perform any special processing that needs to be done once the Exceutor has fully terminated.
权限系统的可扩展性:
1. 角色的树形结构支持;
2. 权限的功能点和资源的对应关系设计成1对N;
3. 对于各种资源的扩展支持:页面, URL,文件等其他资源;从权限中再抽取一种关系;
4. 权限的分组或者类似于角色的树形结构支持;
5. 权限系统的审计跟踪功能,操作日志表;
6. 对资源类型的管理称为粗粒度权限管理;对资源实例的控制称为细粒度权限管理;
7. 对粗粒度的权限管理可以很容易做系统架构级别的功能,即系统功能操作使用统一的粗粒度的权限管理;
8. 对细粒度的权限管理不建议做成系统架构级别的功能,因为这属于业务需求,变化性比较大;
几种BlockingQueue的实现类:
1. ArrayBlockingQueue;
2. DelayedWorkQueue;
3. DelayQueue
4. LinkedBlockingQueue
5. PriorityBlockingQueue
6. SynchronousQueue
7. BlockingDeque
8. LinkedTransferQueue
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable{...}
ScheduledThreadPoolExecutor的内部类: static class DelayedWorkQueue extends AbstractQueue<Runnable> implements BlockingQueue<Runnable>{...}
public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E> {...}
public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable {...}
public class PriorityBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable {...}
public class SynchronousQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable {...}
public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {...}
public class LinkedBlockingDeque<E> extends AbstractQueue<E> implements BlockingDeque<E>, java.io.Serializable {...}
public interface TransferQueue<E> extends BlockingQueue<E> {...}
public class LinkedTransferQueue<E> extends AbstractQueue<E> implements TransferQueue<E>, java.io.Serializable {...}
Redis的字典渐进式扩容与ConcurrentHashMap的扩容策略比较:
1. 扩容所花费的时间比对:一个单线程渐进扩容,一个多线程协同扩容。在平均的情况下,是ConcurrentHashMap快。意味着,扩容时所需要花费的空间能够更快的进行释放。
2. 读操作,两者差不多;
3. 写操作,Redis字典返回更快些,因为不像ConcurrentHashMap那样去帮着扩容(当要写的桶已经迁移到newTable时),等扩容完才能进行操作;
4. 删除操作,与写一样。
所以选择单线程渐进式扩容还是选择多线程协同扩容,需要具体问题具体分享。
1. 如果内存资源吃紧,希望能够尽快扩容来释放扩容时需要的辅助空间,那么选择多线程协同扩容;
2. 如果对于写和删除操作要求迅速,那么可以选择单线程渐进式扩容。
从现有机器多核的情况来看,ConcurrentHashMap的扩容策略更好一些。
-------------------------------------
redis中的hash如何扩容:
首先Redis的字典采用的是一种'单线程渐进式rehash',这里的单线程是指只有一个线程在扩容,而在扩容的同时其他的线程可以并发的进行读写。
Redis系统后台会定时给予扩容的那个线程足够的运行时间,这样不会导致它饿死。大致过程是这样的:
ht[0],是存放数据的table,作为非扩容时容器。
ht[1],只有正在进行扩容时才会使用,它也是存放数据的table,长度为ht[0]的两倍。
扩容时,单线程A负责把数据从ht[0] copy到ht[1] 中。如果这时有其他线程进行读操作:会先去ht[0]中找,找不到再去ht[1]中找。
进行写操作:直接写在ht[1]中。
进行删除操作:与读类似。
当然这过程中会设计到一系列的锁来保证同步性,不过这并不是本文的重点。
而ConcurrentHashMap采用的扩容策略为: '多线程协同式rehash'。
这里的多线程指的是,有多个线程并发的把数据从旧的容器搬运到新的容器中。
扩容时大致过程如下:
线程A在扩容把数据从oldTable搬到到newTable,这时其他线程进行get操作:这个线程知道数据存放在oldTable或是newTable中,直接取即可。
进行写操作:如果要写的桶位,已经被线程A搬运到了newTable。
那么这个线程知道正在扩容,它也一起帮着扩容,扩容完成后才进行put操作。
进行删除操作:与写一致。
--------------------------------------
JDK中哪些地方用到了哪些设计模式:
1. 观察者模式:Observalbe类和Observer接口;javax.servlet.http.SessionBindingListener; java.util.EventListener;
2. 桥接模式: Set<String> names = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());JDBC;
3. 装饰模式: BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); Collections#synchronized***();Collections#unmodifiable***;javax.servlet.http.HttpServletRequestWrapper;HttpServletResponseWrapper;
4. 原型模式: Object#clone(),包括浅克隆和深克隆
5. 建造者模式: StringBuilder, StringBuffer,实现了java.lang.Appendable接口的类
6. 工厂方法: Calendar calendar = java.util.Calendar.getInstance();java.lang.Class#newInstance();java.lang.reflect.Array#newInstance();java.lang.reflect.Constructor#newInstance();
7. 适配器模式: java.util.Arrays.asList(new Integer[]{1,2,3}); java.util.Arrays.asList(1,2,3);
8. 享元模式(Flyway): java.lang.Integer#valueOf(int);Boolean#valueOf();Byte#value();
9. 策略模式: java.util.Comparator#compare(); Servlet
10. 抽象工厂模式: java.util.ResourceBundle#getBundle();java.sql.DriverManager#getConnection();java.nio.charset.Charset#forName();java的AWT中的Button和Text等构件在Windows和Unix中的本地实现是不同的。
11. 单例模式: java.lang.Runtime.getRuntime();Unsafe.getUnsafe();
12. 组合模式: javax.swing.JComponent#add(Component);java.awt.Container#add(Component);Map#putAll(Map);List#addAll(Collection);
13. 代理模式: java.lang.reflect.Proxy;java.rmi.*;
14. 职责链模式:javax.servlet.Filter#doFilter();
15. 命令模式:Runnable;Callable;
16. 解释器模式: java.util.Pattern;java.text.Format;jvaax.el.ELResolver;
17. 迭代器模式: Iterator;Enumeration;
18. 中介者模式: Executor;ScheduledExecutorService;Method#invoke();
19. 备忘录模式: java.io.Serializable;
20. 状态模式:
21. 模板方法模式:java.util.AbstractList;AbstractSet;HttpServlet#do***();
22. 访问者模式:AnnotationValue和AnnotationValue;java.lang.model.element.Element和ElementVistor;java.lang.model.type.TypeMirror和TypeVisitor;
23. 门面模式:java.lang.Class;
--------------------------------------
Sentinel的滑动窗口统计机制:Sentinel处理流程是基于Slot链(ProcessorSlotChain)来完成的,比如限流、熔断等,其中重要的一个Slot就是StatisticSlot,做各种数据统计,而限流/熔断的数据判断来源就是StatisticSlot,StatisticSlot的各种数据统计都是基于滑动窗口来完成的。Sentinel的Slot链(ProcessorSlotChain)是责任链模式的体现。
public final class Integer extends Number implements Comparable<Integer> {
...
/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high) {
return IntegerCache.cache[i + (-IntegerCache.low)];
}
return new Integer(i);
}
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
//high value may be configured by property
int h = 127;
String integerCacheHigPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHigPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
prvate IntegerCache() {}
}
}