Flink异步IO结合Redisson访问Redis

金九银十后端面试备战指南:从原理到实战的系统提升 技术面试不仅考察知识记忆,更关注候选人对原理的理解与工程实战能力。以Java集合、MySQL索引、Redis缓存等高频考点为例,面试官往往通过层层追问检验候选人是否真正理解数据结构设计、事务隔离机制与缓存一致性等核心概念。掌握B+树为何适用于磁盘存储、MVCC如何实现快照读、缓存穿透与雪崩的取舍等原理,才能体现技术深度。在项目复盘环节,用数据量化优化效果、讲清排查链路,是区分候选人的分水岭。系统设计与场景题则需从容量估算、技术选型到容错扩展的完整思考。金九银十窗口期,从基础原理到项目表达的系统化备战指南,正 阅读详情

 

 发表于 2019-07-15 |  分类于 大数据 |  0 | 本文总阅读量 165次

Flink异步IO源码简析。
使用Redisson框架封装的异步请求API。
对key进行异步累计递增计数和计算业务值并保存在Redis中。
Lua脚本和事务API。

FLINK v2-异步IO的设计与实现
Flink使用异步IO访问外部数据
AsyncRedisJob代码

AsyncFunction

 AsyncFunction是一个异步算子接口,本身继承Function和Serializable。
 asyncInvoke()方法会对每一个上游任务下发的流数据进行异步操作,操作完了将结果输出到ResultFuture,回调方式是把ResultFuture传入回调API,Future方式是要调用resultFuture.complete才算异步调用完成【回调和Future看外部系统客户端的封装】。
 timeout()方法用来处理异步调用超时的问题,有default修饰,有默认实现,可以不做处理,但通常要做进一步处理。

 

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
@PublicEvolving
public interface AsyncFunction<IN, OUT> extends Function, Serializable {

	/**
	 * Trigger async operation for each stream input.
	 *
	 * @param input element coming from an upstream task
	 * @param resultFuture to be completed with the result data
	 * @exception Exception in case of a user code error. An exception will make the task fail and
	 * trigger fail-over process.
	 */
	void asyncInvoke(IN input, ResultFuture<OUT> resultFuture) throws Exception;

	/**
	 * {@link AsyncFunction#asyncInvoke} timeout occurred.
	 * By default, the result future is exceptionally completed with a timeout exception.
	 *
	 * @param input element coming from an upstream task
	 * @param resultFuture to be completed with the result data
	 */
	default void timeout(IN input, ResultFuture<OUT> resultFuture) throws Exception {
		resultFuture.completeExceptionally(
			new TimeoutException("Async function call has timed out."));
	}

}

 AsyncFunction的使用:可以通过直接实现AsyncFunction接口的方式来自定义访问外部系统,比如HBase。

使用回调函数的例子:

1
2
3
4
5
6
7
8
public class HBaseAsyncFunc implements AsyncFunction<String, String> {
 
    public void asyncInvoke(String row, ResultFuture<String> result) throws Exception {
      HBaseCallback cb = new HBaseCallback(result);
      Get get = new Get(Bytes.toBytes(row));
      hbase.asyncGet(get, cb);
    }
}

 

使用Future的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class HBaseAsyncFunc implements AsyncFunction<String, String> {

        public void asyncInvoke(String row, final ResultFuture<String> result) throws Exception {
            Get get = new Get(Bytes.toBytes(row));
            ListenableFuture<Result> future = hbase.asyncGet(get);
            Futures.addCallback(future, new FutureCallback<Result>() {
                public void onSuccess(Result result) {
                    List<String> ret = process(result);
                    result.complete(ret);
                }

                public void onFailure(Throwable thrown) {
                    result.completeExceptionally(thrown);
                }
            });
        }
    }
}

 

RichAsyncFunction

 RichAsyncFunction是个抽象类,由于继承了AbstractRichFunction,也就实现了RichFunction,RichFunction里面有着更多比较有用的方法,比如可以使用重新实现后的RuntimeContext。
 Function是在DataStream里的各种算子中被调用的。
 异步的AsyncFunction会被传入AsyncWaitOperator中,AsyncWaitOperator的processElement方法会去调用asyncInvoke(),会注册一个定时器去调用timeout()方法。
 AsyncWaitOperator是在异步的DataStream辅助类AsyncDataStream中被实例化后传入DataStream的transform()方法中被调用【算子名称是「async wait operator」】。

RichFunction接口

1
2
3
4
5
6
7
8
9
10
11
12
@Public
public interface RichFunction extends Function {
    void open(Configuration var1) throws Exception;

    void close() throws Exception;

    RuntimeContext getRuntimeContext();

    IterationRuntimeContext getIterationRuntimeContext();

    void setRuntimeContext(RuntimeContext var1);
}

 

 RichAsyncFunction接口,主要是实现了RichAsyncFunctionIterationRuntimeContext和RichAsyncFunctionRuntimeContext。
 RichAsyncFunctionRuntimeContext:这个运行时上下文只支持线程安全的一些基本操作,像状态、全局累加、广播变量和分布式缓存都是不支持的。
 RichAsyncFunctionIterationRuntimeContext:本身继承RichAsyncFunctionRuntimeContext,所以限制同上,只是实现了IterationRuntimeContext接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@PublicEvolving
public abstract class RichAsyncFunction<IN, OUT> extends AbstractRichFunction implements AsyncFunction<IN, OUT> {
    private static final long serialVersionUID = 3858030061138121840L;

	@Override
	public void setRuntimeContext(RuntimeContext runtimeContext) {
		Preconditions.checkNotNull(runtimeContext);

		if (runtimeContext instanceof IterationRuntimeContext) {
			super.setRuntimeContext(
				new RichAsyncFunctionIterationRuntimeContext(
					(IterationRuntimeContext) runtimeContext));
		} else {
			super.setRuntimeContext(new RichAsyncFunctionRuntimeContext(runtimeContext));
		}
	}

	@Override
	public abstract void asyncInvoke(IN input, ResultFuture<OUT> resultFuture) throws Exception;
	...
	...
}

AsyncWaitOperator

 主要看下processElement()方法,它是在OneInputStreamOperator接口中定义的,OneInputStreamOperator继承自StreamOperator接口。
 另外,如果需要自定义Operator,可以继承AbstractStreamOperator,也可以通过实现OneInputStreamOperator或TwoInputStreamOperator。
 AbstractUdfStreamOperator是用于自定义Function的抽象类,主要是用来处理自定义Function的打开和关闭;它也是StreamOperator,因为它继承了AbstractStreamOperator,而AbstractStreamOperator实现了StreamOperator。

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
@Internal
public class AsyncWaitOperator<IN, OUT>
		extends AbstractUdfStreamOperator<OUT, AsyncFunction<IN, OUT>>
		implements OneInputStreamOperator<IN, OUT>, OperatorActions {

    @Override
    ...
    public void processElement(StreamRecord<IN> element) throws Exception {
        final StreamRecordQueueEntry<OUT> streamRecordBufferEntry = new StreamRecordQueueEntry<>(element);
    
        if (timeout > 0L) {
            // register a timeout for this AsyncStreamRecordBufferEntry
            long timeoutTimestamp = timeout + getProcessingTimeService().getCurrentProcessingTime();
    
            final ScheduledFuture<?> timerFuture = getProcessingTimeService().registerTimer(
                timeoutTimestamp,
                new ProcessingTimeCallback() {
                    @Override
                    public void onProcessingTime(long timestamp) throws Exception {
                        userFunction.timeout(element.getValue(), streamRecordBufferEntry);
                    }
                });
    
            // Cancel the timer once we've completed the stream record buffer entry. This will remove
            // the register trigger task
            streamRecordBufferEntry.onComplete(
                (StreamElementQueueEntry<Collection<OUT>> value) -> {
                    timerFuture.cancel(true);
                },
                executor);
        }
    
        addAsyncBufferEntry(streamRecordBufferEntry);
    
        userFunction.asyncInvoke(element.getValue(), streamRecordBufferEntry);
    }
    ...
}

AsyncDataStream

 AsyncDataStream是DataStream的辅助类,提供unorderedWait和orderedWait的静态方法,方法里是添加异步算子即AsyncWaitOperator。
 其中维护了一个有序和无序的枚举,一个默认的队列容量100。
 需要传入一个上游的DataStream、一个自定义的AsyncFunction(RichAsyncFunction)和超时时间,缓冲区队列大小和顺序可以默认。

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
@PublicEvolving
public class AsyncDataStream {
    public enum OutputMode { ORDERED, UNORDERED }

	private static final int DEFAULT_QUEUE_CAPACITY = 100;

	/**
	 * Add an AsyncWaitOperator.
	 *
	 * @param in The {@link DataStream} where the {@link AsyncWaitOperator} will be added.
	 * @param func {@link AsyncFunction} wrapped inside {@link AsyncWaitOperator}.
	 * @param timeout for the asynchronous operation to complete
	 * @param bufSize The max number of inputs the {@link AsyncWaitOperator} can hold inside.
	 * @param mode Processing mode for {@link AsyncWaitOperator}.
	 * @param <IN> Input type.
	 * @param <OUT> Output type.
	 * @return A new {@link SingleOutputStreamOperator}
	 */
	private static <IN, OUT> SingleOutputStreamOperator<OUT> addOperator(
			DataStream<IN> in,
			AsyncFunction<IN, OUT> func,
			long timeout,
			int bufSize,
			OutputMode mode) {

		TypeInformation<OUT> outTypeInfo = TypeExtractor.getUnaryOperatorReturnType(
			func,
			AsyncFunction.class,
			0,
			1,
			new int[]{1, 0},
			in.getType(),
			Utils.getCallLocationName(),
			true);

		// create transform
		AsyncWaitOperator<IN, OUT> operator = new AsyncWaitOperator<>(
			in.getExecutionEnvironment().clean(func),
			timeout,
			bufSize,
			mode);

		return in.transform("async wait operator", outTypeInfo, operator);
	}
	...
}

AsyncRedisRequest

 示例,没有太多逻辑。
 继承自RichAsyncFunction。
 在open方法中创建RedissonClient。
 在close方法中关闭RedissonClient。
 在asyncInvoke实现异步调用。
 在timeout中处理超时。

 

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
/**
 * AsyncRedisRequest
 * Redis在数据访问方面是单线程的,通过并发获得的唯一好处是将协议和I/O工作分散到不同的线程中去做。
 */
public class AsyncRedisRequest extends RichAsyncFunction<String, String> {
    private static Logger logger = LoggerFactory.getLogger(AsyncRedisRequest.class);

    private static final long serialVersionUID = -8022470346098502168L;
    private transient RedissonClient redissonClient = null;

    @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);
        // ((SingleServerConfig)config.useSingleServer().setTimeout(1000000)).setAddress("redis://127.0.0.1:6379");
        redissonClient = Redisson.create();
    }

    @Override
    public void close() throws Exception {
        super.close();
        if (redissonClient != null && !redissonClient.isShutdown()) {
            redissonClient.shutdown();
        }
    }

    @Override
    public void asyncInvoke(String input, ResultFuture<String> resultFuture) throws Exception {
        POJO pojo = new Gson().fromJson(input, POJO.class);
        pojo.getAid();
        pojo.getLogTime();

        /**
         RBucket<String> bucket = redissonClient.getBucket("", StringCodec.INSTANCE);
         RFuture<String> future = bucket.getAsync();
         */
        RBucket<String> bucket = redissonClient.getBucket("asyncio_" + pojo.getAid(), StringCodec.INSTANCE);
        RFuture future = bucket.getAndSetAsync(input, 24, TimeUnit.HOURS);

        future.whenComplete((res, exception) -> {
            resultFuture.complete(Arrays.asList(res.toString()));
        });
    }

    @Override
    public void timeout(String input, ResultFuture<String> resultFuture) throws Exception {
        // 可以使用一个侧面输出处理一下
        logger.info("timeout: ");
    }

}

示例Job:异步执行Redisson事务和Lua脚本

数据源Kafka

 kafka的server.properties中,num.partitions=3。

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
public class MessageProducer {
    private static final String LOCAL_KAFKA_BROKER = "localhost:9092";

    public static void main(String[] args) throws Exception {
        Properties props = new Properties();
        props.put("bootstrap.servers", LOCAL_KAFKA_BROKER);
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        props.put("acks", "-1");
        props.put("retries", 3);
        props.put("batch.size", 323840);
        props.put("linger.ms", 10);
        props.put("buffer.memory", 33554432);
        props.put("max.block.ms", 3000);
        props.put("request.timeout.ms", "60000");

        Producer<String, String> producer = new KafkaProducer<>(props);
        Gson gson = new Gson();

        for (int i = 0; i < 100000; i++) {
            POJO pojo = new POJO();
            int j = (int) (Math.random() * 3);
            pojo.setAid("ID000-" + i);
            pojo.setAname("NAME-" + i);
            pojo.setAstyle("STYLE000-" + j);
            pojo.setEnergy(new BigDecimal(1000 * Math.random()).setScale(2, RoundingMode.HALF_UP));
            pojo.setAge(j * 9);
            long time = System.currentTimeMillis();
            pojo.setTt(new Date(time));
            pojo.setLogTime(time);
            pojo.setAstatus("02");

            String value = gson.toJson(pojo);

            producer.send(new ProducerRecord<String, String>(AsyncRedisJob.class.getSimpleName(), Integer.toString(i), value));

            System.out.println(value);
        }

        producer.close();
    }
}

使用事务异步提交

 RFuture commitAsync();是没有返回结果的,即Void,对于超时的最好重写timeout进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
RTransaction transaction = redissonClient.createTransaction(TransactionOptions.defaults());
// 注意时区
String dateStr = DateTime.now().toString(DateTimeFormat.forPattern("yyyy-MM-dd"));
RMap<String, Object> transactionMap = transaction.getMap("asyncio_atype_" + pojo.getAstyle() + "_" + dateStr);
// 按天计算累计计数和Energy(卡路里-能量变化)
if (transactionMap.isExists()) {
    transactionMap.put("totalNum", (Long) transactionMap.get("totalNum") + 1);
    transactionMap.put("totalEnergy", new BigDecimal(transactionMap.get("totalNum").toString()).add(pojo.getEnergy()));
} else {
    transactionMap.put("totalNum", 1L);
    transactionMap.put("totalEnergy", new BigDecimal(0.00));
}

RFuture transactionFuture = transaction.commitAsync();

 transaction.getMap,transactionMap.isExists()和后续的计数、能量的计算在partition>1即多个线程执行的时候,是非线程安全的。
 transaction本身也不是分布式事务,所以并发+异步情况下直接使用redisson的transaction是不合适的。

1
2
3
4
5
6
7
8
9
10
pojo.getAstyle(): STYLE000-0 transactionMap.isExists(): false threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (2/3)
pojo.getAstyle(): STYLE000-0 transactionMap.isExists(): false threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (1/3)
pojo.getAstyle(): STYLE000-0 transactionMap.isExists(): false threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (3/3)
pojo.getAstyle(): STYLE000-0 transactionMap.isExists(): true threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (3/3)
pojo.getAstyle(): STYLE000-1 transactionMap.isExists(): false threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (1/3)
pojo.getAstyle(): STYLE000-1 transactionMap.isExists(): true threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (2/3)
pojo.getAstyle(): STYLE000-1 transactionMap.isExists(): true threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (1/3)
pojo.getAstyle(): STYLE000-1 transactionMap.isExists(): true threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (3/3)
pojo.getAstyle(): STYLE000-1 transactionMap.isExists(): true threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (1/3)
pojo.getAstyle(): STYLE000-0 transactionMap.isExists(): true threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (3/3)

异步执行lua脚本

 lua脚本,需要注意isExists返回的可能不是false而是0。
 异步和同步执行的结果差异:4) “\xfc\x05907.0” These letters are object header written by FstCodec

 

1
2
3
4
5
6
7
8
9
10
11
local k = KEYS[1]
local e = ARGV[1]
local isExists = redis.call('exists', k)
if not isExists or isExists == 0 then
  redis.call('hmset', k, 'totalNum', 1)
  redis.call('hmset', k, 'totalEnergy', e)
else
  redis.call('hmset', k, 'totalNum', tonumber(redis.call('hget', k, 'totalNum')) + 1)
  redis.call('hmset', k, 'totalEnergy', string.format("%.2f", tonumber(redis.call('hget', k, 'totalEnergy')) + tonumber(e)))
end
return redis.call('hgetall', k)
1
2
3
4
5
// Mode mode, String shaDigest, ReturnType returnType, List<Object> keys, Object... values
RFuture<List<Object>> scriptFuture = script.evalShaAsync(RScript.Mode.READ_ONLY, sha, RScript.ReturnType.MAPVALUELIST, Arrays.asList(key), String.valueOf(pojo.getEnergy().doubleValue()));
scriptFuture.whenComplete((res, exception) -> {
    resultFuture.complete(Arrays.asList(res.toString()));
});

 需要注意Codec。
 要反复确认whenComplete是否能够拿到异步执行的结果,确定是否走同步执行lua脚本。

1
2
3
4
5
6
7
8
// ((SingleServerConfig)config.useSingleServer().setTimeout(1000000)).setAddress("redis://127.0.0.1:6379");
Config config = new Config();
// 默认的Config在evalShaAsync时有bug,默认Codec是oldConf.setCodec(new FstCodec()); 不会使用getScript(StringCodec.INSTANCE)。
config.setCodec(StringCodec.INSTANCE);
config.useSingleServer()
        .setTimeout(1000000)
        .setAddress("redis://127.0.0.1:6379");
redissonClient = Redisson.create(config);

异步执行lua测试,先后发送了5和15条数据,共3中astyle:

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
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (2/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (3/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (1/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (3/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (3/3)
value: [totalNum, 1, totalEnergy, 295.0]
value: [totalNum, 1, totalEnergy, 867.0]
value: [totalNum, 1, totalEnergy, 704.0]
value: [totalNum, 2, totalEnergy, 1050.00]
value: [totalNum, 3, totalEnergy, 1864.00]
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (1/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (3/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (1/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (2/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (1/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (2/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (3/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (2/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (3/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (2/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (2/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (2/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (3/3)
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (1/3)
value: [totalNum, 4, totalEnergy, 1873.00]
sha: 0219d65422f424b3646391cacd4d90854b270c9a threadName: Source: Custom Source -> async wait operator -> Sink: Unnamed (1/3)
value: [totalNum, 2, totalEnergy, 1121.00]
value: [totalNum, 3, totalEnergy, 1439.00]
value: [totalNum, 2, totalEnergy, 892.00]
value: [totalNum, 4, totalEnergy, 2190.00]
value: [totalNum, 7, totalEnergy, 3049.00]
value: [totalNum, 6, totalEnergy, 2562.00]
value: [totalNum, 8, totalEnergy, 3587.00]
value: [totalNum, 5, totalEnergy, 2374.00]
value: [totalNum, 7, totalEnergy, 3436.00]
value: [totalNum, 6, totalEnergy, 2971.00]
value: [totalNum, 5, totalEnergy, 2250.00]
value: [totalNum, 4, totalEnergy, 1942.00]
value: [totalNum, 5, totalEnergy, 2311.00]
value: [totalNum, 3, totalEnergy, 1288.00]

 

Redis情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
127.0.0.1:6379> keys *
1) "asyncio_atype_STYLE000-1_2019-07-15"
2) "asyncio_atype_STYLE000-2_2019-07-15"
3) "asyncio_atype_STYLE000-0_2019-07-15"
127.0.0.1:6379> hgetall asyncio_atype_STYLE000-1_2019-07-15
1) "totalNum"
2) "7"
3) "totalEnergy"
4) "3049.00"
127.0.0.1:6379> hgetall asyncio_atype_STYLE000-2_2019-07-15
1) "totalNum"
2) "8"
3) "totalEnergy"
4) "3587.00"
127.0.0.1:6379> hgetall asyncio_atype_STYLE000-0_2019-07-15
1) "totalNum"
2) "5"
3) "totalEnergy"
4) "2374.00"
Qwen3.6-Plus国产编程大模型实战接入指南 编程大模型是面向开发者的人工智能核心基础设施,其本质是通过深度语义理解与代码生成能力重构软件开发范式。Qwen3.6-Plus作为首个在HumanEval-X中文增强基准上超越GPT-4 Turbo的国产模型,依托MoE稀疏架构实现低延迟高精度推理,并深度融合Spring Boot、Dubbo、达梦数据库等中国主流技术栈语义。其技术价值在于将模糊业务意图(如Git提交描述、白板草图)转化为可运行、可测试、合规安全的生产级代码,已在金融核心系统、政务云、电商中台等场景完成规模化验证。本文聚焦Qwen3.6-P 阅读详情

相关推荐

【信息科学与工程学】计算机科学与自动化——第三百零四篇 高性能系统开发指南01

高并发:限流、熔断、降级高性能:红包拆分、多级缓存、大Key/热Key拆分、Pipeline、线程池、RocketMQ零丢失、幂等、分布式锁、集群缩容、分批入库海量数据处理:日志分表分片、跨表查询、冷热分层、大数据引擎服务器选型系统安全:网关安全、服务器安全、云存储安全、风控、监控、测试数据一致性:缓存与数据库一致性、大厂方案、蓝绿回滚、流量一致性、流程一致性项目与团队管理:流程问题、管理问题(风险、成本、人员、文档、培训)稳定性建设:上线三板斧、线上五步闭环、混沌工程、容量规划。

weixin_49199313的博客 251

Flink实战--异步IO实战入门(和Redis交互)

本文通过一个例子来说明Flink异步IO的使用。在该例子中还说明了和Redis的交互。

zg_hover的专栏 4134

【信息科学与工程学】计算机科学与自动化——第八十一篇 Java分布式软件高并发/高可用算法01

4. 消息队列(如Kafka的Topic分区,本质是范围)。3. 若是ACCEPT事件,bossGroup线程接受连接,创建SocketChannel,并将其注册到workerGroup的一个EventLoop的Selector上,关注READ事件。1. 分布式缓存分片(如Redis Cluster)。4. 分布式文件存储(如Ceph CRUSH)。6. 调用栈的模拟(如协程)。3. 服务网格(如Istio)的基础。2. 本地缓存与集中式缓存(如Redis)的一致性维护。3. 静态数据(如配置)缓存。

weixin_49199313的博客 1239

Flink异步IO查询Hbase数据,采用旁路缓存redis

概念理解流计算系统中经常需要与外部系统进行交互,比如需要查询外部数据库以关联上用户的额外信息。通常,我们的实现方式是向数据库发送用户a的查询请求(例如在MapFunction中),然后等待结果返回,在这之前,我们无法发送用户b的查询请求。这是一种同步访问的模式,如下图左边所示。图中棕色的长条表示等待时间,可以发现网络等待时间极大地阻碍了吞吐和延迟。为了解决同步访问的问题,异步模式可以并发地处理多个请求和回复。

qq_34676998的博客 2313

【Redis】Redis 使用 redisson 做分布式锁 复盘 maven 依赖 netty 冲突

1.概述 今天想要做一个功能,大概是 flink任务中,输出到100条数据的时候,就要停止输出。并且输出一个特殊的信息。这里每次发送一个消息,记录。 难点: flink任务是并行处理的,要求所有并行度,总共输出不能超过100. 最后输出一条特殊的消息,因此每个并行度都要判断哪个是最后的一条消息。 我这里采用redis分布式锁,去做。核心就是。 发送一条数据,我就在redis中某个key增加1,然后每次去读取,然后判断是不是超过限制了。如果超过限制那么输出一条告警信息。 开始我引入了如下 <dep.

九师兄 1119

flink-redis-sink:使用TableSQL API帮助沉入Redis

该项目用于使用表或sql api将数据写入flink流应用程序中的redis。 之前,我看到了项目,该项目具有一个模块来帮助使用flink写入redis。 但是,它可以工作,但与我的愿望并不完全匹配。 当我想将行/表沉入redis中时: Firstly,i'd like to choose one or more field as the redis key, Secondly, i'd like to take the row as a map or json string as the value. Thirdly, watermark needs to be supported too. 但是,如果不更改源代码,它看起来并不容易。 我想写我自己的redis-sink。 当您查看此项目时,有一些技巧需要记住: 该项目仅支持REDIS CLUSTER模式。 该项目使用redi

flink入门之scala实现异步IO访问redis及踩坑记录(1)

问题 在使用sparkstreaming的过程中,我们经常有一个需求是把中间变量写到redis,然后在流程序中去读redis的中间变量。在sparkstreaming中,我们只需要用个foreach算子就能实现这种需求,那flink中没有foreach算子,我们该如何做到流程中读redis的数据呢? 方法 我们可以用flink的异步IO访问redis完成这种操作 实现 import java.ut...

bradyM的博客 1911

libfacedetection 框架阅读及扩展经验

libfacedetection 框架源码解析与扩展心得1. libfacedetection 框架简介2. 源码解析2.1 facedetectcnn.h2.2 facedetectcnn.cpp2.3 facedetectcnn-model.cpp3. 其他层的扩展--depthwise convolution 前段时间因为工作需要,对libfacedetection框架做了些扩展,在阅读源...

weixin_42616332的博客 1500

Flink集成Redis组件,使用异步IO能完全解决性能瓶颈问题?

基于上述的问题,我们先来对异步IO有个大致的认识,了解的同学可以选择跳过。 流计算系统中经常需要与外部系统(Redis、MySQL等)进行交互,我们通常的做法如向数据库发送用户a的查询请求,然后等待结果返回,在这之前,我们的程序无法发送用户b的查询请求。这是一种同步访问方式,如下图所示。 图中棕色的长条表示等待时间,可以发现网络等待时间极大地阻碍了吞吐和延迟。为了解决同步访问的问题,异步模...

JK_GOME的博客 3043

教你读懂techpoint视频解码芯片tp2855规格书(第一部分)

所有的控制环都是可编程的,以实现最大化的灵活性。对于NTSC/PAL输入,输出时钟和采样结构是非标准的,以便在多路复用输出时与HD格式一同工作。所有通道的音频数据都可以选择性地级联,以实现最大的灵活性。TP2855是一款通用的高清/标清视频解码器芯片,其支持对HD-TVI、NTSC/PAL制式960H分辨率及普通AHD视频格式的解码。TP2855具有内部钳位,在每个通道上都有自动增益控制放大器,用于最佳的信号调节。即使在使用低质量和长线缆的条件下,它的可编程均衡放大器和自动控制环也能维持尚佳的表现。

hufan92的博客 4925

电磁场数值分析作业(西电)共5次【2021】

文章目录作业1作业2作业3作业4作业5 作业1 一个二维正方形(边长a=10mm)的静电场区域,电位边界条件如图所示(单位:V),求区域内的电位分布。要求用超松弛迭代法求解差分方程组进行计算。 clc clear close all hx=11; hy=11; v1=zeros(hy,hx); v1(hy,:)=ones(1,hx)*100; v1(1,:)=ones(1,hx)*50; for i=1:hy v1(i,1)=0; v1(i,hx)=100; end w=2/(1+

薛定谔的壳的博客 5074

flink入门之scala实现异步IO访问redis及踩坑记录(2)

我们在flink入门之scala实现异步IO访问redis及踩坑记录(1)中采用jedis来模拟异步读取redis,那么在本篇,我们要采用redis的高级客户端lettuce,这个客户端很强大,支持异步操作,如果想具体了解的请移步: Redis高级客户端Lettuce详解 首先我们导入依赖: <dependency> <groupId>io.lettuce</groupId> <artifactId>lett

bradyM的博客 1129

机械臂控制的基础知识

在现代工业中,机械臂的自动化控制已经成为智能制造的重要一环。控制机械臂涉及多个学科,包括机械设计、运动学、控制理论和编程等。本文将从以下几个方面介绍机械臂控制的核心知识点:机械臂的构成、运动学分析、动力学建模、控制方法及编程实现。

qq_45728381的博客 5470

Java大厂面试实战:JVM、并发与分布式系统设计

Java作为企业级开发的核心语言,其技术栈深度与工程实践能力是面试考察的重点。从JVM内存模型到并发编程,开发者需要理解对象生命周期、垃圾回收机制以及多线程同步原理。分布式系统设计则涉及Redis集群、MySQL优化等关键技术,这些组件通过分片、索引等机制解决高并发场景下的性能瓶颈。在电商、金融等实际业务中,秒杀系统、实时对账等典型场景需要结合消息队列、缓存策略进行架构设计。本文通过互联网大厂真实面试案例,剖析Java技术栈在系统性能优化、微服务拆分等场景中的工程实践,帮助开发者掌握ConcurrentHa

426

从仿真到打样:PMOS栅极泄放电路设计全流程复盘与三个踩坑点总结

本文详细复盘了PMOS栅极泄放电路从仿真到打样的全流程设计,重点总结了三个关键踩坑点:三极管BE结过压击穿、静态功耗超标和栅极振荡现象。通过优化缓启动电路、改进保护设计和布局调整,最终实现18ms开通时间、190μs关断时间和8μA静态功耗的工业级性能指标,为类似电源开关设计提供实用参考。

weixin_28693683的博客 371

U-Net图像分割实战:从论文解析到PyTorch代码实现

本文深入解析了U-Net图像分割模型的经典架构与核心思想,并提供了从零开始的PyTorch代码实现教程。通过详细拆解编码器-解码器结构、跳跃连接等关键组件,手把手指导读者构建完整的U-Net网络,涵盖数据准备、模型训练、推理部署全流程,是掌握图像分割实战技能的实用指南。

fire9的博客 343

Java后端面试核心考点与实战应答策略深度解析

在Java后端开发领域,JVM内存模型、GC算法与并发编程中的锁机制、线程池是构建高性能、高可用系统的底层基石。理解这些核心原理,能帮助开发者从本质上优化应用性能、规避线上风险。其技术价值在于,通过深入掌握JVM调优与并发控制,可以显著提升系统吞吐量、降低延迟,并有效应对高并发场景下的数据一致性与资源竞争问题。在实际的工程实践中,这些知识广泛应用于电商秒杀、金融交易、实时通信等对性能与稳定性要求极高的业务场景。本文基于真实的面试复盘,聚焦于**JVM性能调优**与**并发编程实战**等高频硬核考点,为你梳理

weixin_33768481的博客 768

基于阿里云物联网平台设计的实时图传系统_采用MQTT协议传输图像

当前基于MQTT协议设计了一个实时图传系统,通过这个项目来演示,两个MQTT设备如何互相订阅,进行消息流转。 在阿里云服务器上创建2个设备,分为为设备A和设备B;设备A负责采集本地摄像头画面上传,设备B负责接收设备A上传的数据然后解析显示出来。在阿里云服务器上需要配置云产品流转,让设备A的数据上传后自动发送给设备B。这样就完成了视频画面数据的流转。不过因为阿里云的最大数据限制,每次最大发送10240字节的数据。

1万+

基于CDC与流处理构建企业级实时数据同步架构实战

在数字化转型背景下,数据集成是企业打通信息孤岛、实现业务联动的关键技术。其核心原理是通过实时捕获数据源的变化,并以异步、解耦的方式将变更事件可靠地分发给下游系统。这项技术的核心价值在于,它能够确保数据在异构系统间流动的实时性、一致性与可观测性,从而支撑库存管理、会员营销、实时分析等高并发业务场景。本文以商超零售系统为背景,深入探讨如何利用Change Data Capture(CDC)技术结合消息队列与流处理引擎,构建高可靠、可扩展的实时数据管道,并详细解析了Debezium、Kafka和SeaTunnel

weixin_34245082的博客 600

全新DEIM有效涨点改进目录 | 本专栏持续更新500+篇内容 | 包含各种顶会顶刊卷积、注意力、特征融合模块、有效特征聚合提取模块,上采样模块、下采样模块,二次创新模块、独家创新等几百种创新点改进

🚀【CVPR2025DEIM改进专栏速览】🔥 专栏提供500+篇目标检测创新改进方案,涵盖卷积/注意力/特征融合等创新改进点,均源自顶会论文及实战经验。支持多领域应用(工业/医疗/遥感等),配套完整教程和答疑服务。亮点包括: 1️⃣ 持续更新SOTA模型改进方案 2️⃣ 小白友好型实验操作指南 3️⃣ 跨学科科研支持(已助非计算机专业发表论文) 4️⃣ 提供虚拟环境配置方案。 订阅可获完整项目代码及交流群服务,适合研究生科研论文改进需求。价格呈上涨趋势,早订更优惠!

Ai缝合怪、助力小伙伴高效发论文 2056

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

混元3.0实战指南:MoE架构与262K上下文如何提升编程生产力

大模型编程辅助已从概念验证迈入工程落地阶段。理解MoE(混合专家)架构原理,有助于把握其在代码生成、错误诊断与多文件协同中的计算效率优势;而超长上下文(如262K)并非参数堆砌,实为解决开发者跨文件、跨配置、跨语言理解碎片化问题的关键能力。结合SWE-bench等真实工程基准的验证逻辑,这类模型的技术价值正体现在CRUD开发、单元测试补全、CI失败归因等高频重复任务中——即提升‘有效编码时间’而非替代思考。本文以混元3.0为典型,解析其三级推理模式、专家调度机制与上下文工程实践,面向一线工程师提供可立即复用

weixin_30790841的博客 367

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

基于Flink及Redis布隆过滤器的大数据去重

package bill; import org.apache.flink.api.java.tuple.Tuple2; import org.apache.flink.configuration.Configuration; import org.apache.flink.streaming.api.TimeCharacteristic; import org.apache.flink.st...

Bill_Xiang的专栏 1442

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

轻松通关Flink第34讲:Flink 和 Redis 整合以及 Redis Sink 实现

这节课我们学习了 Flink 计算 PV、UV后的结果分别写入 Redis、MySQL 和 HBase。我们在实际业务中可以选择使用不同的目标库,你可以在本文中找到对应的实现根据实际情况进行修改来使用。

sucaiwa的博客 4117

flink: 通过ReidsSink将数据写入redis

【代码】flink: 通过ReidsSink将数据写入redis。

amadeus_liu2的博客 908

Flink Redis Sink 基本用法

文章目录简介依赖类使用RedisMapperRedisCommandDemo参考 简介 flink提供了专门操作redis的Redis Sink 依赖 <dependency> <groupId>org.apache.bahir</groupId> <artifactId>flink-connector-redis_2.11<...

小杨的技术博客 3万+

Flink异步IO初步了解

在EventTime中,以watermark为边界,介于两个watermark之间的消息是乱序的,但是多个watermark之间的消息是有序的。之前使用Flink查询Redis数据的过程中,由于对数据一致性的要求并不是很高,当时是用MapFunction + State 的方案。// resultHandler类内部的complete方法就是在用户自定义函数中传结果用的,最终执行结果会调用processInMainBox(results)方法,将结果发送给下游算子。// 调用用户编写的方法。

淡定一生2333的博客 1433
上一篇: CompletableFuture 使用详解
下一篇: PostgreSQL 参数调整(性能优化)
王树民
博客等级 码龄10年 912粉丝 560原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值