Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reponse time 5 times slower when normalizedCache is enabled #76

Open
Tracked by #2331
dush1729 opened this issue Nov 30, 2020 · 5 comments
Open
Tracked by #2331

reponse time 5 times slower when normalizedCache is enabled #76

dush1729 opened this issue Nov 30, 2020 · 5 comments

Comments

@dush1729
Copy link

Version
2.4.4

Question.
This is related to 2413. When I enable normalizedCache, reponse time increases from 800ms to 4000ms. Here's how my Apollo Client look.

@Singleton
@Provides
fun provideLruCache(): LruNormalizedCacheFactory {
    // Create a 50MB NormalizedCacheFactory
    return LruNormalizedCacheFactory(EvictionPolicy.builder().maxSizeBytes(50 * 1024 * 1024).build())
}

@Singleton
@Provides
fun provideSqlCache(): SqlNormalizedCacheFactory {
    return SqlNormalizedCacheFactory(application, "apollo_cache.db")
}

@Singleton
@Provides
fun provideCacheResolver(): CacheKeyResolver {
    return object : CacheKeyResolver() {
        override fun fromFieldRecordSet(field: ResponseField, recordSet: Map<String, Any>): CacheKey {
            return formatCacheKey(recordSet["nickname"] as String?)
        }

        override fun fromFieldArguments(field: ResponseField, variables: Operation.Variables): CacheKey {
            return formatCacheKey(field.resolveArgument("nickname", variables) as String?)
        }

        private fun formatCacheKey(id: String?) = when {
            id.isNullOrEmpty() -> CacheKey.NO_KEY
            else -> CacheKey.from(id)
        }
    }
}

@Singleton
@Provides
@Named("Apollo")
fun provideOkHttpClient(): OkHttpClient {
    return OkHttpClient
            .Builder()
            .addInterceptor(interceptor)
            .addInterceptor(chunkInterceptor)
            .connectTimeout(20, TimeUnit.SECONDS)
            .writeTimeout(20, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            .build()
}

@Singleton
@Provides
fun provideApolloClient(@Named("Apollo") okHttpClient: OkHttpClient,
        lruCache: LruNormalizedCacheFactory, sqlCache: SqlNormalizedCacheFactory, resolver: CacheKeyResolver): ApolloClient {
    val lruFirstThenSqlCache = lruCache.chain(sqlCache)
    return ApolloClient.builder()
            .serverUrl(cmsBaseUrl)
            .normalizedCache(lruFirstThenSqlCache, resolver)
            .defaultResponseFetcher(CACHE_FIRST)
            .okHttpClient(okHttpClient)
            .build()
}

And this is how I call my query

private fun getStudents(): Observable<String> {
    return apolloClient.rxQuery(StudentsQuery()).flatMap { response ->
        if (response.errors?.isNotEmpty() == true) {
            Observable.error(Throwable("Error: fetching students. ${response.errors}"))
        } else {
            Observable.just(gson.toJson(response.data?.students))
        }
    }
}
@dush1729
Copy link
Author

data returned is of size 200kB

@martinbonnin
Copy link
Contributor

Aw yea, that's not great. We definitely need more benchmarks to investigate those.

One thing you can try is write to the cache asynchronously (set writeToCacheAsynchronously = true when passing your normalizedCacheFactory). That should reduce the impact of the cache at the price of maybe a few cache misses.

Besides that, it'd be interesting to know whether it's something specific to your use case or a more general thing. In apollographql/apollo-kotlin#2413, the request time went down to 600ms again once the SQLite writes were wrapped in a transaction. So I'm guessing there's something more to it that could explain the 4000ms time

@dush1729
Copy link
Author

dush1729 commented Nov 30, 2020

After enabling writeToCacheAsynchronously, on first launch I am getting 900ms which is great. But on relaunches, I am back to old times 4000ms which is weird.

And in memory cache seems to be working perfectly fine in all 3 cases(without responseFetcher, with responseFetcher & writeToCacheAsynchronously and with responseFetcher but without writeToCacheAsynchronously). I am getting 200ms when I call same query again without relaunching the app.

@dush1729
Copy link
Author

dush1729 commented Mar 8, 2021

@martinbonnin Any updates on this? I tested few more variations looks like SqlCache might be the culprit. I used only LruCache, it takes only 300ms even after relaunch. I thought LruCache was in-memory, so how is it giving benefit on relaunch? When using only SqlCache, results were slow just like I stated above.

As for fetch strategies, I am using CACHE_FIRST as default one. Using NETWORK_FIRST gets results in 900ms. Using NETWORK_AND_CACHE gets results in 1000ms.

@martinbonnin
Copy link
Contributor

martinbonnin commented Mar 8, 2021

Hi @dush1729 ! We're working hard on optimizing the SQL cache for 3.0 and preliminary results are encouraging. It's not quite ready yet and there are a lot of moving parts at the moment but if you want to take an early look, you can try the latest 3.x dev version ( com.apollographql.apollo3:apollo-runtime:3.0.0-dev4 as of writing)

@BoD BoD transferred this issue from apollographql/apollo-kotlin Dec 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants